summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp9
-rw-r--r--PREUPLOAD.cfg3
-rw-r--r--PermissionController/Android.bp13
-rw-r--r--PermissionController/AndroidManifest.xml232
-rw-r--r--PermissionController/OWNERS6
-rw-r--r--PermissionController/TEST_MAPPING68
-rw-r--r--PermissionController/iconloaderlib/.gitignore13
-rw-r--r--PermissionController/iconloaderlib/Android.bp52
-rw-r--r--PermissionController/iconloaderlib/AndroidManifest.xml20
-rw-r--r--PermissionController/iconloaderlib/build.gradle38
-rw-r--r--PermissionController/iconloaderlib/res/drawable-v26/adaptive_icon_drawable_wrapper.xml22
-rw-r--r--PermissionController/iconloaderlib/res/drawable/ic_instant_app_badge.xml39
-rw-r--r--PermissionController/iconloaderlib/res/values/attrs.xml23
-rw-r--r--PermissionController/iconloaderlib/res/values/colors.xml24
-rw-r--r--PermissionController/iconloaderlib/res/values/config.xml30
-rw-r--r--PermissionController/iconloaderlib/res/values/dimens.xml19
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java466
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java163
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/BitmapRenderer.java70
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/ClockDrawableWrapper.java448
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/ColorExtractor.java127
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java143
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/FastBitmapDrawable.java314
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/FixedScaleDrawable.java53
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/GraphicsUtils.java127
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java411
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java377
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/PlaceHolderIconDrawable.java79
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/RoundDrawableWrapper.java56
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/ShadowGenerator.java183
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/ThemedIconDrawable.java296
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java570
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java65
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/cache/HandlerRunnable.java79
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java313
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/util/ComponentKey.java84
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/util/NoLocaleSQLiteHelper.java58
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/util/SQLiteCacheHelper.java125
-rw-r--r--PermissionController/iconloaderlib/src/com/android/launcher3/util/SafeCloseable.java26
-rw-r--r--PermissionController/iconloaderlib/src_full_lib/com/android/launcher3/icons/IconFactory.java89
-rw-r--r--PermissionController/iconloaderlib/src_full_lib/com/android/launcher3/icons/SimpleIconCache.java114
-rw-r--r--PermissionController/lint-baseline.xml565
-rw-r--r--PermissionController/proguard.flags9
-rw-r--r--PermissionController/res/color-v33/safety_center_button_info.xml21
-rw-r--r--PermissionController/res/color-v33/safety_center_button_recommend.xml21
-rw-r--r--PermissionController/res/color-v33/safety_center_button_warn.xml21
-rw-r--r--PermissionController/res/color-v33/safety_center_outline_button_info.xml23
-rw-r--r--PermissionController/res/color-v33/safety_center_outline_button_recommend.xml23
-rw-r--r--PermissionController/res/color-v33/safety_center_outline_button_warn.xml23
-rw-r--r--PermissionController/res/color-v33/safety_center_toggle_disabled.xml20
-rw-r--r--PermissionController/res/color-v33/sc_surface_light.xml19
-rw-r--r--PermissionController/res/color-v34/preference_highlight_color.xml20
-rw-r--r--PermissionController/res/drawable-v31/safety_status_info.xml37
-rw-r--r--PermissionController/res/drawable-v31/safety_status_info_review.xml37
-rw-r--r--PermissionController/res/drawable-v31/safety_status_recommendation.xml37
-rw-r--r--PermissionController/res/drawable-v31/safety_status_warn.xml37
-rw-r--r--PermissionController/res/drawable-v33/ic_check.xml (renamed from PermissionController/res/drawable-v31/ic_check.xml)0
-rw-r--r--PermissionController/res/drawable-v33/ic_chevron_right.xml (renamed from PermissionController/res/drawable-v31/ic_block.xml)2
-rw-r--r--PermissionController/res/drawable-v33/ic_collapse_issues.xml (renamed from PermissionController/res/drawable/safety_shield.xml)6
-rw-r--r--PermissionController/res/drawable-v33/ic_expand_issues.xml25
-rw-r--r--PermissionController/res/drawable-v33/ic_expand_less.xml (renamed from PermissionController/res/drawable-v31/ic_expand_less.xml)0
-rw-r--r--PermissionController/res/drawable-v33/ic_expand_more.xml (renamed from PermissionController/res/drawable-v31/ic_expand_more.xml)0
-rw-r--r--PermissionController/res/drawable-v33/ic_privacy.xml (renamed from PermissionController/res/drawable-v31/ic_safety_null_state.xml)21
-rw-r--r--PermissionController/res/drawable-v33/ic_safety_center_shield.xml (renamed from PermissionController/res/drawable-v31/ic_safety_info_outline.xml)19
-rw-r--r--PermissionController/res/drawable-v33/ic_safety_empty.xml (renamed from PermissionController/res/drawable-v31/ic_safety_empty.xml)0
-rw-r--r--PermissionController/res/drawable-v33/ic_safety_group_collapse.xml (renamed from PermissionController/res/drawable-v31/ic_safety_recommendation_outline.xml)10
-rw-r--r--PermissionController/res/drawable-v33/ic_safety_group_expand.xml12
-rw-r--r--PermissionController/res/drawable-v33/ic_safety_info.xml26
-rw-r--r--PermissionController/res/drawable-v33/ic_safety_issue_dismiss.xml (renamed from PermissionController/res/drawable-v31/ic_safety_info.xml)13
-rw-r--r--PermissionController/res/drawable-v33/ic_safety_null_state.xml (renamed from PermissionController/res/drawable-v31/ic_safety_issue_dismiss.xml)17
-rw-r--r--PermissionController/res/drawable-v33/ic_safety_recommendation.xml (renamed from PermissionController/res/drawable-v31/ic_safety_recommendation.xml)20
-rw-r--r--PermissionController/res/drawable-v33/ic_safety_warn.xml (renamed from PermissionController/res/drawable-v31/ic_safety_warn.xml)20
-rw-r--r--PermissionController/res/drawable-v33/ic_settings_gear.xml28
-rw-r--r--PermissionController/res/drawable-v33/ic_settings_info.xml (renamed from PermissionController/res/drawable-v31/ic_history.xml)23
-rw-r--r--PermissionController/res/drawable-v33/indicator_background_circle.xml29
-rw-r--r--PermissionController/res/drawable-v33/more_issues_collapse_anim.xml311
-rw-r--r--PermissionController/res/drawable-v33/more_issues_expand_anim.xml267
-rw-r--r--PermissionController/res/drawable-v33/safety_center_card_background.xml (renamed from PermissionController/res/drawable-v31/safety_center_card_background.xml)4
-rw-r--r--PermissionController/res/drawable-v33/safety_center_card_widget_background.xml21
-rw-r--r--PermissionController/res/drawable-v33/safety_center_group_collapse_anim.xml324
-rw-r--r--PermissionController/res/drawable-v33/safety_center_group_expand_anim.xml280
-rw-r--r--PermissionController/res/drawable-v33/safety_center_issue_resolved_avd.xml157
-rw-r--r--PermissionController/res/drawable-v33/safety_center_more_issues_card_background.xml33
-rw-r--r--PermissionController/res/drawable-v33/safety_center_sensor_toggle_disabled.xml25
-rw-r--r--PermissionController/res/drawable-v33/safety_center_sensor_toggle_enabled.xml26
-rw-r--r--PermissionController/res/drawable-v33/safety_entity_top_flat_bottom_flat_background.xml22
-rw-r--r--PermissionController/res/drawable-v33/safety_entity_top_flat_bottom_large_background.xml37
-rw-r--r--PermissionController/res/drawable-v33/safety_entity_top_flat_bottom_small_background.xml37
-rw-r--r--PermissionController/res/drawable-v33/safety_entity_top_large_bottom_flat_background.xml37
-rw-r--r--PermissionController/res/drawable-v33/safety_entity_top_large_bottom_large_background.xml33
-rw-r--r--PermissionController/res/drawable-v33/safety_entity_top_large_bottom_small_background.xml41
-rw-r--r--PermissionController/res/drawable-v33/safety_entity_top_small_bottom_flat_background.xml37
-rw-r--r--PermissionController/res/drawable-v33/safety_entity_top_small_bottom_large_background.xml41
-rw-r--r--PermissionController/res/drawable-v33/safety_entity_top_small_bottom_small_background.xml33
-rw-r--r--PermissionController/res/drawable-v33/safety_entry_icon_action_background.xml30
-rw-r--r--PermissionController/res/drawable-v33/safety_group_entry_background.xml24
-rw-r--r--PermissionController/res/drawable-v33/safety_status_info.xml32
-rw-r--r--PermissionController/res/drawable-v33/safety_status_info_to_info_anim.xml173
-rw-r--r--PermissionController/res/drawable-v33/safety_status_recommend_to_info_anim.xml698
-rw-r--r--PermissionController/res/drawable-v33/safety_status_recommendation.xml34
-rw-r--r--PermissionController/res/drawable-v33/safety_status_small_info_to_info_anim.xml151
-rw-r--r--PermissionController/res/drawable-v33/safety_status_small_info_to_recommendation_anim.xml151
-rw-r--r--PermissionController/res/drawable-v33/safety_status_small_info_to_warn_anim.xml151
-rw-r--r--PermissionController/res/drawable-v33/safety_status_small_recommendation_to_info_anim.xml151
-rw-r--r--PermissionController/res/drawable-v33/safety_status_small_recommendation_to_recommendation_anim.xml151
-rw-r--r--PermissionController/res/drawable-v33/safety_status_small_recommendation_to_warn_anim.xml151
-rw-r--r--PermissionController/res/drawable-v33/safety_status_small_warn_to_info_anim.xml151
-rw-r--r--PermissionController/res/drawable-v33/safety_status_small_warn_to_recommendation_anim.xml151
-rw-r--r--PermissionController/res/drawable-v33/safety_status_small_warn_to_warn_anim.xml151
-rw-r--r--PermissionController/res/drawable-v33/safety_status_warn.xml34
-rw-r--r--PermissionController/res/drawable-v33/safety_status_warn_to_info_anim.xml697
-rw-r--r--PermissionController/res/drawable-v33/safety_status_warn_to_recommend_anim.xml255
-rw-r--r--PermissionController/res/drawable-v33/status_info_to_scanning_anim.xml192
-rw-r--r--PermissionController/res/drawable-v33/status_recommend_to_scanning_anim.xml124
-rw-r--r--PermissionController/res/drawable-v33/status_scanning_anim_info.xml79
-rw-r--r--PermissionController/res/drawable-v33/status_scanning_anim_recommend.xml79
-rw-r--r--PermissionController/res/drawable-v33/status_scanning_anim_warn.xml79
-rw-r--r--PermissionController/res/drawable-v33/status_scanning_end_anim_info_to_info.xml205
-rw-r--r--PermissionController/res/drawable-v33/status_scanning_end_anim_info_to_recommend.xml308
-rw-r--r--PermissionController/res/drawable-v33/status_scanning_end_anim_info_to_warn.xml308
-rw-r--r--PermissionController/res/drawable-v33/status_scanning_end_anim_recommend_to_info.xml231
-rw-r--r--PermissionController/res/drawable-v33/status_scanning_end_anim_recommend_to_recommend.xml283
-rw-r--r--PermissionController/res/drawable-v33/status_scanning_end_anim_recommend_to_warn.xml309
-rw-r--r--PermissionController/res/drawable-v33/status_scanning_end_anim_warn_to_info.xml230
-rw-r--r--PermissionController/res/drawable-v33/status_scanning_end_anim_warn_to_recommend.xml308
-rw-r--r--PermissionController/res/drawable-v33/status_scanning_end_anim_warn_to_warn.xml283
-rw-r--r--PermissionController/res/drawable-v33/status_warn_to_scanning_anim.xml124
-rw-r--r--PermissionController/res/drawable-v34/ic_business.xml10
-rw-r--r--PermissionController/res/drawable-v34/ic_collections_bookmark.xml10
-rw-r--r--PermissionController/res/drawable-v34/ic_gear.xml13
-rw-r--r--PermissionController/res/drawable-v34/ic_help.xml11
-rw-r--r--PermissionController/res/drawable-v34/ic_info_24dp.xml10
-rw-r--r--PermissionController/res/drawable-v34/ic_safety_center_brand_chip.xml14
-rw-r--r--PermissionController/res/drawable-v34/ic_safety_center_shield.xml14
-rw-r--r--PermissionController/res/drawable-v34/ic_safety_info.xml34
-rw-r--r--PermissionController/res/drawable-v34/ic_safety_null_state.xml28
-rw-r--r--PermissionController/res/drawable-v34/ic_safety_recommendation.xml35
-rw-r--r--PermissionController/res/drawable-v34/ic_safety_warn.xml35
-rw-r--r--PermissionController/res/drawable-v34/safety_center_brand_chip_background.xml (renamed from PermissionController/res/drawable/safety_center_button_background_dark.xml)9
-rw-r--r--PermissionController/res/drawable-v34/safety_status_info.xml20
-rw-r--r--PermissionController/res/drawable-v34/safety_status_info_to_info_anim.xml245
-rw-r--r--PermissionController/res/drawable-v34/safety_status_recommend_to_info_anim.xml722
-rw-r--r--PermissionController/res/drawable-v34/safety_status_recommendation.xml24
-rw-r--r--PermissionController/res/drawable-v34/safety_status_small_info_to_info_anim.xml163
-rw-r--r--PermissionController/res/drawable-v34/safety_status_small_info_to_recommendation_anim.xml163
-rw-r--r--PermissionController/res/drawable-v34/safety_status_small_info_to_warn_anim.xml163
-rw-r--r--PermissionController/res/drawable-v34/safety_status_small_recommendation_to_info_anim.xml163
-rw-r--r--PermissionController/res/drawable-v34/safety_status_small_recommendation_to_recommendation_anim.xml163
-rw-r--r--PermissionController/res/drawable-v34/safety_status_small_recommendation_to_warn_anim.xml163
-rw-r--r--PermissionController/res/drawable-v34/safety_status_small_warn_to_info_anim.xml163
-rw-r--r--PermissionController/res/drawable-v34/safety_status_small_warn_to_recommendation_anim.xml163
-rw-r--r--PermissionController/res/drawable-v34/safety_status_small_warn_to_warn_anim.xml163
-rw-r--r--PermissionController/res/drawable-v34/safety_status_warn.xml24
-rw-r--r--PermissionController/res/drawable-v34/safety_status_warn_to_info_anim.xml722
-rw-r--r--PermissionController/res/drawable-v34/safety_status_warn_to_recommend_anim.xml346
-rw-r--r--PermissionController/res/drawable-v34/status_info_to_scanning_anim.xml149
-rw-r--r--PermissionController/res/drawable-v34/status_recommend_to_scanning_anim.xml225
-rw-r--r--PermissionController/res/drawable-v34/status_scanning_anim_info.xml111
-rw-r--r--PermissionController/res/drawable-v34/status_scanning_anim_recommend.xml111
-rw-r--r--PermissionController/res/drawable-v34/status_scanning_anim_warn.xml111
-rw-r--r--PermissionController/res/drawable-v34/status_scanning_end_anim_info_to_info.xml265
-rw-r--r--PermissionController/res/drawable-v34/status_scanning_end_anim_info_to_recommend.xml469
-rw-r--r--PermissionController/res/drawable-v34/status_scanning_end_anim_info_to_warn.xml469
-rw-r--r--PermissionController/res/drawable-v34/status_scanning_end_anim_recommend_to_info.xml293
-rw-r--r--PermissionController/res/drawable-v34/status_scanning_end_anim_recommend_to_recommend.xml458
-rw-r--r--PermissionController/res/drawable-v34/status_scanning_end_anim_recommend_to_warn.xml532
-rw-r--r--PermissionController/res/drawable-v34/status_scanning_end_anim_warn_to_info.xml293
-rw-r--r--PermissionController/res/drawable-v34/status_scanning_end_anim_warn_to_recommend.xml469
-rw-r--r--PermissionController/res/drawable-v34/status_scanning_end_anim_warn_to_warn.xml441
-rw-r--r--PermissionController/res/drawable-v34/status_warn_to_scanning_anim.xml225
-rw-r--r--PermissionController/res/drawable/coarse_off_dark.gifbin170063 -> 0 bytes
-rw-r--r--PermissionController/res/drawable/coarse_off_light.gifbin127528 -> 0 bytes
-rw-r--r--PermissionController/res/drawable/coarse_on_dark.gifbin196366 -> 0 bytes
-rw-r--r--PermissionController/res/drawable/coarse_on_light.gifbin149193 -> 0 bytes
-rw-r--r--PermissionController/res/drawable/fine_off_dark.gifbin178865 -> 0 bytes
-rw-r--r--PermissionController/res/drawable/fine_off_light.gifbin110934 -> 0 bytes
-rw-r--r--PermissionController/res/drawable/fine_on_dark.gifbin160541 -> 0 bytes
-rw-r--r--PermissionController/res/drawable/fine_on_light.gifbin117548 -> 0 bytes
-rw-r--r--PermissionController/res/drawable/forward_arrow.xml (renamed from PermissionController/res/drawable-v31/ic_safety_warn_outline.xml)19
-rw-r--r--PermissionController/res/drawable/grant_dialog_permission_rationale_background.xml (renamed from PermissionController/res/drawable-v31/indicator_background_circle.xml)11
-rw-r--r--PermissionController/res/drawable/ic_more_info_arrow.xml23
-rw-r--r--PermissionController/res/drawable/ic_settings_notification.xml92
-rw-r--r--PermissionController/res/drawable/ic_shield_exclamation_outline.xml23
-rw-r--r--PermissionController/res/drawable/settings_gear.xml27
-rw-r--r--PermissionController/res/layout-television/grant_permissions.xml6
-rw-r--r--PermissionController/res/layout-v31/expand_button_with_large_title.xml9
-rw-r--r--PermissionController/res/layout-v31/preference_issue_card.xml77
-rw-r--r--PermissionController/res/layout-v31/preference_safety_status.xml56
-rw-r--r--PermissionController/res/layout-v31/safety_center_toggle_button.xml46
-rw-r--r--PermissionController/res/layout-v33/action_button_list.xml20
-rw-r--r--PermissionController/res/layout-v33/indicator_card.xml79
-rw-r--r--PermissionController/res/layout-v33/preference_category_no_label.xml19
-rw-r--r--PermissionController/res/layout-v33/preference_entry.xml20
-rw-r--r--PermissionController/res/layout-v33/preference_entry_icon_action_gear_widget.xml22
-rw-r--r--PermissionController/res/layout-v33/preference_entry_icon_action_info_widget.xml22
-rw-r--r--PermissionController/res/layout-v33/preference_group.xml20
-rw-r--r--PermissionController/res/layout-v33/preference_issue_card.xml93
-rw-r--r--PermissionController/res/layout-v33/preference_more_issues_card.xml20
-rw-r--r--PermissionController/res/layout-v33/preference_safety_status.xml (renamed from PermissionController/res/drawable/safety_center_button_background.xml)9
-rw-r--r--PermissionController/res/layout-v33/safety_center_entry_common_view.xml46
-rw-r--r--PermissionController/res/layout-v33/safety_center_group.xml49
-rw-r--r--PermissionController/res/layout-v33/safety_center_group_entry.xml20
-rw-r--r--PermissionController/res/layout-v33/safety_center_qs.xml81
-rw-r--r--PermissionController/res/layout-v33/safety_center_scroll_wrapper.xml28
-rw-r--r--PermissionController/res/layout-v33/safety_center_toggle_button.xml42
-rw-r--r--PermissionController/res/layout-v33/spaced_preference_category_no_label.xml18
-rw-r--r--PermissionController/res/layout-v33/view_entry.xml32
-rw-r--r--PermissionController/res/layout-v33/view_more_issues.xml45
-rw-r--r--PermissionController/res/layout-v33/view_status_card.xml61
-rw-r--r--PermissionController/res/layout-v34/app_data_sharing_details_preference.xml32
-rw-r--r--PermissionController/res/layout-v34/app_data_sharing_settings_preference.xml50
-rw-r--r--PermissionController/res/layout-v34/app_data_sharing_updates_footer_preference.xml39
-rw-r--r--PermissionController/res/layout-v34/permission_rationale.xml143
-rw-r--r--PermissionController/res/layout-v34/preference_brand_chip.xml25
-rw-r--r--PermissionController/res/layout-v34/preference_illustration.xml23
-rw-r--r--PermissionController/res/layout-v34/safety_center_non_scroll_wrapper.xml21
-rw-r--r--PermissionController/res/layout-w764dp-v33/action_button_list.xml21
-rw-r--r--PermissionController/res/layout/app_permission.xml46
-rw-r--r--PermissionController/res/layout/grant_permissions.xml43
-rw-r--r--PermissionController/res/layout/grant_permissions_material3.xml52
-rw-r--r--PermissionController/res/layout/image_view_with_divider.xml8
-rw-r--r--PermissionController/res/layout/indicator_card.xml66
-rw-r--r--PermissionController/res/layout/preference_spacer.xml19
-rw-r--r--PermissionController/res/layout/safety_center_qs.xml99
-rw-r--r--PermissionController/res/navigation/nav_graph.xml5
-rw-r--r--PermissionController/res/raw-night/coarse_loc_off.json1
-rw-r--r--PermissionController/res/raw-night/coarse_loc_on.json1
-rw-r--r--PermissionController/res/raw-night/fine_loc_off.json1
-rw-r--r--PermissionController/res/raw-night/fine_loc_on.json1
-rw-r--r--PermissionController/res/raw/coarse_loc_off.json1
-rw-r--r--PermissionController/res/raw/coarse_loc_on.json1
-rw-r--r--PermissionController/res/raw/fine_loc_off.json1
-rw-r--r--PermissionController/res/raw/fine_loc_on.json1
-rw-r--r--PermissionController/res/values-af-v33/strings.xml24
-rw-r--r--PermissionController/res/values-af-v34/strings.xml27
-rw-r--r--PermissionController/res/values-af/strings.xml150
-rw-r--r--PermissionController/res/values-am-v33/strings.xml24
-rw-r--r--PermissionController/res/values-am-v34/strings.xml27
-rw-r--r--PermissionController/res/values-am/strings.xml188
-rw-r--r--PermissionController/res/values-ar-v33/strings.xml24
-rw-r--r--PermissionController/res/values-ar-v34/strings.xml27
-rw-r--r--PermissionController/res/values-ar/strings.xml152
-rw-r--r--PermissionController/res/values-as-v33/strings.xml24
-rw-r--r--PermissionController/res/values-as-v34/strings.xml27
-rw-r--r--PermissionController/res/values-as/strings.xml148
-rw-r--r--PermissionController/res/values-az-v33/strings.xml24
-rw-r--r--PermissionController/res/values-az-v34/strings.xml27
-rw-r--r--PermissionController/res/values-az/strings.xml148
-rw-r--r--PermissionController/res/values-b+sr+Latn-v33/strings.xml24
-rw-r--r--PermissionController/res/values-b+sr+Latn-v34/strings.xml27
-rw-r--r--PermissionController/res/values-b+sr+Latn/strings.xml148
-rw-r--r--PermissionController/res/values-be-v33/strings.xml24
-rw-r--r--PermissionController/res/values-be-v34/strings.xml27
-rw-r--r--PermissionController/res/values-be/strings.xml150
-rw-r--r--PermissionController/res/values-bg-v33/strings.xml24
-rw-r--r--PermissionController/res/values-bg-v34/strings.xml27
-rw-r--r--PermissionController/res/values-bg/strings.xml146
-rw-r--r--PermissionController/res/values-bn-v33/strings.xml24
-rw-r--r--PermissionController/res/values-bn-v34/strings.xml27
-rw-r--r--PermissionController/res/values-bn/strings.xml150
-rw-r--r--PermissionController/res/values-bs-v33/strings.xml24
-rw-r--r--PermissionController/res/values-bs-v34/strings.xml27
-rw-r--r--PermissionController/res/values-bs/strings.xml152
-rw-r--r--PermissionController/res/values-ca-v33/strings.xml24
-rw-r--r--PermissionController/res/values-ca-v34/strings.xml27
-rw-r--r--PermissionController/res/values-ca/strings.xml154
-rw-r--r--PermissionController/res/values-cs-v33/strings.xml24
-rw-r--r--PermissionController/res/values-cs-v34/strings.xml27
-rw-r--r--PermissionController/res/values-cs/strings.xml148
-rw-r--r--PermissionController/res/values-da-v33/strings.xml24
-rw-r--r--PermissionController/res/values-da-v34/strings.xml27
-rw-r--r--PermissionController/res/values-da/strings.xml150
-rw-r--r--PermissionController/res/values-de-v33/strings.xml24
-rw-r--r--PermissionController/res/values-de-v34/strings.xml27
-rw-r--r--PermissionController/res/values-de/strings.xml148
-rw-r--r--PermissionController/res/values-el-v33/strings.xml24
-rw-r--r--PermissionController/res/values-el-v34/strings.xml27
-rw-r--r--PermissionController/res/values-el/strings.xml146
-rw-r--r--PermissionController/res/values-en-rAU-v33/strings.xml24
-rw-r--r--PermissionController/res/values-en-rAU-v34/strings.xml27
-rw-r--r--PermissionController/res/values-en-rAU/strings.xml146
-rw-r--r--PermissionController/res/values-en-rCA-v33/strings.xml24
-rw-r--r--PermissionController/res/values-en-rCA-v34/strings.xml27
-rw-r--r--PermissionController/res/values-en-rCA/strings.xml146
-rw-r--r--PermissionController/res/values-en-rGB-v33/strings.xml24
-rw-r--r--PermissionController/res/values-en-rGB-v34/strings.xml27
-rw-r--r--PermissionController/res/values-en-rGB/strings.xml146
-rw-r--r--PermissionController/res/values-en-rIN-v33/strings.xml24
-rw-r--r--PermissionController/res/values-en-rIN-v34/strings.xml27
-rw-r--r--PermissionController/res/values-en-rIN/strings.xml146
-rw-r--r--PermissionController/res/values-en-rXC-v33/strings.xml24
-rw-r--r--PermissionController/res/values-en-rXC-v34/strings.xml27
-rw-r--r--PermissionController/res/values-en-rXC/strings.xml146
-rw-r--r--PermissionController/res/values-es-rUS-v33/strings.xml24
-rw-r--r--PermissionController/res/values-es-rUS-v34/strings.xml27
-rw-r--r--PermissionController/res/values-es-rUS/strings.xml150
-rw-r--r--PermissionController/res/values-es-v33/strings.xml24
-rw-r--r--PermissionController/res/values-es-v34/strings.xml27
-rw-r--r--PermissionController/res/values-es/strings.xml154
-rw-r--r--PermissionController/res/values-et-v33/strings.xml24
-rw-r--r--PermissionController/res/values-et-v34/strings.xml27
-rw-r--r--PermissionController/res/values-et/strings.xml150
-rw-r--r--PermissionController/res/values-eu-v33/strings.xml24
-rw-r--r--PermissionController/res/values-eu-v34/strings.xml27
-rw-r--r--PermissionController/res/values-eu/strings.xml150
-rw-r--r--PermissionController/res/values-fa-v33/strings.xml24
-rw-r--r--PermissionController/res/values-fa-v34/strings.xml27
-rw-r--r--PermissionController/res/values-fa/strings.xml156
-rw-r--r--PermissionController/res/values-fi-v33/strings.xml24
-rw-r--r--PermissionController/res/values-fi-v34/strings.xml27
-rw-r--r--PermissionController/res/values-fi/strings.xml148
-rw-r--r--PermissionController/res/values-fr-rCA-v33/strings.xml24
-rw-r--r--PermissionController/res/values-fr-rCA-v34/strings.xml27
-rw-r--r--PermissionController/res/values-fr-rCA/strings.xml148
-rw-r--r--PermissionController/res/values-fr-v33/strings.xml24
-rw-r--r--PermissionController/res/values-fr-v34/strings.xml27
-rw-r--r--PermissionController/res/values-fr/strings.xml146
-rw-r--r--PermissionController/res/values-gl-v33/strings.xml24
-rw-r--r--PermissionController/res/values-gl-v34/strings.xml27
-rw-r--r--PermissionController/res/values-gl/strings.xml154
-rw-r--r--PermissionController/res/values-gu-v33/strings.xml24
-rw-r--r--PermissionController/res/values-gu-v34/strings.xml27
-rw-r--r--PermissionController/res/values-gu/strings.xml148
-rw-r--r--PermissionController/res/values-hi-v33/strings.xml24
-rw-r--r--PermissionController/res/values-hi-v34/strings.xml27
-rw-r--r--PermissionController/res/values-hi/strings.xml150
-rw-r--r--PermissionController/res/values-hr-v33/strings.xml24
-rw-r--r--PermissionController/res/values-hr-v34/strings.xml27
-rw-r--r--PermissionController/res/values-hr/strings.xml150
-rw-r--r--PermissionController/res/values-hu-v33/strings.xml24
-rw-r--r--PermissionController/res/values-hu-v34/strings.xml27
-rw-r--r--PermissionController/res/values-hu/strings.xml146
-rw-r--r--PermissionController/res/values-hy-v33/strings.xml24
-rw-r--r--PermissionController/res/values-hy-v34/strings.xml27
-rw-r--r--PermissionController/res/values-hy/strings.xml146
-rw-r--r--PermissionController/res/values-in-v33/strings.xml24
-rw-r--r--PermissionController/res/values-in-v34/strings.xml27
-rw-r--r--PermissionController/res/values-in/strings.xml148
-rw-r--r--PermissionController/res/values-is-v33/strings.xml24
-rw-r--r--PermissionController/res/values-is-v34/strings.xml27
-rw-r--r--PermissionController/res/values-is/strings.xml148
-rw-r--r--PermissionController/res/values-it-v33/strings.xml24
-rw-r--r--PermissionController/res/values-it-v34/strings.xml27
-rw-r--r--PermissionController/res/values-it/strings.xml152
-rw-r--r--PermissionController/res/values-iw-v33/strings.xml24
-rw-r--r--PermissionController/res/values-iw-v34/strings.xml27
-rw-r--r--PermissionController/res/values-iw/strings.xml150
-rw-r--r--PermissionController/res/values-ja-v33/strings.xml24
-rw-r--r--PermissionController/res/values-ja-v34/strings.xml27
-rw-r--r--PermissionController/res/values-ja/strings.xml148
-rw-r--r--PermissionController/res/values-ka-v33/strings.xml24
-rw-r--r--PermissionController/res/values-ka-v34/strings.xml27
-rw-r--r--PermissionController/res/values-ka/strings.xml146
-rw-r--r--PermissionController/res/values-kk-v33/strings.xml24
-rw-r--r--PermissionController/res/values-kk-v34/strings.xml27
-rw-r--r--PermissionController/res/values-kk/strings.xml148
-rw-r--r--PermissionController/res/values-km-v33/strings.xml24
-rw-r--r--PermissionController/res/values-km-v34/strings.xml27
-rw-r--r--PermissionController/res/values-km/strings.xml150
-rw-r--r--PermissionController/res/values-kn-v33/strings.xml24
-rw-r--r--PermissionController/res/values-kn-v34/strings.xml27
-rw-r--r--PermissionController/res/values-kn/strings.xml150
-rw-r--r--PermissionController/res/values-ko-v33/strings.xml24
-rw-r--r--PermissionController/res/values-ko-v34/strings.xml27
-rw-r--r--PermissionController/res/values-ko/strings.xml150
-rw-r--r--PermissionController/res/values-ky-v33/strings.xml24
-rw-r--r--PermissionController/res/values-ky-v34/strings.xml27
-rw-r--r--PermissionController/res/values-ky/strings.xml146
-rw-r--r--PermissionController/res/values-lo-v33/strings.xml24
-rw-r--r--PermissionController/res/values-lo-v34/strings.xml27
-rw-r--r--PermissionController/res/values-lo/strings.xml146
-rw-r--r--PermissionController/res/values-lt-v33/strings.xml24
-rw-r--r--PermissionController/res/values-lt-v34/strings.xml27
-rw-r--r--PermissionController/res/values-lt/strings.xml148
-rw-r--r--PermissionController/res/values-lv-v33/strings.xml24
-rw-r--r--PermissionController/res/values-lv-v34/strings.xml27
-rw-r--r--PermissionController/res/values-lv/strings.xml146
-rw-r--r--PermissionController/res/values-mk-v33/strings.xml24
-rw-r--r--PermissionController/res/values-mk-v34/strings.xml27
-rw-r--r--PermissionController/res/values-mk/strings.xml146
-rw-r--r--PermissionController/res/values-ml-v33/strings.xml24
-rw-r--r--PermissionController/res/values-ml-v34/strings.xml27
-rw-r--r--PermissionController/res/values-ml/strings.xml146
-rw-r--r--PermissionController/res/values-mn-v33/strings.xml24
-rw-r--r--PermissionController/res/values-mn-v34/strings.xml27
-rw-r--r--PermissionController/res/values-mn/strings.xml146
-rw-r--r--PermissionController/res/values-mr-v33/strings.xml24
-rw-r--r--PermissionController/res/values-mr-v34/strings.xml27
-rw-r--r--PermissionController/res/values-mr/strings.xml146
-rw-r--r--PermissionController/res/values-ms-v33/strings.xml24
-rw-r--r--PermissionController/res/values-ms-v34/strings.xml27
-rw-r--r--PermissionController/res/values-ms/strings.xml146
-rw-r--r--PermissionController/res/values-my-v33/strings.xml24
-rw-r--r--PermissionController/res/values-my-v34/strings.xml27
-rw-r--r--PermissionController/res/values-my/strings.xml150
-rw-r--r--PermissionController/res/values-nb-v33/strings.xml24
-rw-r--r--PermissionController/res/values-nb-v34/strings.xml27
-rw-r--r--PermissionController/res/values-nb/strings.xml146
-rw-r--r--PermissionController/res/values-ne-v33/strings.xml24
-rw-r--r--PermissionController/res/values-ne-v34/strings.xml27
-rw-r--r--PermissionController/res/values-ne/strings.xml150
-rw-r--r--PermissionController/res/values-night-v31/colors.xml9
-rw-r--r--PermissionController/res/values-night-v33/themes.xml64
-rw-r--r--PermissionController/res/values-night-v34/colors.xml21
-rw-r--r--PermissionController/res/values-night-v34/themes.xml32
-rw-r--r--PermissionController/res/values-night/colors.xml22
-rw-r--r--PermissionController/res/values-night/themes.xml2
-rw-r--r--PermissionController/res/values-nl-v33/strings.xml24
-rw-r--r--PermissionController/res/values-nl-v34/strings.xml27
-rw-r--r--PermissionController/res/values-nl/strings.xml148
-rw-r--r--PermissionController/res/values-or-v33/strings.xml24
-rw-r--r--PermissionController/res/values-or-v34/strings.xml27
-rw-r--r--PermissionController/res/values-or-watch/strings.xml2
-rw-r--r--PermissionController/res/values-or/strings.xml152
-rw-r--r--PermissionController/res/values-pa-v33/strings.xml24
-rw-r--r--PermissionController/res/values-pa-v34/strings.xml27
-rw-r--r--PermissionController/res/values-pa/strings.xml148
-rw-r--r--PermissionController/res/values-pl-v33/strings.xml24
-rw-r--r--PermissionController/res/values-pl-v34/strings.xml27
-rw-r--r--PermissionController/res/values-pl/strings.xml152
-rw-r--r--PermissionController/res/values-pt-rBR-v33/strings.xml24
-rw-r--r--PermissionController/res/values-pt-rBR-v34/strings.xml27
-rw-r--r--PermissionController/res/values-pt-rBR/strings.xml152
-rw-r--r--PermissionController/res/values-pt-rPT-v33/strings.xml24
-rw-r--r--PermissionController/res/values-pt-rPT-v34/strings.xml27
-rw-r--r--PermissionController/res/values-pt-rPT/strings.xml184
-rw-r--r--PermissionController/res/values-pt-v33/strings.xml24
-rw-r--r--PermissionController/res/values-pt-v34/strings.xml27
-rw-r--r--PermissionController/res/values-pt/strings.xml152
-rw-r--r--PermissionController/res/values-ro-v33/strings.xml24
-rw-r--r--PermissionController/res/values-ro-v34/strings.xml27
-rw-r--r--PermissionController/res/values-ro/strings.xml148
-rw-r--r--PermissionController/res/values-ru-v33/strings.xml24
-rw-r--r--PermissionController/res/values-ru-v34/strings.xml27
-rw-r--r--PermissionController/res/values-ru/strings.xml150
-rw-r--r--PermissionController/res/values-si-v33/strings.xml24
-rw-r--r--PermissionController/res/values-si-v34/strings.xml27
-rw-r--r--PermissionController/res/values-si/strings.xml148
-rw-r--r--PermissionController/res/values-sk-v33/strings.xml24
-rw-r--r--PermissionController/res/values-sk-v34/strings.xml27
-rw-r--r--PermissionController/res/values-sk/strings.xml148
-rw-r--r--PermissionController/res/values-sl-v33/strings.xml24
-rw-r--r--PermissionController/res/values-sl-v34/strings.xml27
-rw-r--r--PermissionController/res/values-sl/strings.xml150
-rw-r--r--PermissionController/res/values-sq-v33/strings.xml24
-rw-r--r--PermissionController/res/values-sq-v34/strings.xml27
-rw-r--r--PermissionController/res/values-sq/strings.xml158
-rw-r--r--PermissionController/res/values-sr-v33/strings.xml24
-rw-r--r--PermissionController/res/values-sr-v34/strings.xml27
-rw-r--r--PermissionController/res/values-sr/strings.xml148
-rw-r--r--PermissionController/res/values-sv-v33/strings.xml24
-rw-r--r--PermissionController/res/values-sv-v34/strings.xml27
-rw-r--r--PermissionController/res/values-sv/strings.xml146
-rw-r--r--PermissionController/res/values-sw-v33/strings.xml24
-rw-r--r--PermissionController/res/values-sw-v34/strings.xml27
-rw-r--r--PermissionController/res/values-sw/strings.xml146
-rw-r--r--PermissionController/res/values-ta-v33/strings.xml24
-rw-r--r--PermissionController/res/values-ta-v34/strings.xml27
-rw-r--r--PermissionController/res/values-ta/strings.xml148
-rw-r--r--PermissionController/res/values-te-v33/strings.xml24
-rw-r--r--PermissionController/res/values-te-v34/strings.xml27
-rw-r--r--PermissionController/res/values-te/strings.xml152
-rw-r--r--PermissionController/res/values-television/themes.xml6
-rw-r--r--PermissionController/res/values-th-v33/strings.xml24
-rw-r--r--PermissionController/res/values-th-v34/strings.xml27
-rw-r--r--PermissionController/res/values-th/strings.xml146
-rw-r--r--PermissionController/res/values-tl-v33/strings.xml24
-rw-r--r--PermissionController/res/values-tl-v34/strings.xml27
-rw-r--r--PermissionController/res/values-tl/strings.xml148
-rw-r--r--PermissionController/res/values-tr-v33/strings.xml24
-rw-r--r--PermissionController/res/values-tr-v34/strings.xml27
-rw-r--r--PermissionController/res/values-tr/strings.xml148
-rw-r--r--PermissionController/res/values-uk-v33/strings.xml24
-rw-r--r--PermissionController/res/values-uk-v34/strings.xml27
-rw-r--r--PermissionController/res/values-uk/strings.xml152
-rw-r--r--PermissionController/res/values-ur-v33/strings.xml24
-rw-r--r--PermissionController/res/values-ur-v34/strings.xml27
-rw-r--r--PermissionController/res/values-ur/strings.xml148
-rw-r--r--PermissionController/res/values-uz-v33/strings.xml24
-rw-r--r--PermissionController/res/values-uz-v34/strings.xml27
-rw-r--r--PermissionController/res/values-uz/strings.xml152
-rw-r--r--PermissionController/res/values-v31/colors.xml3
-rw-r--r--PermissionController/res/values-v31/styles.xml138
-rw-r--r--PermissionController/res/values-v33/attrs.xml43
-rw-r--r--PermissionController/res/values-v33/bools.xml21
-rw-r--r--PermissionController/res/values-v33/colors.xml99
-rw-r--r--PermissionController/res/values-v33/dimens.xml55
-rw-r--r--PermissionController/res/values-v33/strings.xml61
-rw-r--r--PermissionController/res/values-v33/styles.xml810
-rw-r--r--PermissionController/res/values-v33/themes.xml110
-rw-r--r--PermissionController/res/values-v34/bools.xml21
-rw-r--r--PermissionController/res/values-v34/colors.xml55
-rw-r--r--PermissionController/res/values-v34/dimens.xml25
-rw-r--r--PermissionController/res/values-v34/ids.xml19
-rw-r--r--PermissionController/res/values-v34/strings.xml35
-rw-r--r--PermissionController/res/values-v34/styles.xml374
-rw-r--r--PermissionController/res/values-v34/themes.xml30
-rw-r--r--PermissionController/res/values-vi-v33/strings.xml24
-rw-r--r--PermissionController/res/values-vi-v34/strings.xml27
-rw-r--r--PermissionController/res/values-vi/strings.xml150
-rw-r--r--PermissionController/res/values-w492dp-v33/styles.xml38
-rw-r--r--PermissionController/res/values-w764dp-v33/dimens.xml19
-rw-r--r--PermissionController/res/values-w764dp-v33/styles.xml40
-rw-r--r--PermissionController/res/values-w764dp-v34/dimens.xml19
-rw-r--r--PermissionController/res/values-w800dp-v33/styles.xml38
-rw-r--r--PermissionController/res/values-zh-rCN-v33/strings.xml24
-rw-r--r--PermissionController/res/values-zh-rCN-v34/strings.xml27
-rw-r--r--PermissionController/res/values-zh-rCN/strings.xml148
-rw-r--r--PermissionController/res/values-zh-rHK-v33/strings.xml24
-rw-r--r--PermissionController/res/values-zh-rHK-v34/strings.xml27
-rw-r--r--PermissionController/res/values-zh-rHK/strings.xml150
-rw-r--r--PermissionController/res/values-zh-rTW-v33/strings.xml24
-rw-r--r--PermissionController/res/values-zh-rTW-v34/strings.xml27
-rw-r--r--PermissionController/res/values-zh-rTW/strings.xml146
-rw-r--r--PermissionController/res/values-zu-v33/strings.xml24
-rw-r--r--PermissionController/res/values-zu-v34/strings.xml27
-rw-r--r--PermissionController/res/values-zu/strings.xml148
-rw-r--r--PermissionController/res/values/bools.xml22
-rw-r--r--PermissionController/res/values/colors.xml12
-rw-r--r--PermissionController/res/values/config.xml3
-rw-r--r--PermissionController/res/values/overlayable.xml234
-rw-r--r--PermissionController/res/values/strings.xml413
-rw-r--r--PermissionController/res/values/styles.xml161
-rw-r--r--PermissionController/res/values/themes.xml6
-rw-r--r--PermissionController/res/xml-v34/app_data_sharing_updates.xml28
-rw-r--r--PermissionController/res/xml-v34/privacy_subpage.xml67
-rw-r--r--PermissionController/res/xml-v34/safety_center_subpage.xml45
-rw-r--r--PermissionController/res/xml/privacy_controls.xml53
-rw-r--r--PermissionController/res/xml/roles.xml282
-rw-r--r--PermissionController/res/xml/safety_center_dashboard.xml19
-rw-r--r--PermissionController/res/xml/unused_app_categories.xml6
-rw-r--r--PermissionController/role-controller/Android.bp37
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/AssistantRoleBehavior.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/AssistantRoleBehavior.java)54
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/AutomotiveRoleBehavior.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/AutomotiveRoleBehavior.java)5
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/BrowserRoleBehavior.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/BrowserRoleBehavior.java)26
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceAppStreamingRoleBehavior.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/CompanionDeviceAppStreamingRoleBehavior.java)6
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceComputerRoleBehavior.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/CompanionDeviceComputerRoleBehavior.java)6
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceGlassesRoleBehavior.java41
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceWatchRoleBehavior.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/CompanionDeviceWatchRoleBehavior.java)6
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/DevicePolicyManagementRoleBehavior.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/DevicePolicyManagementRoleBehavior.java)5
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/DialerRoleBehavior.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/DialerRoleBehavior.java)40
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/DocumentManagerRoleBehavior.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/DocumentManagerRoleBehavior.java)5
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/EmergencyRoleBehavior.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/EmergencyRoleBehavior.java)20
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/HomeRoleBehavior.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/HomeRoleBehavior.java)88
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/NotesRoleBehavior.java58
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/SmsRoleBehavior.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/SmsRoleBehavior.java)54
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/SystemShellRoleBehavior.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/SystemShellRoleBehavior.java)5
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/SystemUiRoleBehavior.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/SystemUiRoleBehavior.java)5
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/SystemWearHealthServiceRoleBehavior.java36
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/behavior/TelevisionRoleBehavior.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/TelevisionRoleBehavior.java)5
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/AppOp.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/AppOp.java)8
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/AppOpPermissions.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/AppOpPermissions.java)6
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/IntentFilterData.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/IntentFilterData.java)2
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/Permission.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/Permission.java)8
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/PermissionSet.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/PermissionSet.java)2
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/Permissions.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/Permissions.java)63
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/PreferredActivity.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/PreferredActivity.java)2
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/RequiredActivity.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/RequiredActivity.java)14
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/RequiredBroadcastReceiver.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/RequiredBroadcastReceiver.java)13
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/RequiredComponent.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/RequiredComponent.java)50
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/RequiredContentProvider.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/RequiredContentProvider.java)13
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/RequiredMetaData.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/RequiredMetaData.java)2
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/RequiredService.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/RequiredService.java)14
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/Role.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/Role.java)206
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/RoleBehavior.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/RoleBehavior.java)57
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/RoleParser.java)79
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/Roles.java (renamed from PermissionController/src/com/android/permissioncontroller/role/model/Roles.java)2
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/util/ArrayUtils.java61
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/util/CollectionUtils.java89
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/util/NotificationUtils.java (renamed from PermissionController/src/com/android/permissioncontroller/role/utils/NotificationUtils.java)2
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/util/PackageUtils.java91
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/util/RoleManagerCompat.java102
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/util/UserUtils.java88
-rw-r--r--PermissionController/role-controller/lint-baseline.xml15
-rw-r--r--PermissionController/src/com/android/permissioncontroller/Constants.java111
-rw-r--r--PermissionController/src/com/android/permissioncontroller/DeviceUtils.java4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/PermissionController.proto2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/PermissionControllerApplication.java32
-rw-r--r--PermissionController/src/com/android/permissioncontroller/hibernation/HibernationPolicy.kt406
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/TEST_MAPPING54
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompat.java84
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/AppPermGroupUiInfoLiveData.kt20
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/AutoRevokedPackagesLiveData.kt5
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/CustomPermGroupNamesLiveData.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/ForegroundPermNamesLiveData.kt3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/LightPackageInfoLiveData.kt22
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/LightPermInfoLiveData.kt2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/PackageBroadcastReceiver.kt9
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/PackagePermissionsLiveData.kt6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupUsageLiveData.kt2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesLiveData.kt2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesUiInfoLiveData.kt54
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/PermissionChange.kt (renamed from PermissionController/src/com/android/permissioncontroller/permission/data/v33/PermissionChange.kt)6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/PermissionEvent.kt (renamed from PermissionController/src/com/android/permissioncontroller/permission/data/v33/PermissionEvent.kt)6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/ServiceLiveData.kt12
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/SinglePermGroupPackagesUiInfoLiveData.kt5
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/SmartUpdateMediatorLiveData.kt19
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/StandardPermGroupNamesLiveData.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/UserPackageInfosLiveData.kt42
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/UserSensitivityLiveData.kt3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/UsersLiveData.kt1
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightHistoricalPackageOpsLiveData.kt147
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightPackageOpsLiveData.kt149
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/v31/package-info.java (renamed from service/java/com/android/access/AccessCheckingService.kt)12
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/v33/PermissionDecision.kt1
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/v33/RecentPermissionDecisionsLiveData.kt2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/v34/AppDataSharingUpdatesLiveData.kt77
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/v34/LightInstallSourceInfoLiveData.kt107
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/v34/SafetyLabelInfoLiveData.kt130
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/v34/package-info.java18
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/AppPermissionGroup.java58
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/legacy/PermissionApps.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/legacy/PermissionGroups.java6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightAppPermGroup.kt18
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt77
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermission.kt19
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/AppPermissionId.kt10
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightHistoricalPackageOps.kt229
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightPackageOps.kt79
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/package-info.java18
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v34/LightInstallSourceInfo.kt61
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v34/SafetyLabelInfo.kt36
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v34/package-info.java18
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/v31/AppPermissionUsage.java66
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/v31/PermissionUsages.java6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/v34/AppDataSharingUpdate.kt106
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/AutoRevokePermissions.kt19
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/BasePermissionEventStorage.kt (renamed from PermissionController/src/com/android/permissioncontroller/permission/service/v33/BasePermissionEventStorage.kt)7
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/LocationAccessCheck.java722
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PermissionChangeStorageImpl.kt214
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java36
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceModel.kt13
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventCleanupJobService.kt (renamed from PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionEventCleanupJobService.kt)5
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventStorage.kt (renamed from PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionEventStorage.kt)7
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventStorageImpls.kt (renamed from PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionEventStorageImpls.kt)12
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PermissionSearchIndexablesProvider.java4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PermissionStorageTimeChangeReceiver.kt (renamed from PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionStorageTimeChangeReceiver.kt)7
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PersistedStoragePackageUninstalledReceiver.kt (renamed from PermissionController/src/com/android/permissioncontroller/permission/service/v33/PersistedStoragePackageUninstalledReceiver.kt)7
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/RuntimePermissionsUpgradeController.kt109
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/SplitPermissionIndex.kt6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/TEST_MAPPING17
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionDecisionStorageImpl.kt2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/v33/SafetyCenterQsTileService.kt40
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/v33/TEST_MAPPING7
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/v34/SafetyLabelChangesJobService.kt723
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/v34/package-info.java18
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/AutoGrantPermissionsNotifier.java22
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java307
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsViewHandler.java19
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/ManagePermissionsActivity.java105
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/OverlayWarningDialog.java63
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/ReviewOngoingUsageActivity.java6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/UnusedAppsFragment.kt99
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAllAppPermissionsFragment.java10
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java5
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionsFragment.java3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoReviewPermissionDecisionsFragment.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/GrantPermissionsAutoViewHandler.java5
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionHistoryPreference.kt82
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageDetailsFragment.kt216
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageFragment.kt152
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AllAppPermissionsFragment.java7
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java58
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java7
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.kt220
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ManageStandardPermissionsFragment.java15
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionControlPreference.java21
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionPreference.java8
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ReviewPermissionsFragment.java6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/CardViewPreference.java (renamed from PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/CardViewPreference.java)5
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/DashboardUtils.kt117
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionDetailsFragment.java396
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionDetailsWrapperFragment.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionHistoryPreference.java104
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageControlPreference.java (renamed from PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageV2ControlPreference.java)24
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageDetailsFragment.java433
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageFragment.java448
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageV2Fragment.java429
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageWrapperFragment.java (renamed from PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageV2WrapperFragment.java)14
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/ReviewOngoingUsageFragment.java6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v33/SafetyCenterQsFragment.java525
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingDetailsPreference.kt52
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatePreference.kt57
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFooterPreference.kt87
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFragment.kt321
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesWrapperFragment.kt39
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/PermissionRationaleViewHandlerImpl.kt277
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/package-info.java (renamed from PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v33/package-info.java)4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/AppPermissionActivity.java4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageDetailsViewModelLegacy.kt560
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageViewModelLegacy.kt231
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionGroupsViewModel.kt13
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt335
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt480
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageStandardPermissionsViewModel.kt14
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt27
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/ReviewPermissionsViewModel.kt8
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/UnusedAppsViewModel.kt165
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageControlPreferenceUtils.kt10
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModel.kt1088
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageViewModel.kt489
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/ReviewOngoingUsageViewModel.kt (renamed from PermissionController/src/com/android/permissioncontroller/permission/ui/model/ReviewOngoingUsageViewModel.kt)18
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v33/ReviewPermissionDecisionsViewModel.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/AppDataSharingUpdatesViewModel.kt191
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt263
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/package-info.java18
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/television/AllAppPermissionsFragment.java10
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java8
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionsFragment.java4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/television/GrantPermissionsViewHandlerImpl.java15
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionAppsFragment.java4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/v33/AdvancedConfirmDialogArgs.kt (renamed from PermissionController/src/com/android/permissioncontroller/permission/ui/AdvancedConfirmDialogArgs.kt)17
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/v33/widget/SafetyProtectionSectionView.kt (renamed from PermissionController/src/com/android/permissioncontroller/permission/ui/widget/SafetyProtectionSectionView.kt)2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/v34/PermissionRationaleActivity.java610
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/v34/PermissionRationaleViewHandler.kt104
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/v34/package-info.java18
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/AppPermissionsFragmentWear.java4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/GrantPermissionsWearViewHandler.java5
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/CollectionUtils.java25
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt477
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt409
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/SafetyNetLogger.java102
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java446
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/legacy/LegacySafetyNetLogger.java112
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/v31/AdminRestrictedPermissionsUtils.java (renamed from PermissionController/src/com/android/permissioncontroller/permission/utils/AdminRestrictedPermissionsUtils.java)31
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/v31/SubattributionUtils.java (renamed from PermissionController/src/com/android/permissioncontroller/permission/utils/SubattributionUtils.java)50
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/v34/SafetyLabelUtils.kt58
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySettingsUtil.kt92
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySourceService.kt986
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/AutoRevokePrivacySource.kt52
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/LocationAccessPrivacySource.kt43
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/NotificationListenerCheck.kt1125
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/NotificationListenerPregrants.kt49
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySource.kt25
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourceData.kt26
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourceStorageRepository.kt24
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourcesUtils.kt52
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/SafetyCenterReceiver.kt131
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/TEST_MAPPING40
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/TextStorageRepository.kt69
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/WorkPolicyInfo.kt136
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/v34/AppDataSharingUpdatesPrivacySource.kt121
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/Role.md12
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/TEST_MAPPING17
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/model/EncryptionUnawareConfirmationMixin.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/model/RoleParserInitializer.java35
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/model/VisibilityMixin.java3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/service/RoleControllerServiceImpl.java12
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/service/RoleSearchIndexablesProvider.java15
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppActivity.java8
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java13
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java11
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleActivity.java7
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleViewModel.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/RoleItem.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/RoleListLiveData.java7
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/RoleListSortFunction.java14
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/RoleLiveData.java6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/RoleSortFunction.java15
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/TwoTargetPreference.java3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoDefaultAppFragment.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/AssistantRoleUiBehavior.java63
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/BrowserRoleUiBehavior.java37
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/DialerRoleUiBehavior.java68
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/EmergencyRoleUiBehavior.java47
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/HomeRoleUiBehavior.java121
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/RoleUiBehavior.java133
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/SmsRoleUiBehavior.java47
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessActivity.java8
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessChildFragment.java10
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessListChildFragment.java12
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessViewModel.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/utils/PackageUtils.java35
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/utils/RoleManagerCompat.java42
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java151
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/utils/UiUtils.java55
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/utils/UserUtils.java39
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/SafetyCenterConstants.java46
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/TEST_MAPPING4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/package-info.java19
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java175
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterJobServiceFlags.java61
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterSearchIndexablesProvider.kt336
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/service/package-info.java19
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ClickableDisabledSwitchPreference.java123
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/CollapsableGroupCardHelper.kt57
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/CollapsableIssuesCardHelper.kt463
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ComparablePreference.kt30
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ComparablePreferenceCategory.kt54
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/EqualWidthContainer.kt49
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/HighlightablePreferenceGroupAdapter.java234
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/InteractionLogger.kt444
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardAnimator.kt220
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardPreference.java590
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardAnimator.kt114
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardPreference.kt98
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ParsedSafetyCenterIntent.kt78
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PendingIntentSender.kt54
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PositionInCardList.kt90
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PreferenceHighlightManager.kt131
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PrivacyControlsFragment.java82
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PrivacySubpageFragment.kt185
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyBrandChipPreference.kt85
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java239
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterContentManager.java52
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterDashboardFragment.java292
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterFragment.kt170
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterQsActivity.java (renamed from PermissionController/src/com/android/permissioncontroller/permission/ui/SafetyCenterQsActivity.java)46
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterQsFragment.java785
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterScrollWrapperFragment.kt49
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterSubpageFragment.kt179
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterTouchTarget.kt55
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterUiFlags.kt35
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyEntry.java117
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyEntryPreference.java82
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyGroupPreference.kt70
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyHomepageEntryPreference.kt73
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyIllustrationPreference.kt51
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyPreferenceComparisonCallback.java45
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusAnimationSequencer.kt168
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusPreference.java345
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetySubpageEntryPreference.kt139
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SeverityIconPicker.kt67
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SeverityLevel.java63
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SnakeCaseConverter.kt39
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SpacerPreference.kt129
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/StaticSafetyEntryPreference.java86
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/StatusAnimationResolver.kt149
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/TextFadeAnimator.kt124
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt316
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/PrivacyControlsViewModel.kt217
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterQsViewModel.kt (renamed from PermissionController/src/com/android/permissioncontroller/permission/ui/model/v33/SafetyCenterQsViewModel.kt)161
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterUiData.kt71
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterViewModel.kt95
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/StatusUiData.kt101
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/package-info.java19
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/package-info.java19
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/MoreIssuesHeaderView.kt255
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryCommonViewsManager.kt109
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryGroupView.kt279
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryView.kt197
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/StatusCardView.kt72
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/package-info.java19
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetylabel/AppsSafetyLabelHistory.kt150
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetylabel/AppsSafetyLabelHistoryPersistence.kt608
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetylabel/SafetyLabelChangedBroadcastReceiver.kt230
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetylabel/TEST_MAPPING27
-rw-r--r--PermissionController/tests/inprocess/Android.bp6
-rw-r--r--PermissionController/tests/inprocess/AndroidTest.xml2
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/GetPermissionGroupInfoTest.kt13
-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/util/ArrayUtilsTest.kt74
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/CollectionUtilsTest.kt60
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/KotlinUtilsTest.kt165
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/PermissionMappingTest.kt59
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/UtilsTest.kt274
-rw-r--r--PermissionController/tests/mocking/Android.bp16
-rw-r--r--PermissionController/tests/mocking/AndroidTest.xml2
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/hibernation/HibernationControllerTest.kt11
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/hibernation/HibernationPolicyTest.kt167
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/data/FakeEventStorage.kt (renamed from PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/data/v33/FakeEventStorage.kt)6
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/data/v33/RecentPermissionDecisionsLiveDataTest.kt1
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/BasePermissionEventStorageTest.kt (renamed from PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/BasePermissionEventStorageTest.kt)4
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionChangeStorageImplTest.kt165
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionEventCleanupJobServiceTest.kt (renamed from PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/PermissionEventCleanupJobServiceTest.kt)6
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionStorageTimeChangeReceiverTest.kt (renamed from PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/PermissionStorageTimeChangeReceiverTest.kt)14
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PersistedStoragePackageUninstalledReceiverTest.kt (renamed from PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/PersistedStoragePackageUninstalledReceiverTest.kt)6
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/RuntimePermissionsUpgradeControllerTest.kt115
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/TestPermissionEvent.kt (renamed from PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/TestPermissionEvent.kt)4
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/ReviewPermissionsViewModelTest.kt14
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/v34/LightInstallSourceInfoTest.kt218
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/utils/GrantRevokeTests.kt7
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/AccessibilitySourceServiceTest.kt235
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/AppDataSharingUpdatesPrivacySourceTest.kt197
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerCheckInternalTest.kt567
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerPregrantsTest.kt74
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerPrivacySourceTest.kt316
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/SafetyCenterReceiverTest.kt54
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/TextStorageRepositoryTest.kt146
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/WorkPolicyInfoTest.kt307
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/role/model/RoleParserTest.kt14
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/OWNERS3
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/SafetyStatusAnimationSequencerTest.kt391
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/SnakeCaseConverterTest.kt90
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/model/SafetyCenterUiDataTest.kt249
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/model/StatusUiDataTest.kt267
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/AppsSafetyLabelHistoryPersistenceTest.kt538
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/AppsSafetyLabelHistoryTest.kt295
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/SafetyLabelChangesJobServiceTest.kt161
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/TEST_MAPPING12
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/TestSafetyLabels.kt88
-rw-r--r--PermissionController/tests/outofprocess/Android.bp1
-rw-r--r--PermissionController/tests/outofprocess/AndroidTest.xml2
-rw-r--r--PermissionController/tests/permissionui/Android.bp1
-rw-r--r--PermissionController/tests/permissionui/AndroidTest.xml16
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/PermissionGroupPreferenceUtils.kt4
-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.kt13
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/AppPermissionFragmentTest.kt4
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/CustomPermissionAppsFragmentTest.kt4
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/PermissionAppsFragmentTest.kt9
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageCustomPermissionsFragmentTest.kt8
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ManageStandardPermissionsFragmentTest.kt27
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/ReviewOngoingUsageFragmentTest.kt4
-rw-r--r--PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/v31/PermissionUsageFragmentTest.kt (renamed from PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/v31/PermissionUsageV2FragmentTest.kt)29
-rw-r--r--SafetyCenter/Annotations/Android.bp48
-rw-r--r--SafetyCenter/Annotations/java/com/android/safetycenter/annotations/NonNullByDefault.java42
-rw-r--r--SafetyCenter/Config/Android.bp9
-rw-r--r--SafetyCenter/Config/TEST_MAPPING10
-rw-r--r--SafetyCenter/Config/java/com/android/safetycenter/config/ParseException.java6
-rw-r--r--SafetyCenter/Config/java/com/android/safetycenter/config/SafetyCenterConfigParser.java167
-rw-r--r--SafetyCenter/Config/java/com/android/safetycenter/config/package-info.java19
-rw-r--r--SafetyCenter/Config/tests/Android.bp3
-rw-r--r--SafetyCenter/Config/tests/AndroidTest.xml7
-rw-r--r--SafetyCenter/Config/tests/java/com/android/safetycenter/config/Coroutines.kt77
-rw-r--r--SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParseExceptionTest.kt3
-rw-r--r--SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigInvalidTest.kt719
-rw-r--r--SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigOverlayTest.kt19
-rw-r--r--SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigValidTest.kt139
-rw-r--r--SafetyCenter/Config/tests/overlay/Android.bp2
-rw-r--r--SafetyCenter/Config/tests/res/raw-v34/config_safety_sources_group_hidden_with_only_dynamic.xml15
-rw-r--r--SafetyCenter/Config/tests/res/raw-v34/config_safety_sources_group_hidden_with_only_static.xml14
-rw-r--r--SafetyCenter/Config/tests/res/raw-v34/config_safety_sources_group_stateful_with_only_issue_only.xml13
-rw-r--r--SafetyCenter/Config/tests/res/raw-v34/config_safety_sources_group_stateless_with_only_issue_only.xml13
-rw-r--r--SafetyCenter/Config/tests/res/raw-v34/config_static_safety_source_with_deduplication_groups.xml32
-rw-r--r--SafetyCenter/Config/tests/res/raw-v34/config_static_safety_source_with_notifications.xml16
-rw-r--r--SafetyCenter/Config/tests/res/raw-v34/config_static_safety_source_with_package_certs.xml32
-rw-r--r--SafetyCenter/Config/tests/res/raw-v34/config_valid.xml193
-rw-r--r--SafetyCenter/Config/tests/res/raw/config_dynamic_safety_source_invalid_id.xml16
-rw-r--r--SafetyCenter/Config/tests/res/raw/config_issue_only_safety_source_invalid_id.xml11
-rw-r--r--SafetyCenter/Config/tests/res/raw/config_safety_sources_group_invalid_id.xml15
-rw-r--r--SafetyCenter/Config/tests/res/raw/config_static_safety_source_invalid_id.xml15
-rw-r--r--SafetyCenter/Config/tests/res/raw/config_valid.xml4
-rw-r--r--SafetyCenter/Config/tests/res/values/strings.xml3
-rw-r--r--SafetyCenter/ConfigLintChecker/Android.bp7
-rw-r--r--SafetyCenter/ConfigLintChecker/java/android/annotation/SuppressLint.java39
-rw-r--r--SafetyCenter/ConfigLintChecker/java/android/os/Build.java8
-rw-r--r--SafetyCenter/ConfigLintChecker/java/android/os/Parcel.java4
-rw-r--r--SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ConfigLintCheckerIssueRegistry.kt16
-rw-r--r--SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ConfigSchemaDetector.kt61
-rw-r--r--SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/FileSdk.kt97
-rw-r--r--SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ParserExceptionDetector.kt92
-rw-r--r--SafetyCenter/ConfigLintChecker/java/android/util/ArraySet.java42
-rw-r--r--SafetyCenter/ConfigLintChecker/java/com/android/modules/utils/build/SdkLevel.java45
-rw-r--r--SafetyCenter/ConfigLintChecker/tests/java/android/safetycenter/lint/test/ConfigSchemaDetectorTest.kt130
-rw-r--r--SafetyCenter/ConfigLintChecker/tests/java/android/safetycenter/lint/test/ParserExceptionDetectorTest.kt185
-rw-r--r--SafetyCenter/InternalData/Android.bp50
-rw-r--r--SafetyCenter/InternalData/java/com/android/safetycenter/internaldata/SafetyCenterBundles.java100
-rw-r--r--SafetyCenter/InternalData/java/com/android/safetycenter/internaldata/SafetyCenterIds.java139
-rw-r--r--SafetyCenter/InternalData/java/com/android/safetycenter/internaldata/package-info.java19
-rw-r--r--SafetyCenter/InternalData/proto/safety_center_internal_data.proto67
-rw-r--r--SafetyCenter/OWNERS9
-rw-r--r--SafetyCenter/PendingIntents/Android.bp42
-rw-r--r--SafetyCenter/PendingIntents/java/com/android/safetycenter/pendingintents/PendingIntentSender.java134
-rw-r--r--SafetyCenter/PendingIntents/java/com/android/safetycenter/pendingintents/package-info.java19
-rw-r--r--SafetyCenter/Persistence/Android.bp36
-rw-r--r--SafetyCenter/Persistence/TEST_MAPPING7
-rw-r--r--SafetyCenter/Persistence/java/com/android/safetycenter/persistence/PersistedSafetyCenterIssue.java188
-rw-r--r--SafetyCenter/Persistence/java/com/android/safetycenter/persistence/PersistenceException.java34
-rw-r--r--SafetyCenter/Persistence/java/com/android/safetycenter/persistence/SafetyCenterIssuesPersistence.java307
-rw-r--r--SafetyCenter/Persistence/java/com/android/safetycenter/persistence/package-info.java19
-rw-r--r--SafetyCenter/Persistence/tests/Android.bp36
-rw-r--r--SafetyCenter/Persistence/tests/AndroidManifest.xml30
-rw-r--r--SafetyCenter/Persistence/tests/AndroidTest.xml86
-rw-r--r--SafetyCenter/Persistence/tests/data/invalid_file_corrupted.txt4
-rw-r--r--SafetyCenter/Persistence/tests/data/invalid_file_extra_attribute.xml4
-rw-r--r--SafetyCenter/Persistence/tests/data/invalid_file_extra_element.xml6
-rw-r--r--SafetyCenter/Persistence/tests/data/invalid_file_extra_root.txt7
-rw-r--r--SafetyCenter/Persistence/tests/data/invalid_file_inconsistent_dismiss_count.xml4
-rw-r--r--SafetyCenter/Persistence/tests/data/invalid_file_inconsistent_dismissed_at.xml4
-rw-r--r--SafetyCenter/Persistence/tests/data/invalid_file_invalid_dismiss_count.xml4
-rw-r--r--SafetyCenter/Persistence/tests/data/invalid_file_invalid_dismissed_at.xml4
-rw-r--r--SafetyCenter/Persistence/tests/data/invalid_file_invalid_first_seen_at.xml4
-rw-r--r--SafetyCenter/Persistence/tests/data/invalid_file_invalid_notification_dismissed_at.xml4
-rw-r--r--SafetyCenter/Persistence/tests/data/invalid_file_invalid_version.xml4
-rw-r--r--SafetyCenter/Persistence/tests/data/invalid_file_missing_first_seen_at.xml4
-rw-r--r--SafetyCenter/Persistence/tests/data/invalid_file_missing_key.xml4
-rw-r--r--SafetyCenter/Persistence/tests/data/invalid_file_missing_version.xml4
-rw-r--r--SafetyCenter/Persistence/tests/data/invalid_file_negative_dismiss_count.xml4
-rw-r--r--SafetyCenter/Persistence/tests/data/invalid_file_wrong_root.xml2
-rw-r--r--SafetyCenter/Persistence/tests/data/invalid_file_wrong_version.xml4
-rw-r--r--SafetyCenter/Persistence/tests/data/valid_file_v0.xml5
-rw-r--r--SafetyCenter/Persistence/tests/data/valid_file_v1.xml7
-rw-r--r--SafetyCenter/Persistence/tests/data/valid_file_v2.xml9
-rw-r--r--SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/PersistedSafetyCenterIssueTest.kt126
-rw-r--r--SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/PersistenceConstants.kt22
-rw-r--r--SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/PersistenceExceptionTest.kt48
-rw-r--r--SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/SafetyCenterIssuesPersistenceInvalidTest.kt160
-rw-r--r--SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/SafetyCenterIssuesPersistenceValidTest.kt107
-rw-r--r--SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/SafetyCenterIssuesPersistenceWriteTest.kt91
-rw-r--r--SafetyCenter/Resources/Android.bp19
-rw-r--r--SafetyCenter/Resources/AndroidManifestLibrary.xml19
-rw-r--r--SafetyCenter/Resources/res/drawable-night-v34/illustration_android_lock_screen_sources.xml62
-rw-r--r--SafetyCenter/Resources/res/drawable-v34/illustration_android_lock_screen_sources.xml62
-rw-r--r--SafetyCenter/Resources/res/drawable-w480dp-night-v34/illustration_android_lock_screen_sources.xml62
-rw-r--r--SafetyCenter/Resources/res/drawable-w480dp-v34/illustration_android_lock_screen_sources.xml62
-rw-r--r--SafetyCenter/Resources/res/raw-v34/safety_center_config.xml127
-rw-r--r--SafetyCenter/Resources/res/raw/safety_center_config.xml50
-rw-r--r--SafetyCenter/Resources/res/values-af-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-af/strings.xml10
-rw-r--r--SafetyCenter/Resources/res/values-am-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-am/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-ar-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-ar/strings.xml10
-rw-r--r--SafetyCenter/Resources/res/values-as-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-as/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-az-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-az/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-b+sr+Latn-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-b+sr+Latn/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-be-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-be/strings.xml12
-rw-r--r--SafetyCenter/Resources/res/values-bg-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-bg/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-bn-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-bn/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-bs-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-bs/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-ca-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-ca/strings.xml10
-rw-r--r--SafetyCenter/Resources/res/values-cs-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-cs/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-da-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-da/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-de-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-de/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-el-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-el/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-en-rAU-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-en-rAU/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-en-rCA-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-en-rCA/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-en-rGB-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-en-rGB/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-en-rIN-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-en-rIN/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-en-rXC-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-en-rXC/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-es-rUS-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-es-rUS/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-es-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-es/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-et-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-et/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-eu-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-eu/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-fa-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-fa/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-fi-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-fi/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-fr-rCA-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-fr-rCA/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-fr-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-fr/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-gl-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-gl/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-gu-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-gu/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-hi-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-hi/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-hr-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-hr/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-hu-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-hu/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-hy-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-hy/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-in-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-in/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-is-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-is/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-it-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-it/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-iw-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-iw/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-ja-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-ja/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-ka-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-ka/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-kk-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-kk/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-km-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-km/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-kn-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-kn/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-ko-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-ko/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-ky-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-ky/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-lo-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-lo/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-lt-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-lt/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-lv-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-lv/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-mk-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-mk/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-ml-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-ml/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-mn-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-mn/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-mr-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-mr/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-ms-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-ms/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-my-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-my/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-nb-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-nb/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-ne-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-ne/strings.xml10
-rw-r--r--SafetyCenter/Resources/res/values-nl-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-nl/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-or-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-or/strings.xml10
-rw-r--r--SafetyCenter/Resources/res/values-pa-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-pa/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-pl-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-pl/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-pt-rBR-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-pt-rBR/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-pt-rPT-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-pt-rPT/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-pt-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-pt/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-ro-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-ro/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-ru-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-ru/strings.xml10
-rw-r--r--SafetyCenter/Resources/res/values-si-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-si/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-sk-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-sk/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-sl-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-sl/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-sq-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-sq/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-sr-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-sr/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-sv-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-sv/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-sw-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-sw/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-ta-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-ta/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-te-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-te/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-th-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-th/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-tl-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-tl/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-tr-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-tr/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-uk-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-uk/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-ur-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-ur/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-uz-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-uz/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-v34/config.xml23
-rw-r--r--SafetyCenter/Resources/res/values-v34/strings.xml39
-rw-r--r--SafetyCenter/Resources/res/values-vi-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-vi/strings.xml10
-rw-r--r--SafetyCenter/Resources/res/values-zh-rCN-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-zh-rCN/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-zh-rHK-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-zh-rHK/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-zh-rTW-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-zh-rTW/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values-zu-v34/strings.xml32
-rw-r--r--SafetyCenter/Resources/res/values-zu/strings.xml8
-rw-r--r--SafetyCenter/Resources/res/values/config.xml25
-rw-r--r--SafetyCenter/Resources/res/values/strings.xml8
-rw-r--r--SafetyCenter/Resources/shared_res/drawable-v33/ic_notification_badge_critical.xml18
-rw-r--r--SafetyCenter/Resources/shared_res/drawable-v33/ic_notification_badge_general.xml9
-rw-r--r--SafetyCenter/Resources/shared_res/values-af/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-am/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-ar/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-as/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-az/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-b+sr+Latn/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-be/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-bg/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-bn/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-bs/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-ca/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-cs/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-da/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-de/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-el/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-en-rAU/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-en-rCA/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-en-rGB/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-en-rIN/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-en-rXC/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-es-rUS/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-es/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-et/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-eu/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-fa/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-fi/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-fr-rCA/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-fr/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-gl/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-gu/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-hi/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-hr/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-hu/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-hy/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-in/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-is/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-it/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-iw/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-ja/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-ka/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-kk/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-km/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-kn/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-ko/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-ky/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-lo/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-lt/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-lv/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-mk/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-ml/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-mn/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-mr/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-ms/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-my/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-nb/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-ne/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-night/colors.xml20
-rw-r--r--SafetyCenter/Resources/shared_res/values-nl/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-or/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-pa/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-pl/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-pt-rBR/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-pt-rPT/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-pt/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-ro/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-ru/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-si/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-sk/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-sl/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-sq/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-sr/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-sv/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-sw/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-ta/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-te/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-th/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-tl/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-tr/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-uk/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-ur/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-uz/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-vi/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-zh-rCN/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-zh-rHK/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-zh-rTW/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values-zu/strings.xml51
-rw-r--r--SafetyCenter/Resources/shared_res/values/colors.xml20
-rw-r--r--SafetyCenter/Resources/shared_res/values/strings.xml127
-rw-r--r--SafetyCenter/ResourcesLib/Android.bp9
-rw-r--r--SafetyCenter/ResourcesLib/TEST_MAPPING7
-rw-r--r--SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/SafetyCenterResourcesContext.java244
-rw-r--r--SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/package-info.java19
-rw-r--r--SafetyCenter/ResourcesLib/tests/Android.bp3
-rw-r--r--SafetyCenter/ResourcesLib/tests/AndroidManifest.xml2
-rw-r--r--SafetyCenter/ResourcesLib/tests/AndroidTest.xml6
-rw-r--r--SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/drawable/valid_drawable.xml25
-rw-r--r--SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/values/colors.xml19
-rw-r--r--SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/values/strings.xml22
-rw-r--r--SafetyCenter/ResourcesLib/tests/java/com/android/safetycenter/resources/SafetyCenterResourcesContextTest.kt231
-rw-r--r--SafetyCenter/TEST_MAPPING13
-rw-r--r--SafetyLabel/Android.bp49
-rw-r--r--SafetyLabel/TEST_MAPPING7
-rw-r--r--SafetyLabel/java/com/android/permission/safetylabel/DataCategory.java100
-rw-r--r--SafetyLabel/java/com/android/permission/safetylabel/DataCategoryConstants.java101
-rw-r--r--SafetyLabel/java/com/android/permission/safetylabel/DataLabel.java83
-rw-r--r--SafetyLabel/java/com/android/permission/safetylabel/DataLabelConstants.java42
-rw-r--r--SafetyLabel/java/com/android/permission/safetylabel/DataPurposeConstants.java79
-rw-r--r--SafetyLabel/java/com/android/permission/safetylabel/DataType.java154
-rw-r--r--SafetyLabel/java/com/android/permission/safetylabel/DataTypeConstants.java421
-rw-r--r--SafetyLabel/java/com/android/permission/safetylabel/SafetyLabel.java77
-rw-r--r--SafetyLabel/tests/Android.bp38
-rw-r--r--SafetyLabel/tests/AndroidManifest.xml30
-rw-r--r--SafetyLabel/tests/AndroidTest.xml40
-rw-r--r--SafetyLabel/tests/java/com/android/permission/safetylabel/DataCategoryTest.kt261
-rw-r--r--SafetyLabel/tests/java/com/android/permission/safetylabel/DataLabelTest.kt126
-rw-r--r--SafetyLabel/tests/java/com/android/permission/safetylabel/DataTypeTest.kt280
-rw-r--r--SafetyLabel/tests/java/com/android/permission/safetylabel/SafetyLabelTest.kt129
-rw-r--r--SafetyLabel/tests/java/com/android/permission/safetylabel/SafetyLabelTestPersistableBundles.kt353
-rw-r--r--framework-s/Android.bp10
-rw-r--r--framework-s/api/current.txt1
-rw-r--r--framework-s/api/system-current.txt128
-rw-r--r--framework-s/jarjar-rules.txt4
-rw-r--r--framework-s/java/android/app/role/IRoleManager.aidl5
-rw-r--r--framework-s/java/android/app/role/RoleManager.java96
-rw-r--r--framework-s/java/android/app/role/TEST_MAPPING19
-rw-r--r--framework-s/java/android/safetycenter/ISafetyCenterManager.aidl13
-rw-r--r--framework-s/java/android/safetycenter/SafetyCenterData.java371
-rw-r--r--framework-s/java/android/safetycenter/SafetyCenterEntry.java10
-rw-r--r--framework-s/java/android/safetycenter/SafetyCenterEntryGroup.java16
-rw-r--r--framework-s/java/android/safetycenter/SafetyCenterIssue.java347
-rw-r--r--framework-s/java/android/safetycenter/SafetyCenterManager.java69
-rw-r--r--framework-s/java/android/safetycenter/SafetyCenterStatus.java4
-rw-r--r--framework-s/java/android/safetycenter/SafetyEvent.java40
-rw-r--r--framework-s/java/android/safetycenter/SafetySourceData.java125
-rw-r--r--framework-s/java/android/safetycenter/SafetySourceIssue.java893
-rw-r--r--framework-s/java/android/safetycenter/SafetySourceStatus.java26
-rw-r--r--framework-s/java/android/safetycenter/TEST_MAPPING4
-rw-r--r--framework-s/java/android/safetycenter/config/BuilderUtils.java54
-rw-r--r--framework-s/java/android/safetycenter/config/SafetyCenterConfig.java21
-rw-r--r--framework-s/java/android/safetycenter/config/SafetySource.java339
-rw-r--r--framework-s/java/android/safetycenter/config/SafetySourcesGroup.java173
-rw-r--r--framework-s/java/android/safetycenter/config/safety_center_config-v34.xsd217
-rw-r--r--framework-s/java/android/safetycenter/config/safety_center_config.xsd47
-rw-r--r--framework-s/java/android/safetylabel/SafetyLabelConstants.java63
-rw-r--r--framework-s/lint-baseline.xml37
-rw-r--r--jarjar-rules.txt6
-rw-r--r--ktfmt_includes.txt2
-rw-r--r--permissions/com.android.permissioncontroller.xml2
-rw-r--r--service/Android.bp65
-rw-r--r--service/jarjar-rules.txt14
-rw-r--r--service/java/com/android/permission/compat/UserHandleCompat.java11
-rw-r--r--service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java74
-rw-r--r--service/java/com/android/permission/util/PackageUtils.java48
-rw-r--r--service/java/com/android/permission/util/PermissionUtils.java56
-rw-r--r--service/java/com/android/permission/util/UserUtils.java109
-rw-r--r--service/java/com/android/role/RoleService.java117
-rw-r--r--service/java/com/android/role/RoleShellCommand.java15
-rw-r--r--service/java/com/android/role/TEST_MAPPING21
-rw-r--r--service/java/com/android/role/persistence/RolesPersistenceImpl.java71
-rw-r--r--service/java/com/android/safetycenter/ApiLock.java35
-rw-r--r--service/java/com/android/safetycenter/DevicePolicyResources.java85
-rw-r--r--service/java/com/android/safetycenter/PendingIntentFactory.java246
-rw-r--r--service/java/com/android/safetycenter/RefreshReasons.java106
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterBroadcastDispatcher.java405
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterConfigReader.java537
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterDataChangeNotifier.java70
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterDataFactory.java1347
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterDataTracker.java707
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterFlags.java576
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterListeners.java281
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterRefreshManager.java184
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterRefreshTracker.java536
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterService.java1086
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterShellCommandHandler.java211
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterTimeouts.java89
-rw-r--r--service/java/com/android/safetycenter/SafetySourceIssueInfo.java113
-rw-r--r--service/java/com/android/safetycenter/SafetySourceKey.java79
-rw-r--r--service/java/com/android/safetycenter/SafetySources.java114
-rw-r--r--service/java/com/android/safetycenter/SafetySourcesGroups.java49
-rw-r--r--service/java/com/android/safetycenter/TEST_MAPPING4
-rw-r--r--service/java/com/android/safetycenter/UserProfileGroup.java297
-rw-r--r--service/java/com/android/safetycenter/data/AndroidLockScreenFix.java261
-rw-r--r--service/java/com/android/safetycenter/data/SafetyCenterDataManager.java536
-rw-r--r--service/java/com/android/safetycenter/data/SafetyCenterInFlightIssueActionRepository.java170
-rw-r--r--service/java/com/android/safetycenter/data/SafetyCenterIssueDeduplicator.java448
-rw-r--r--service/java/com/android/safetycenter/data/SafetyCenterIssueDismissalRepository.java610
-rw-r--r--service/java/com/android/safetycenter/data/SafetyCenterIssueRepository.java310
-rw-r--r--service/java/com/android/safetycenter/data/SafetySourceDataRepository.java354
-rw-r--r--service/java/com/android/safetycenter/data/SafetySourceDataValidator.java224
-rw-r--r--service/java/com/android/safetycenter/data/SafetySourceStateCollectedLogger.java170
-rw-r--r--service/java/com/android/safetycenter/data/package-info.java19
-rw-r--r--service/java/com/android/safetycenter/logging/SafetyCenterPullAtomCallback.java180
-rw-r--r--service/java/com/android/safetycenter/logging/SafetyCenterStatsdLogger.java485
-rw-r--r--service/java/com/android/safetycenter/logging/package-info.java19
-rw-r--r--service/java/com/android/safetycenter/notifications/SafetyCenterNotificationChannels.java205
-rw-r--r--service/java/com/android/safetycenter/notifications/SafetyCenterNotificationFactory.java262
-rw-r--r--service/java/com/android/safetycenter/notifications/SafetyCenterNotificationReceiver.java255
-rw-r--r--service/java/com/android/safetycenter/notifications/SafetyCenterNotificationSender.java463
-rw-r--r--service/java/com/android/safetycenter/notifications/package-info.java19
-rw-r--r--service/java/com/android/safetycenter/package-info.java (renamed from service/java/com/android/access/package-info.java)11
-rw-r--r--service/lint-baseline.xml26
-rw-r--r--tests/apex/AndroidTest.xml2
-rw-r--r--tests/apex/java/com/android/permission/persistence/RuntimePermissionsPersistenceTest.kt64
-rw-r--r--tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt41
-rw-r--r--tests/cts/safetycenter/Android.bp8
-rw-r--r--tests/cts/safetycenter/AndroidManifest.xml11
-rw-r--r--tests/cts/safetycenter/AndroidTest.xml21
-rw-r--r--tests/cts/safetycenter/TEST_MAPPING10
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterActivityTest.kt85
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterDataTest.kt585
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryGroupTest.kt51
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryOrGroupTest.kt10
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryTest.kt138
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterErrorDetailsTest.kt13
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterIssueTest.kt542
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt2404
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterShellCommandsTest.kt59
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryGroupTest.kt42
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryTest.kt44
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStatusTest.kt50
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt438
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt69
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceDataTest.kt278
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceErrorDetailsTest.kt18
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceIssueTest.kt1589
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceStatusTest.kt113
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetyCenterConfigTest.kt82
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt384
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourcesGroupTest.kt476
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/config/XmlConfigTest.kt68
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/testing/Coroutines.kt37
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/testing/EqualsHashCodeToStringTester.kt94
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/testing/FakeExecutor.kt7
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetyCenterFlags.kt52
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetySourceBroadcastReceiver.kt88
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/ui/SafetyCenterActivityTest.kt90
-rw-r--r--tests/functional/safetycenter/OWNERS3
-rw-r--r--tests/functional/safetycenter/multiusers/Android.bp43
-rw-r--r--tests/functional/safetycenter/multiusers/AndroidManifest.xml29
-rw-r--r--tests/functional/safetycenter/multiusers/AndroidTest.xml56
-rw-r--r--tests/functional/safetycenter/multiusers/TEST_MAPPING30
-rw-r--r--tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt1310
-rw-r--r--tests/functional/safetycenter/safetycenteractivity/Android.bp43
-rw-r--r--tests/functional/safetycenter/safetycenteractivity/AndroidManifest.xml29
-rw-r--r--tests/functional/safetycenter/safetycenteractivity/AndroidTest.xml61
-rw-r--r--tests/functional/safetycenter/safetycenteractivity/TEST_MAPPING17
-rw-r--r--tests/functional/safetycenter/safetycenteractivity/src/android/safetycenter/functional/ui/SafetyCenterActivityTest.kt1496
-rw-r--r--tests/functional/safetycenter/singleuser/Android.bp45
-rw-r--r--tests/functional/safetycenter/singleuser/AndroidManifest.xml37
-rw-r--r--tests/functional/safetycenter/singleuser/AndroidTest.xml61
-rw-r--r--tests/functional/safetycenter/singleuser/TEST_MAPPING17
-rw-r--r--tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterManagerTest.kt3674
-rw-r--r--tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterNotificationTest.kt995
-rw-r--r--tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/NotificationCharacteristics.kt71
-rw-r--r--tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/StatusBarNotificationWithChannel.kt26
-rw-r--r--tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/TestNotificationListener.kt353
-rw-r--r--tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/PrivacySubpageTest.kt222
-rw-r--r--tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterQsActivityTest.kt158
-rw-r--r--tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterStatusCardTest.kt273
-rw-r--r--tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterSubpagesTest.kt1026
-rw-r--r--tests/hostside/safetycenter/Android.bp39
-rw-r--r--tests/hostside/safetycenter/AndroidTest.xml41
-rw-r--r--tests/hostside/safetycenter/OWNERS3
-rw-r--r--tests/hostside/safetycenter/TEST_MAPPING12
-rw-r--r--tests/hostside/safetycenter/helper-app/Android.bp35
-rw-r--r--tests/hostside/safetycenter/helper-app/AndroidManifest.xml26
-rw-r--r--tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterInteractionLoggingHelperTests.kt105
-rw-r--r--tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterNotificationLoggingHelperTests.kt80
-rw-r--r--tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetySourceStateCollectedLoggingHelperTests.kt161
-rw-r--r--tests/hostside/safetycenter/src/android/safetycenter/hostside/HelperApp.kt23
-rw-r--r--tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt148
-rw-r--r--tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterSystemEventReportedLoggingHostTest.kt204
-rw-r--r--tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetySourceStateCollectedLoggingHostTest.kt140
-rw-r--r--tests/hostside/safetycenter/src/android/safetycenter/hostside/rules/HelperAppRule.kt57
-rw-r--r--tests/hostside/safetycenter/src/android/safetycenter/hostside/rules/RequireSafetyCenterRule.kt58
-rw-r--r--tests/utils/safetycenter/Android.bp48
-rw-r--r--tests/utils/safetycenter/AndroidManifest.xml58
-rw-r--r--tests/utils/safetycenter/OWNERS3
-rw-r--r--tests/utils/safetycenter/TEST_MAPPING7
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/Coroutines.kt103
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/EqualsHashCodeToStringTester.kt172
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterActivityLauncher.kt122
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterApisWithShellPermissions.kt (renamed from tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetyCenterApisWithShellPermissions.kt)72
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterEnabledChangedReceiver.kt87
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt562
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt1037
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestData.kt558
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestHelper.kt191
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestListener.kt64
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceIntentHandler.kt318
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceReceiver.kt255
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceTestData.kt838
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SettingsPackage.kt (renamed from tests/cts/safetycenter/src/android/safetycenter/cts/testing/SettingsPackage.kt)26
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/ShellPermissions.kt73
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/TestActivity.kt35
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/UiTestHelper.kt255
-rw-r--r--tests/utils/safetycenter/res/layout/test_activity.xml31
1474 files changed, 126177 insertions, 12831 deletions
diff --git a/Android.bp b/Android.bp
index b22b21451..4a436da6c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -14,6 +14,7 @@
package {
default_applicable_licenses: ["Android-Apache-2.0"],
+ default_visibility: [":__subpackages__"],
}
apex {
@@ -53,11 +54,6 @@ android_app_certificate {
certificate: "com.android.permission",
}
-filegroup {
- name: "permission-jarjar-rules",
- srcs: ["jarjar-rules.txt"],
-}
-
sdk {
name: "permission-module-sdk",
apexes: [
@@ -109,8 +105,9 @@ bootclasspath_fragment {
// result in a build failure due to inconsistent flags.
package_prefixes: [
"android.app.role",
+ "android.permission.jarjar",
"android.safetycenter",
- "com.android.permission",
+ "android.safetylabel",
],
},
}
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index fc93cc505..925bbf9d7 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -4,4 +4,5 @@ commit_msg_changeid_field = true
[Hook Scripts]
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
-ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py -f ${PREUPLOAD_FILES}
+ktfmt_hook = ${REPO_ROOT}/external/ktfmt/ktfmt.py --check -i ${REPO_ROOT}/packages/modules/Permission/ktfmt_includes.txt ${PREUPLOAD_FILES}
+ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py --no-verify-format -f ${PREUPLOAD_FILES}
diff --git a/PermissionController/Android.bp b/PermissionController/Android.bp
index 74a47f288..cd0ceab01 100644
--- a/PermissionController/Android.bp
+++ b/PermissionController/Android.bp
@@ -78,7 +78,6 @@ android_app {
// artifact. See also b/209458854.
sdk_version: "system_current",
min_sdk_version: "30",
- target_sdk_version: "32",
updatable: true,
privileged: true,
certificate: "platform",
@@ -99,10 +98,11 @@ android_app {
// Soong fails to automatically add this dependency because all the
// *.kt sources are inside a filegroup.
"kotlin-annotations",
+ "safety-center-annotations",
],
static_libs: [
- "iconloader",
+ "iconloader_sc_mainline_prod",
"com.google.android.material_material",
"androidx.transition_transition",
"androidx-constraintlayout_constraintlayout",
@@ -134,20 +134,29 @@ android_app {
"SettingsLibActionBarShadow",
"SettingsLibProgressBar",
"SettingsLibCollapsingToolbarBaseActivity",
+ "SettingsLibActivityEmbedding",
"SettingsLibSettingsTheme",
"SettingsLibFooterPreference",
"SettingsLibSelectorWithWidgetPreference",
"SettingsLibTwoTargetPreference",
+ "SettingsLibIllustrationPreference",
"androidx.annotation_annotation",
"permissioncontroller-statsd",
"car-ui-lib",
"libprotobuf-java-lite",
+ "safety-center-internal-data",
+ "safety-center-pending-intents",
"SettingsLibUtils",
"modules-utils-build_system",
+ "safety-center-resources-lib",
+ "lottie",
+ "safety-label",
+ "role-controller",
],
proto: {
type: "lite",
+ include_dirs: ["packages/modules/Permission/PermissionController/src/com/android/permissioncontroller"],
},
lint: {
diff --git a/PermissionController/AndroidManifest.xml b/PermissionController/AndroidManifest.xml
index e3490b105..874ba35d6 100644
--- a/PermissionController/AndroidManifest.xml
+++ b/PermissionController/AndroidManifest.xml
@@ -61,7 +61,11 @@
<uses-permission android:name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
<!--SYSTEM_APPLICATION_OVERLAY will be granted on T+, as installer protection is added in T -->
<uses-permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY"/>
+ <uses-permission android:name="android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK" />
<uses-permission android:name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS"/>
+ <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" />
<application android:name="com.android.permissioncontroller.PermissionControllerApplication"
android:label="@string/app_name"
@@ -78,20 +82,43 @@
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
+ <action android:name="com.android.permissioncontroller.action.SET_UP_LOCATION_ACCESS_CHECK" />
</intent-filter>
</receiver>
- <receiver android:name="com.android.permissioncontroller.hibernation.HibernationOnBootReceiver"
+ <receiver
+ android:name="com.android.permissioncontroller.privacysources.SetupPeriodicNotificationListenerCheck"
+ android:enabled="@bool/is_at_least_t"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.BOOT_COMPLETED" />
+ <action android:name="com.android.permissioncontroller.action.SET_UP_NOTIFICATION_LISTENER_CHECK" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.permissioncontroller.hibernation.HibernationBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
+ <action android:name="com.android.permissioncontroller.action.SET_UP_HIBERNATION" />
+ <action android:name="android.intent.action.TIME_SET" />
+ <action android:name="android.intent.action.TIMEZONE_CHANGED" />
</intent-filter>
</receiver>
+ <receiver android:name="com.android.permissioncontroller.hibernation.DismissHandler"
+ android:enabled="@bool/is_at_least_t"/>
+
<receiver android:name="com.android.permissioncontroller.permission.service.LocationAccessCheck$NotificationDeleteHandler" />
<receiver android:name="com.android.permissioncontroller.permission.service.LocationAccessCheck$NotificationClickHandler" />
+ <receiver android:name="com.android.permissioncontroller.permission.service.LocationAccessCheck$SafetyCenterPrimaryActionHandler"
+ android:enabled="@bool/is_at_least_t" />
+
+ <receiver android:name="com.android.permissioncontroller.permission.service.LocationAccessCheck$WarningCardDismissalHandler"
+ android:enabled="@bool/is_at_least_t"/>
+
<receiver android:name="com.android.permissioncontroller.permission.service.LocationAccessCheck$PackageResetHandler"
android:exported="true">
<intent-filter>
@@ -101,8 +128,33 @@
</intent-filter>
</receiver>
- <receiver android:name="com.android.permissioncontroller.privacysources.SafetyCenterReceiver"
- android:exported="true">
+ <receiver
+ android:name="com.android.permissioncontroller.privacysources.NotificationListenerCheckNotificationDeleteHandler"
+ android:enabled="@bool/is_at_least_t" />
+
+ <receiver
+ android:name="com.android.permissioncontroller.privacysources.DisableNotificationListenerComponentHandler"
+ android:enabled="@bool/is_at_least_t" />
+
+ <receiver
+ android:name="com.android.permissioncontroller.privacysources.NotificationListenerActionCardDismissalReceiver"
+ android:enabled="@bool/is_at_least_t" />
+
+ <receiver
+ android:name="com.android.permissioncontroller.privacysources.NotificationListenerPackageResetHandler"
+ android:enabled="@bool/is_at_least_t"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED"/>
+ <action android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
+ <data android:scheme="package" />
+ </intent-filter>
+ </receiver>
+
+ <receiver
+ android:name="com.android.permissioncontroller.privacysources.SafetyCenterReceiver"
+ android:enabled="@bool/is_at_least_t"
+ android:exported="true">
<intent-filter>
<action android:name="android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED"/>
<action android:name="android.safetycenter.action.REFRESH_SAFETY_SOURCES"/>
@@ -110,21 +162,112 @@
</intent-filter>
</receiver>
-
<service android:name="com.android.permissioncontroller.permission.service.LocationAccessCheck$LocationAccessCheckJobService"
android:permission="android.permission.BIND_JOB_SERVICE" />
+ <service
+ android:name="com.android.permissioncontroller.privacysources.NotificationListenerCheckJobService"
+ android:enabled="@bool/is_at_least_t"
+ android:permission="android.permission.BIND_JOB_SERVICE" />
+
<service android:name="com.android.permissioncontroller.hibernation.HibernationJobService"
android:permission="android.permission.BIND_JOB_SERVICE" />
- <service android:name="com.android.permissioncontroller.permission.service.v33.PermissionEventCleanupJobService"
+ <service android:name="com.android.permissioncontroller.permission.service.PermissionEventCleanupJobService"
android:permission="android.permission.BIND_JOB_SERVICE" />
+ <service
+ android:name="com.android.permissioncontroller.safetycenter.service.SafetyCenterBackgroundRefreshJobService"
+ android:enabled="@bool/is_at_least_t"
+ android:permission="android.permission.BIND_JOB_SERVICE"
+ android:exported="false" />
+
+ <receiver
+ android:name="com.android.permissioncontroller.safetycenter.service.SafetyCenterBackgroundRefreshJobService$SetupSafetyCenterBackgroundRefreshReceiver"
+ android:enabled="@bool/is_at_least_t"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED"/>
+ <action android:name="android.intent.action.BOOT_COMPLETED" />
+ </intent-filter>
+ </receiver>
+
+ <service
+ android:name="com.android.permissioncontroller.permission.service.v34.SafetyLabelChangesJobService"
+ android:enabled="@bool/is_at_least_u"
+ android:permission="android.permission.BIND_JOB_SERVICE"
+ android:exported="false" />
+
+ <receiver
+ android:name="com.android.permissioncontroller.permission.service.v34.SafetyLabelChangesJobService$Receiver"
+ android:enabled="@bool/is_at_least_u"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.BOOT_COMPLETED" />
+ <action android:name="com.android.permissioncontroller.action.SET_UP_SAFETY_LABEL_CHANGES_JOB" />
+ </intent-filter>
+ </receiver>
+
+ <receiver
+ android:name="com.android.permissioncontroller.permission.service.v34.SafetyLabelChangesJobService$NotificationDeleteHandler"
+ android:enabled="@bool/is_at_least_u">
+ </receiver>
+
+ <receiver
+ android:name="com.android.permissioncontroller.privacysources.AccessibilityOnBootReceiver"
+ android:enabled="@bool/is_at_least_t"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.BOOT_COMPLETED" />
+ <action android:name="com.android.permissioncontroller.action.SET_UP_ACCESSIBILITY_CHECK" />
+ </intent-filter>
+ </receiver>
+
+ <receiver
+ android:name="com.android.permissioncontroller.privacysources.AccessibilityWarningCardDismissalReceiver"
+ android:enabled="@bool/is_at_least_t" />
+
+ <receiver
+ android:name="com.android.permissioncontroller.privacysources.AccessibilityRemoveAccessHandler"
+ android:enabled="@bool/is_at_least_t" />
+
+ <receiver
+ android:name="com.android.permissioncontroller.privacysources.AccessibilityNotificationDeleteHandler"
+ android:enabled="@bool/is_at_least_t" />
+
+ <receiver
+ android:name="com.android.permissioncontroller.privacysources.AccessibilityPackageResetHandler"
+ android:enabled="@bool/is_at_least_t"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
+ <action android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
+ <data android:scheme="package" />
+ </intent-filter>
+ </receiver>
+
+ <receiver
+ android:name="com.android.permissioncontroller.safetylabel.SafetyLabelChangedBroadcastReceiver"
+ android:enabled="@bool/is_at_least_u"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.PACKAGE_ADDED" />
+ <action android:name="com.android.permissioncontroller.action.PACKAGE_ADDED_PERMISSIONCONTROLLER_FORWARDED" />
+ <data android:scheme="package" />
+ </intent-filter>
+ </receiver>
+
+ <service
+ android:name="com.android.permissioncontroller.privacysources.AccessibilityJobService"
+ android:enabled="@bool/is_at_least_t"
+ android:permission="android.permission.BIND_JOB_SERVICE" />
+
<activity android:name="com.android.permissioncontroller.permission.ui.GrantPermissionsActivity"
android:configChanges="keyboardHidden|screenSize"
android:excludeFromRecents="true"
android:exported="true"
android:theme="@style/GrantPermissions.FilterTouches"
+ android:windowSoftInputMode="stateAlwaysHidden|adjustNothing"
android:visibleToInstantApps="true"
android:inheritShowWhenLocked="true"
android:hardwareAccelerated="false"
@@ -139,6 +282,18 @@
</intent-filter>
</activity>
+ <activity android:name="com.android.permissioncontroller.permission.ui.v34.PermissionRationaleActivity"
+ android:configChanges="keyboardHidden|screenSize"
+ android:windowSoftInputMode="stateAlwaysHidden|adjustNothing"
+ android:excludeFromRecents="true"
+ android:exported="false"
+ android:theme="@style/GrantPermissions.FilterTouches"
+ android:visibleToInstantApps="true"
+ android:inheritShowWhenLocked="true"
+ android:hardwareAccelerated="false"
+ android:canDisplayOnRemoteDevices="false">
+ </activity>
+
<activity android:name="com.android.permissioncontroller.permission.ui.ManagePermissionsActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/app_permissions"
@@ -153,10 +308,23 @@
<action android:name="android.intent.action.REVIEW_PERMISSION_USAGE" />
<action android:name="android.intent.action.REVIEW_PERMISSION_HISTORY" />
<action android:name="android.intent.action.MANAGE_UNUSED_APPS" />
+ <action android:name="android.intent.action.REVIEW_APP_DATA_SHARING_UPDATES" />
<action android:name="android.permission.action.REVIEW_PERMISSION_DECISIONS"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
+ <activity-alias android:name="com.android.permissioncontroller.permission.ui.ManagePermissionsActivityAlias"
+ android:configChanges="orientation|keyboardHidden|screenSize"
+ android:label="@string/app_permissions"
+ android:exported="true"
+ android:theme="@style/Theme.PermissionController.Settings.FilterTouches"
+ android:permission="android.permission.LAUNCH_PERMISSION_SETTINGS"
+ android:targetActivity="com.android.permissioncontroller.permission.ui.ManagePermissionsActivity">
+ <intent-filter android:priority="1">
+ <action android:name="android.settings.APP_PERMISSIONS_SETTINGS"/>
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity-alias>
<activity android:name="com.android.permissioncontroller.permission.ui.ManagePermissionsActivityTrampoline"
android:excludeFromRecents="true"
@@ -188,10 +356,11 @@
</intent-filter>
</activity>
- <activity android:name="com.android.permissioncontroller.permission.ui.SafetyCenterQsActivity"
+ <activity android:name="com.android.permissioncontroller.safetycenter.ui.SafetyCenterQsActivity"
android:excludeFromRecents="true"
+ android:launchMode="singleInstance"
android:exported="true"
- android:theme="@style/SafetyCenter"
+ android:theme="@style/Theme.SafetyCenterQs"
android:permission="android.permission.REVOKE_RUNTIME_PERMISSIONS">
<intent-filter android:priority="1">
<action android:name="android.intent.action.VIEW_SAFETY_CENTER_QS" />
@@ -199,11 +368,6 @@
</intent-filter>
</activity>
- <activity android:name="com.android.permissioncontroller.permission.ui.OverlayWarningDialog"
- android:excludeFromRecents="true"
- android:exported="false"
- android:theme="@style/Theme.AppCompat.DayNight.Dialog.Alert" />
-
<activity android:name="com.android.permissioncontroller.permission.ui.LocationProviderInterceptDialog"
android:excludeFromRecents="true"
android:exported="false"
@@ -225,7 +389,7 @@
android:excludeFromRecents="true"
android:exported="true"
android:theme="@style/PermissionDialog.FilterTouches"
- android:permission="android.permission.REVIEW_ACCESSIBILITY_SERVICES" >
+ android:permission="android.permission.GRANT_RUNTIME_PERMISSIONS" >
<intent-filter android:priority="1">
<action android:name="android.intent.action.REVIEW_ACCESSIBILITY_SERVICES" />
<category android:name="android.intent.category.DEFAULT" />
@@ -329,6 +493,18 @@
</intent-filter>
</provider>
+ <provider android:name="com.android.permissioncontroller.safetycenter.service.SafetyCenterSearchIndexablesProvider"
+ android:authorities="com.android.permissioncontroller.safetycenter"
+ android:enabled="@bool/is_at_least_t"
+ android:multiprocess="false"
+ android:exported="true"
+ android:grantUriPermissions="true"
+ android:permission="android.permission.READ_SEARCH_INDEXABLES">
+ <intent-filter>
+ <action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER" />
+ </intent-filter>
+ </provider>
+
<service android:name="com.android.permissioncontroller.permission.service.PermissionControllerServiceImpl"
android:exported="true"
android:visibleToInstantApps="true">
@@ -352,6 +528,18 @@
</intent-filter>
</service>
+ <service
+ android:name="com.android.permissioncontroller.permission.service.v33.SafetyCenterQsTileService"
+ android:enabled="@bool/is_at_least_t"
+ android:exported="true"
+ android:label="@string/safety_privacy_qs_tile_title"
+ android:icon ="@drawable/ic_safety_center_shield"
+ android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
+ <intent-filter>
+ <action android:name="android.service.quicksettings.action.QS_TILE" />
+ </intent-filter>
+ </service>
+
<service android:name="com.android.permissioncontroller.auto.DrivingDecisionReminderService" />
<receiver android:name="com.android.permissioncontroller.role.service.ClearUserDeniedReceiver"
@@ -363,7 +551,7 @@
</intent-filter>
</receiver>
- <receiver android:name="com.android.permissioncontroller.permission.service.v33.PersistedStoragePackageUninstalledReceiver"
+ <receiver android:name="com.android.permissioncontroller.permission.service.PersistedStoragePackageUninstalledReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
@@ -372,7 +560,7 @@
</intent-filter>
</receiver>
- <receiver android:name="com.android.permissioncontroller.permission.service.v33.PermissionStorageTimeChangeReceiver"
+ <receiver android:name="com.android.permissioncontroller.permission.service.PermissionStorageTimeChangeReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
@@ -389,9 +577,10 @@
</receiver>
<activity android:name="com.android.permissioncontroller.incident.ConfirmationActivity"
- android:theme="@style/Theme.DeviceDefault.Dialog.Alert.DayNight"
+ android:theme="@style/Theme.DeviceDefault.Dialog.NoActionBar.DayNight"
android:exported="false"
android:excludeFromRecents="true"
+ android:finishOnCloseSystemDialogs="true"
android:noHistory="true" />
<receiver android:name="com.android.permissioncontroller.incident.ApprovalReceiver"
@@ -402,14 +591,23 @@
<activity
android:name="com.android.permissioncontroller.safetycenter.ui.SafetyCenterActivity"
+ android:enabled="@bool/is_at_least_t"
android:exported="true"
- android:theme="@style/Theme.PermissionController.Settings.FilterTouches">
+ android:theme="@style/Theme.SafetyCenter">
<intent-filter android:priority="1">
<action android:name="android.intent.action.SAFETY_CENTER"/>
+ <action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
+ <!-- Higher priority than the settings version of controls, so this should handle it -->
+ <intent-filter android:priority="100">
+ <action android:name="android.settings.PRIVACY_CONTROLS"/>
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
</activity>
+ <!-- Unexported empty activity for in-process tests -->
+ <activity android:name="android.app.Activity" />
</application>
</manifest>
diff --git a/PermissionController/OWNERS b/PermissionController/OWNERS
index 8f3889b9d..66cd836f2 100644
--- a/PermissionController/OWNERS
+++ b/PermissionController/OWNERS
@@ -1,8 +1,5 @@
include platform/frameworks/base:/core/java/android/permission/OWNERS
-toddke@google.com
-patb@google.com
-
# For automotive related changes
stenning@google.com
@@ -13,6 +10,9 @@ robhor@google.com
# For incident report related changes
joeo@google.com
+# for SafetyCenter UI changes
+per-file res/** = file:platform/packages/modules/Permission:/SafetyCenter/OWNERS
+
# For Wear related changes
per-file WEAR_OWNERS = file:/PermissionController/WEAR_OWNERS
per-file src/com/android/permissioncontroller/permission/ui/wear/** = file:/PermissionController/WEAR_OWNERS
diff --git a/PermissionController/TEST_MAPPING b/PermissionController/TEST_MAPPING
index 0911e0d91..0ae3818fd 100644
--- a/PermissionController/TEST_MAPPING
+++ b/PermissionController/TEST_MAPPING
@@ -11,6 +11,74 @@
}
],
"file_patterns": ["res/xml/roles\\.xml"]
+ },
+ {
+ "name": "PermissionUiTestCases",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ }
+ ]
+ }
+ ],
+ "presubmit-large": [
+ {
+ "name": "CtsPermission3TestCases",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.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"
+ }
+ ],
+ "file_patterns": ["res/xml/roles\\.xml"]
+ },
+ {
+ "name": "PermissionUiTestCases[com.google.android.permission.apex]",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ },
+ // 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": "CtsPermission3TestCases[com.google.android.permission.apex]",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ }
+ ]
}
],
"imports": [
diff --git a/PermissionController/iconloaderlib/.gitignore b/PermissionController/iconloaderlib/.gitignore
new file mode 100644
index 000000000..6213826ab
--- /dev/null
+++ b/PermissionController/iconloaderlib/.gitignore
@@ -0,0 +1,13 @@
+*.iml
+.project
+.classpath
+.project.properties
+gen/
+bin/
+.idea/
+.gradle/
+local.properties
+gradle/
+build/
+gradlew*
+.DS_Store
diff --git a/PermissionController/iconloaderlib/Android.bp b/PermissionController/iconloaderlib/Android.bp
new file mode 100644
index 000000000..2bc3de435
--- /dev/null
+++ b/PermissionController/iconloaderlib/Android.bp
@@ -0,0 +1,52 @@
+// 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_library {
+ name: "iconloader_base_sc_mainline_prod",
+ sdk_version: "current",
+ min_sdk_version: "26",
+ static_libs: [
+ "androidx.core_core",
+ ],
+ resource_dirs: [
+ "res",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+}
+
+android_library {
+ name: "iconloader_sc_mainline_prod",
+ sdk_version: "system_current",
+ min_sdk_version: "26",
+ static_libs: [
+ "androidx.core_core",
+ ],
+ resource_dirs: [
+ "res",
+ ],
+ srcs: [
+ "src/**/*.java",
+ "src_full_lib/**/*.java",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
+}
diff --git a/PermissionController/iconloaderlib/AndroidManifest.xml b/PermissionController/iconloaderlib/AndroidManifest.xml
new file mode 100644
index 000000000..b30258da2
--- /dev/null
+++ b/PermissionController/iconloaderlib/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?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="com.android.launcher3.icons">
+</manifest>
diff --git a/PermissionController/iconloaderlib/build.gradle b/PermissionController/iconloaderlib/build.gradle
new file mode 100644
index 000000000..35ca8dee2
--- /dev/null
+++ b/PermissionController/iconloaderlib/build.gradle
@@ -0,0 +1,38 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion COMPILE_SDK
+ buildToolsVersion BUILD_TOOLS_VERSION
+
+ defaultConfig {
+ minSdkVersion 26
+ targetSdkVersion 28
+ versionCode 1
+ versionName "1.0"
+ }
+
+ sourceSets {
+ main {
+ java.srcDirs = ['src', 'src_full_lib']
+ manifest.srcFile 'AndroidManifest.xml'
+ res.srcDirs = ['res']
+ }
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+
+ tasks.withType(JavaCompile) {
+ options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+ implementation "androidx.core:core"
+}
diff --git a/PermissionController/iconloaderlib/res/drawable-v26/adaptive_icon_drawable_wrapper.xml b/PermissionController/iconloaderlib/res/drawable-v26/adaptive_icon_drawable_wrapper.xml
new file mode 100644
index 000000000..9f13cf571
--- /dev/null
+++ b/PermissionController/iconloaderlib/res/drawable-v26/adaptive_icon_drawable_wrapper.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@color/legacy_icon_background"/>
+ <foreground>
+ <com.android.launcher3.icons.FixedScaleDrawable />
+ </foreground>
+</adaptive-icon>
diff --git a/PermissionController/iconloaderlib/res/drawable/ic_instant_app_badge.xml b/PermissionController/iconloaderlib/res/drawable/ic_instant_app_badge.xml
new file mode 100644
index 000000000..b74317e5f
--- /dev/null
+++ b/PermissionController/iconloaderlib/res/drawable/ic_instant_app_badge.xml
@@ -0,0 +1,39 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/profile_badge_size"
+ android:height="@dimen/profile_badge_size"
+ android:viewportWidth="18"
+ android:viewportHeight="18">
+
+ <path
+ android:fillColor="@android:color/black"
+ android:strokeWidth="1"
+ android:pathData="M 9 0 C 13.9705627485 0 18 4.02943725152 18 9 C 18 13.9705627485 13.9705627485 18 9 18 C 4.02943725152 18 0 13.9705627485 0 9 C 0 4.02943725152 4.02943725152 0 9 0 Z" />
+ <path
+ android:fillColor="@android:color/white"
+ android:strokeWidth="1"
+ android:pathData="M 9 0 C 13.9705627485 0 18 4.02943725152 18 9 C 18 13.9705627485 13.9705627485 18 9 18 C 4.02943725152 18 0 13.9705627485 0 9 C 0 4.02943725152 4.02943725152 0 9 0 Z" />
+ <path
+ android:fillColor="@android:color/white"
+ android:strokeWidth="1"
+ android:pathData="M 9 0 C 13.9705627485 0 18 4.02943725152 18 9 C 18 13.9705627485 13.9705627485 18 9 18 C 4.02943725152 18 0 13.9705627485 0 9 C 0 4.02943725152 4.02943725152 0 9 0 Z" />
+ <path
+ android:fillColor="@android:color/black"
+ android:fillAlpha="0.87"
+ android:strokeWidth="1"
+ android:pathData="M 6 10.4123279 L 8.63934949 10.4123279 L 8.63934949 15.6 L 12.5577168 7.84517705 L 9.94547194 7.84517705 L 9.94547194 2 Z" />
+</vector>
diff --git a/PermissionController/iconloaderlib/res/values/attrs.xml b/PermissionController/iconloaderlib/res/values/attrs.xml
new file mode 100644
index 000000000..8f0bd2c1a
--- /dev/null
+++ b/PermissionController/iconloaderlib/res/values/attrs.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2021, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <attr name="disabledIconAlpha" format="float" />
+ <attr name="loadingIconColor" format="color" />
+
+</resources> \ No newline at end of file
diff --git a/PermissionController/iconloaderlib/res/values/colors.xml b/PermissionController/iconloaderlib/res/values/colors.xml
new file mode 100644
index 000000000..70582c2e2
--- /dev/null
+++ b/PermissionController/iconloaderlib/res/values/colors.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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>
+ <color name="legacy_icon_background">#FFFFFF</color>
+
+ <!-- Yellow 600, used for highlighting "important" conversations in settings & notifications -->
+ <color name="important_conversation">#f9ab00</color>
+</resources>
diff --git a/PermissionController/iconloaderlib/res/values/config.xml b/PermissionController/iconloaderlib/res/values/config.xml
new file mode 100644
index 000000000..893f955c2
--- /dev/null
+++ b/PermissionController/iconloaderlib/res/values/config.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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>
+
+ <!-- Various configurations to control the simple cache implementation -->
+
+ <dimen name="default_icon_bitmap_size">56dp</dimen>
+ <bool name="simple_cache_enable_im_memory">false</bool>
+ <string name="cache_db_name" translatable="false">app_icons.db</string>
+
+ <string name="calendar_component_name" translatable="false"></string>
+ <string name="clock_component_name" translatable="false"></string>
+
+</resources> \ No newline at end of file
diff --git a/PermissionController/iconloaderlib/res/values/dimens.xml b/PermissionController/iconloaderlib/res/values/dimens.xml
new file mode 100644
index 000000000..e8c0c44f7
--- /dev/null
+++ b/PermissionController/iconloaderlib/res/values/dimens.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>
+ <dimen name="profile_badge_size">24dp</dimen>
+</resources>
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
new file mode 100644
index 000000000..9ce997587
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
@@ -0,0 +1,466 @@
+package com.android.launcher3.icons;
+
+import static android.graphics.Paint.DITHER_FLAG;
+import static android.graphics.Paint.FILTER_BITMAP_FLAG;
+
+import static com.android.launcher3.icons.ShadowGenerator.BLUR_FACTOR;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
+import android.os.Build;
+import android.os.Process;
+import android.os.UserHandle;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.icons.BitmapInfo.Extender;
+
+/**
+ * This class will be moved to androidx library. There shouldn't be any dependency outside
+ * this package.
+ */
+public class BaseIconFactory implements AutoCloseable {
+
+ private static final String TAG = "BaseIconFactory";
+ private static final int DEFAULT_WRAPPER_BACKGROUND = Color.WHITE;
+ static final boolean ATLEAST_OREO = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
+ static final boolean ATLEAST_P = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
+
+ private static final float ICON_BADGE_SCALE = 0.444f;
+
+ private final Rect mOldBounds = new Rect();
+ protected final Context mContext;
+ private final Canvas mCanvas;
+ private final PackageManager mPm;
+ private final ColorExtractor mColorExtractor;
+ private boolean mDisableColorExtractor;
+ private boolean mBadgeOnLeft = false;
+
+ protected final int mFillResIconDpi;
+ protected final int mIconBitmapSize;
+
+ private IconNormalizer mNormalizer;
+ private ShadowGenerator mShadowGenerator;
+ private final boolean mShapeDetection;
+
+ private Drawable mWrapperIcon;
+ private int mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;
+ private Bitmap mUserBadgeBitmap;
+
+ private final Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+ private static final float PLACEHOLDER_TEXT_SIZE = 20f;
+ private static int PLACEHOLDER_BACKGROUND_COLOR = Color.rgb(240, 240, 240);
+
+ protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize,
+ boolean shapeDetection) {
+ mContext = context.getApplicationContext();
+ mShapeDetection = shapeDetection;
+ mFillResIconDpi = fillResIconDpi;
+ mIconBitmapSize = iconBitmapSize;
+
+ mPm = mContext.getPackageManager();
+ mColorExtractor = new ColorExtractor();
+
+ mCanvas = new Canvas();
+ mCanvas.setDrawFilter(new PaintFlagsDrawFilter(DITHER_FLAG, FILTER_BITMAP_FLAG));
+ mTextPaint.setTextAlign(Paint.Align.CENTER);
+ mTextPaint.setColor(PLACEHOLDER_BACKGROUND_COLOR);
+ mTextPaint.setTextSize(context.getResources().getDisplayMetrics().density *
+ PLACEHOLDER_TEXT_SIZE);
+ clear();
+ }
+
+ public BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize) {
+ this(context, fillResIconDpi, iconBitmapSize, false);
+ }
+
+ protected void clear() {
+ mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;
+ mDisableColorExtractor = false;
+ mBadgeOnLeft = false;
+ }
+
+ public ShadowGenerator getShadowGenerator() {
+ if (mShadowGenerator == null) {
+ mShadowGenerator = new ShadowGenerator(mIconBitmapSize);
+ }
+ return mShadowGenerator;
+ }
+
+ public IconNormalizer getNormalizer() {
+ if (mNormalizer == null) {
+ mNormalizer = new IconNormalizer(mContext, mIconBitmapSize, mShapeDetection);
+ }
+ return mNormalizer;
+ }
+
+ @SuppressWarnings("deprecation")
+ public BitmapInfo createIconBitmap(Intent.ShortcutIconResource iconRes) {
+ try {
+ Resources resources = mPm.getResourcesForApplication(iconRes.packageName);
+ if (resources != null) {
+ final int id = resources.getIdentifier(iconRes.resourceName, null, null);
+ // do not stamp old legacy shortcuts as the app may have already forgotten about it
+ return createBadgedIconBitmap(
+ resources.getDrawableForDensity(id, mFillResIconDpi),
+ Process.myUserHandle() /* only available on primary user */,
+ false /* do not apply legacy treatment */);
+ }
+ } catch (Exception e) {
+ // Icon not found.
+ }
+ return null;
+ }
+
+ /**
+ * Create a placeholder icon using the passed in text.
+ *
+ * @param placeholder used for foreground element in the icon bitmap
+ * @param color used for the foreground text color
+ * @return
+ */
+ public BitmapInfo createIconBitmap(String placeholder, int color) {
+ if (!ATLEAST_OREO) return null;
+
+ Bitmap placeholderBitmap = Bitmap.createBitmap(mIconBitmapSize, mIconBitmapSize,
+ Bitmap.Config.ARGB_8888);
+ mTextPaint.setColor(color);
+ Canvas canvas = new Canvas(placeholderBitmap);
+ canvas.drawText(placeholder, mIconBitmapSize / 2, mIconBitmapSize * 5 / 8, mTextPaint);
+ AdaptiveIconDrawable drawable = new AdaptiveIconDrawable(
+ new ColorDrawable(PLACEHOLDER_BACKGROUND_COLOR),
+ new BitmapDrawable(mContext.getResources(), placeholderBitmap));
+ Bitmap icon = createIconBitmap(drawable, 1f);
+ return BitmapInfo.of(icon, extractColor(icon));
+ }
+
+ public BitmapInfo createIconBitmap(Bitmap icon) {
+ if (mIconBitmapSize != icon.getWidth() || mIconBitmapSize != icon.getHeight()) {
+ icon = createIconBitmap(new BitmapDrawable(mContext.getResources(), icon), 1f);
+ }
+
+ return BitmapInfo.of(icon, extractColor(icon));
+ }
+
+ /**
+ * Creates an icon from the bitmap cropped to the current device icon shape
+ */
+ public BitmapInfo createShapedIconBitmap(Bitmap icon, UserHandle user) {
+ Drawable d = new FixedSizeBitmapDrawable(icon);
+ if (ATLEAST_OREO) {
+ float inset = AdaptiveIconDrawable.getExtraInsetFraction();
+ inset = inset / (1 + 2 * inset);
+ d = new AdaptiveIconDrawable(new ColorDrawable(Color.BLACK),
+ new InsetDrawable(d, inset, inset, inset, inset));
+ }
+ return createBadgedIconBitmap(d, user, true);
+ }
+
+ public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
+ boolean shrinkNonAdaptiveIcons) {
+ return createBadgedIconBitmap(icon, user, shrinkNonAdaptiveIcons, false, null);
+ }
+
+ public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
+ int iconAppTargetSdk) {
+ return createBadgedIconBitmap(icon, user, iconAppTargetSdk, false);
+ }
+
+ public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
+ int iconAppTargetSdk, boolean isInstantApp) {
+ return createBadgedIconBitmap(icon, user, iconAppTargetSdk, isInstantApp, null);
+ }
+
+ public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
+ int iconAppTargetSdk, boolean isInstantApp, float[] scale) {
+ boolean shrinkNonAdaptiveIcons = ATLEAST_P ||
+ (ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O);
+ return createBadgedIconBitmap(icon, user, shrinkNonAdaptiveIcons, isInstantApp, scale);
+ }
+
+ public Bitmap createScaledBitmapWithoutShadow(Drawable icon, int iconAppTargetSdk) {
+ boolean shrinkNonAdaptiveIcons = ATLEAST_P ||
+ (ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O);
+ return createScaledBitmapWithoutShadow(icon, shrinkNonAdaptiveIcons);
+ }
+
+ /**
+ * Creates bitmap using the source drawable and various parameters.
+ * The bitmap is visually normalized with other icons and has enough spacing to add shadow.
+ *
+ * @param icon source of the icon
+ * @param user info can be used for a badge
+ * @param shrinkNonAdaptiveIcons {@code true} if non adaptive icons should be treated
+ * @param isInstantApp info can be used for a badge
+ * @param scale returns the scale result from normalization
+ * @return a bitmap suitable for disaplaying as an icon at various system UIs.
+ */
+ public BitmapInfo createBadgedIconBitmap(@NonNull Drawable icon, UserHandle user,
+ boolean shrinkNonAdaptiveIcons, boolean isInstantApp, float[] scale) {
+ if (scale == null) {
+ scale = new float[1];
+ }
+ icon = normalizeAndWrapToAdaptiveIcon(icon, shrinkNonAdaptiveIcons, null, scale);
+ Bitmap bitmap = createIconBitmap(icon, scale[0]);
+ if (ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) {
+ mCanvas.setBitmap(bitmap);
+ getShadowGenerator().recreateIcon(Bitmap.createBitmap(bitmap), mCanvas);
+ mCanvas.setBitmap(null);
+ }
+
+ if (isInstantApp) {
+ badgeWithDrawable(bitmap, mContext.getDrawable(R.drawable.ic_instant_app_badge));
+ }
+ if (user != null) {
+ BitmapDrawable drawable = new FixedSizeBitmapDrawable(bitmap);
+ Drawable badged = mPm.getUserBadgedIcon(drawable, user);
+ if (badged instanceof BitmapDrawable) {
+ bitmap = ((BitmapDrawable) badged).getBitmap();
+ } else {
+ bitmap = createIconBitmap(badged, 1f);
+ }
+ }
+ int color = extractColor(bitmap);
+ return icon instanceof BitmapInfo.Extender
+ ? ((BitmapInfo.Extender) icon).getExtendedInfo(bitmap, color, this, scale[0], user)
+ : BitmapInfo.of(bitmap, color);
+ }
+
+ public Bitmap getUserBadgeBitmap(UserHandle user) {
+ if (mUserBadgeBitmap == null) {
+ Bitmap bitmap = Bitmap.createBitmap(
+ mIconBitmapSize, mIconBitmapSize, Bitmap.Config.ARGB_8888);
+ Drawable badgedDrawable = mPm.getUserBadgedIcon(
+ new FixedSizeBitmapDrawable(bitmap), user);
+ if (badgedDrawable instanceof BitmapDrawable) {
+ mUserBadgeBitmap = ((BitmapDrawable) badgedDrawable).getBitmap();
+ } else {
+ badgedDrawable.setBounds(0, 0, mIconBitmapSize, mIconBitmapSize);
+ mUserBadgeBitmap = BitmapRenderer.createSoftwareBitmap(
+ mIconBitmapSize, mIconBitmapSize, badgedDrawable::draw);
+ }
+ }
+ return mUserBadgeBitmap;
+ }
+
+ public Bitmap createScaledBitmapWithoutShadow(Drawable icon, boolean shrinkNonAdaptiveIcons) {
+ RectF iconBounds = new RectF();
+ float[] scale = new float[1];
+ icon = normalizeAndWrapToAdaptiveIcon(icon, shrinkNonAdaptiveIcons, iconBounds, scale);
+ return createIconBitmap(icon,
+ Math.min(scale[0], ShadowGenerator.getScaleForBounds(iconBounds)));
+ }
+
+ /**
+ * Switches badging to left/right
+ */
+ public void setBadgeOnLeft(boolean badgeOnLeft) {
+ mBadgeOnLeft = badgeOnLeft;
+ }
+
+ /**
+ * Sets the background color used for wrapped adaptive icon
+ */
+ public void setWrapperBackgroundColor(int color) {
+ mWrapperBackgroundColor = (Color.alpha(color) < 255) ? DEFAULT_WRAPPER_BACKGROUND : color;
+ }
+
+ /**
+ * Disables the dominant color extraction for all icons loaded.
+ */
+ public void disableColorExtraction() {
+ mDisableColorExtractor = true;
+ }
+
+ private Drawable normalizeAndWrapToAdaptiveIcon(@NonNull Drawable icon,
+ boolean shrinkNonAdaptiveIcons, RectF outIconBounds, float[] outScale) {
+ if (icon == null) {
+ return null;
+ }
+ float scale = 1f;
+
+ if (shrinkNonAdaptiveIcons && ATLEAST_OREO) {
+ if (mWrapperIcon == null) {
+ mWrapperIcon = mContext.getDrawable(R.drawable.adaptive_icon_drawable_wrapper)
+ .mutate();
+ }
+ AdaptiveIconDrawable dr = (AdaptiveIconDrawable) mWrapperIcon;
+ dr.setBounds(0, 0, 1, 1);
+ boolean[] outShape = new boolean[1];
+ scale = getNormalizer().getScale(icon, outIconBounds, dr.getIconMask(), outShape);
+ if (!(icon instanceof AdaptiveIconDrawable) && !outShape[0]) {
+ FixedScaleDrawable fsd = ((FixedScaleDrawable) dr.getForeground());
+ fsd.setDrawable(icon);
+ fsd.setScale(scale);
+ icon = dr;
+ scale = getNormalizer().getScale(icon, outIconBounds, null, null);
+
+ ((ColorDrawable) dr.getBackground()).setColor(mWrapperBackgroundColor);
+ }
+ } else {
+ scale = getNormalizer().getScale(icon, outIconBounds, null, null);
+ }
+
+ outScale[0] = scale;
+ return icon;
+ }
+
+ /**
+ * Adds the {@param badge} on top of {@param target} using the badge dimensions.
+ */
+ public void badgeWithDrawable(Bitmap target, Drawable badge) {
+ mCanvas.setBitmap(target);
+ badgeWithDrawable(mCanvas, badge);
+ mCanvas.setBitmap(null);
+ }
+
+ /**
+ * Adds the {@param badge} on top of {@param target} using the badge dimensions.
+ */
+ public void badgeWithDrawable(Canvas target, Drawable badge) {
+ int badgeSize = getBadgeSizeForIconSize(mIconBitmapSize);
+ if (mBadgeOnLeft) {
+ badge.setBounds(0, mIconBitmapSize - badgeSize, badgeSize, mIconBitmapSize);
+ } else {
+ badge.setBounds(mIconBitmapSize - badgeSize, mIconBitmapSize - badgeSize,
+ mIconBitmapSize, mIconBitmapSize);
+ }
+ badge.draw(target);
+ }
+
+ private Bitmap createIconBitmap(Drawable icon, float scale) {
+ return createIconBitmap(icon, scale, mIconBitmapSize);
+ }
+
+ /**
+ * @param icon drawable that should be flattened to a bitmap
+ * @param scale the scale to apply before drawing {@param icon} on the canvas
+ */
+ public Bitmap createIconBitmap(@NonNull Drawable icon, float scale, int size) {
+ Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+ if (icon == null) {
+ return bitmap;
+ }
+ mCanvas.setBitmap(bitmap);
+ mOldBounds.set(icon.getBounds());
+
+ if (ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) {
+ int offset = Math.max((int) Math.ceil(BLUR_FACTOR * size),
+ Math.round(size * (1 - scale) / 2 ));
+ icon.setBounds(offset, offset, size - offset, size - offset);
+ if (icon instanceof BitmapInfo.Extender) {
+ ((Extender) icon).drawForPersistence(mCanvas);
+ } else {
+ icon.draw(mCanvas);
+ }
+ } else {
+ if (icon instanceof BitmapDrawable) {
+ BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
+ Bitmap b = bitmapDrawable.getBitmap();
+ if (bitmap != null && b.getDensity() == Bitmap.DENSITY_NONE) {
+ bitmapDrawable.setTargetDensity(mContext.getResources().getDisplayMetrics());
+ }
+ }
+ int width = size;
+ int height = size;
+
+ int intrinsicWidth = icon.getIntrinsicWidth();
+ int intrinsicHeight = icon.getIntrinsicHeight();
+ if (intrinsicWidth > 0 && intrinsicHeight > 0) {
+ // Scale the icon proportionally to the icon dimensions
+ final float ratio = (float) intrinsicWidth / intrinsicHeight;
+ if (intrinsicWidth > intrinsicHeight) {
+ height = (int) (width / ratio);
+ } else if (intrinsicHeight > intrinsicWidth) {
+ width = (int) (height * ratio);
+ }
+ }
+ final int left = (size - width) / 2;
+ final int top = (size - height) / 2;
+ icon.setBounds(left, top, left + width, top + height);
+ mCanvas.save();
+ mCanvas.scale(scale, scale, size / 2, size / 2);
+ icon.draw(mCanvas);
+ mCanvas.restore();
+
+ }
+ icon.setBounds(mOldBounds);
+ mCanvas.setBitmap(null);
+ return bitmap;
+ }
+
+ @Override
+ public void close() {
+ clear();
+ }
+
+ public BitmapInfo makeDefaultIcon(UserHandle user) {
+ return createBadgedIconBitmap(getFullResDefaultActivityIcon(mFillResIconDpi),
+ user, Build.VERSION.SDK_INT);
+ }
+
+ public static Drawable getFullResDefaultActivityIcon(int iconDpi) {
+ return Resources.getSystem().getDrawableForDensity(
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+ ? android.R.drawable.sym_def_app_icon : android.R.mipmap.sym_def_app_icon,
+ iconDpi);
+ }
+
+ /**
+ * Badges the provided source with the badge info
+ */
+ public BitmapInfo badgeBitmap(Bitmap source, BitmapInfo badgeInfo) {
+ Bitmap icon = BitmapRenderer.createHardwareBitmap(mIconBitmapSize, mIconBitmapSize, (c) -> {
+ getShadowGenerator().recreateIcon(source, c);
+ badgeWithDrawable(c, new FixedSizeBitmapDrawable(badgeInfo.icon));
+ });
+ return BitmapInfo.of(icon, badgeInfo.color);
+ }
+
+ private int extractColor(Bitmap bitmap) {
+ return mDisableColorExtractor ? 0 : mColorExtractor.findDominantColorByHue(bitmap);
+ }
+
+ /**
+ * Returns the correct badge size given an icon size
+ */
+ public static int getBadgeSizeForIconSize(int iconSize) {
+ return (int) (ICON_BADGE_SCALE * iconSize);
+ }
+
+ /**
+ * An extension of {@link BitmapDrawable} which returns the bitmap pixel size as intrinsic size.
+ * This allows the badging to be done based on the action bitmap size rather than
+ * the scaled bitmap size.
+ */
+ private static class FixedSizeBitmapDrawable extends BitmapDrawable {
+
+ public FixedSizeBitmapDrawable(Bitmap bitmap) {
+ super(null, bitmap);
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return getBitmap().getWidth();
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return getBitmap().getWidth();
+ }
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java
new file mode 100644
index 000000000..06b39b8f1
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java
@@ -0,0 +1,163 @@
+/*
+ * 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 com.android.launcher3.icons;
+
+import static com.android.launcher3.icons.GraphicsUtils.getExpectedBitmapSize;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.UserHandle;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.icons.ThemedIconDrawable.ThemedBitmapInfo;
+import com.android.launcher3.icons.cache.BaseIconCache;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class BitmapInfo {
+
+ public static final Bitmap LOW_RES_ICON = Bitmap.createBitmap(1, 1, Config.ALPHA_8);
+ public static final BitmapInfo LOW_RES_INFO = fromBitmap(LOW_RES_ICON);
+
+ public static final String TAG = "BitmapInfo";
+
+ protected static final byte TYPE_DEFAULT = 1;
+ protected static final byte TYPE_THEMED = 2;
+
+ public final Bitmap icon;
+ public final int color;
+
+ public BitmapInfo(Bitmap icon, int color) {
+ this.icon = icon;
+ this.color = color;
+ }
+
+ /**
+ * Ideally icon should not be null, except in cases when generating hardware bitmap failed
+ */
+ public final boolean isNullOrLowRes() {
+ return icon == null || icon == LOW_RES_ICON;
+ }
+
+ public final boolean isLowRes() {
+ return LOW_RES_ICON == icon;
+ }
+
+ /**
+ * Returns a serialized version of BitmapInfo
+ */
+ @Nullable
+ public byte[] toByteArray() {
+ if (isNullOrLowRes()) {
+ return null;
+ }
+ ByteArrayOutputStream out = new ByteArrayOutputStream(getExpectedBitmapSize(icon) + 1);
+ try {
+ out.write(TYPE_DEFAULT);
+ icon.compress(Bitmap.CompressFormat.PNG, 100, out);
+ out.flush();
+ out.close();
+ return out.toByteArray();
+ } catch (IOException e) {
+ Log.w(TAG, "Could not write bitmap");
+ return null;
+ }
+ }
+
+ /**
+ * Returns a new icon based on the theme of the context
+ */
+ public FastBitmapDrawable newThemedIcon(Context context) {
+ return newIcon(context);
+ }
+
+ /**
+ * Creates a drawable for the provided BitmapInfo
+ */
+ public FastBitmapDrawable newIcon(Context context) {
+ FastBitmapDrawable drawable = isLowRes()
+ ? new PlaceHolderIconDrawable(this, context)
+ : new FastBitmapDrawable(this);
+ drawable.mDisabledAlpha = GraphicsUtils.getFloat(context, R.attr.disabledIconAlpha, 1f);
+ return drawable;
+ }
+
+ /**
+ * Returns a BitmapInfo previously serialized using {@link #toByteArray()};
+ */
+ @NonNull
+ public static BitmapInfo fromByteArray(byte[] data, int color, UserHandle user,
+ BaseIconCache iconCache, Context context) {
+ if (data == null) {
+ return null;
+ }
+ BitmapFactory.Options decodeOptions;
+ if (BitmapRenderer.USE_HARDWARE_BITMAP && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ decodeOptions = new BitmapFactory.Options();
+ decodeOptions.inPreferredConfig = Bitmap.Config.HARDWARE;
+ } else {
+ decodeOptions = null;
+ }
+ if (data[0] == TYPE_DEFAULT) {
+ return BitmapInfo.of(
+ BitmapFactory.decodeByteArray(data, 1, data.length - 1, decodeOptions),
+ color);
+ } else if (data[0] == TYPE_THEMED) {
+ return ThemedBitmapInfo.decode(data, color, decodeOptions, user, iconCache, context);
+ } else {
+ return null;
+ }
+ }
+
+ public static BitmapInfo fromBitmap(@NonNull Bitmap bitmap) {
+ return of(bitmap, 0);
+ }
+
+ public static BitmapInfo of(@NonNull Bitmap bitmap, int color) {
+ return new BitmapInfo(bitmap, color);
+ }
+
+ /**
+ * Interface to be implemented by drawables to provide a custom BitmapInfo
+ */
+ public interface Extender {
+
+ /**
+ * Called for creating a custom BitmapInfo
+ */
+ BitmapInfo getExtendedInfo(Bitmap bitmap, int color,
+ BaseIconFactory iconFactory, float normalizationScale, UserHandle user);
+
+ /**
+ * Called to draw the UI independent of any runtime configurations like time or theme
+ */
+ void drawForPersistence(Canvas canvas);
+
+ /**
+ * Returns a new icon with theme applied
+ */
+ Drawable getThemedDrawable(Context context);
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/BitmapRenderer.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/BitmapRenderer.java
new file mode 100644
index 000000000..5751ed95c
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/BitmapRenderer.java
@@ -0,0 +1,70 @@
+/*
+ * 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 com.android.launcher3.icons;
+
+import android.annotation.TargetApi;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
+import android.graphics.Picture;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
+
+/**
+ * Interface representing a bitmap draw operation.
+ */
+public interface BitmapRenderer {
+
+ boolean USE_HARDWARE_BITMAP = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
+
+ static Bitmap createSoftwareBitmap(int width, int height, BitmapRenderer renderer) {
+ GraphicsUtils.noteNewBitmapCreated();
+ Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ renderer.draw(new Canvas(result));
+ return result;
+ }
+
+ @TargetApi(Build.VERSION_CODES.P)
+ static Bitmap createHardwareBitmap(int width, int height, BitmapRenderer renderer) {
+ if (!USE_HARDWARE_BITMAP) {
+ return createSoftwareBitmap(width, height, renderer);
+ }
+
+ GraphicsUtils.noteNewBitmapCreated();
+ Picture picture = new Picture();
+ renderer.draw(picture.beginRecording(width, height));
+ picture.endRecording();
+ return Bitmap.createBitmap(picture);
+ }
+
+ /**
+ * Returns a bitmap from subset of the source bitmap. The new bitmap may be the
+ * same object as source, or a copy may have been made.
+ */
+ static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) {
+ if (Build.VERSION.SDK_INT >= VERSION_CODES.O && source.getConfig() == Config.HARDWARE) {
+ return createHardwareBitmap(width, height, c -> c.drawBitmap(source,
+ new Rect(x, y, x + width, y + height), new RectF(0, 0, width, height), null));
+ } else {
+ GraphicsUtils.noteNewBitmapCreated();
+ return Bitmap.createBitmap(source, x, y, width, height);
+ }
+ }
+
+ void draw(Canvas out);
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/ClockDrawableWrapper.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/ClockDrawableWrapper.java
new file mode 100644
index 000000000..a7894c991
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/ClockDrawableWrapper.java
@@ -0,0 +1,448 @@
+/*
+ * 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 com.android.launcher3.icons;
+
+import static com.android.launcher3.icons.ThemedIconDrawable.getColors;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.Rect;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.TypedValue;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.icons.ThemedIconDrawable.ThemeData;
+
+import java.util.Calendar;
+import java.util.concurrent.TimeUnit;
+import java.util.function.IntFunction;
+
+/**
+ * Wrapper over {@link AdaptiveIconDrawable} to intercept icon flattening logic for dynamic
+ * clock icons
+ */
+@TargetApi(Build.VERSION_CODES.O)
+public class ClockDrawableWrapper extends AdaptiveIconDrawable implements BitmapInfo.Extender {
+
+ private static final String TAG = "ClockDrawableWrapper";
+
+ private static final boolean DISABLE_SECONDS = true;
+
+ // Time after which the clock icon should check for an update. The actual invalidate
+ // will only happen in case of any change.
+ public static final long TICK_MS = DISABLE_SECONDS ? TimeUnit.MINUTES.toMillis(1) : 200L;
+
+ private static final String LAUNCHER_PACKAGE = "com.android.launcher3";
+ private static final String ROUND_ICON_METADATA_KEY = LAUNCHER_PACKAGE
+ + ".LEVEL_PER_TICK_ICON_ROUND";
+ private static final String HOUR_INDEX_METADATA_KEY = LAUNCHER_PACKAGE + ".HOUR_LAYER_INDEX";
+ private static final String MINUTE_INDEX_METADATA_KEY = LAUNCHER_PACKAGE
+ + ".MINUTE_LAYER_INDEX";
+ private static final String SECOND_INDEX_METADATA_KEY = LAUNCHER_PACKAGE
+ + ".SECOND_LAYER_INDEX";
+ private static final String DEFAULT_HOUR_METADATA_KEY = LAUNCHER_PACKAGE
+ + ".DEFAULT_HOUR";
+ private static final String DEFAULT_MINUTE_METADATA_KEY = LAUNCHER_PACKAGE
+ + ".DEFAULT_MINUTE";
+ private static final String DEFAULT_SECOND_METADATA_KEY = LAUNCHER_PACKAGE
+ + ".DEFAULT_SECOND";
+
+ /* Number of levels to jump per second for the second hand */
+ private static final int LEVELS_PER_SECOND = 10;
+
+ public static final int INVALID_VALUE = -1;
+
+ private final AnimationInfo mAnimationInfo = new AnimationInfo();
+ private int mTargetSdkVersion;
+ protected ThemeData mThemeData;
+
+ public ClockDrawableWrapper(AdaptiveIconDrawable base) {
+ super(base.getBackground(), base.getForeground());
+ }
+
+ /**
+ * Loads and returns the wrapper from the provided package, or returns null
+ * if it is unable to load.
+ */
+ public static ClockDrawableWrapper forPackage(Context context, String pkg, int iconDpi) {
+ try {
+ PackageManager pm = context.getPackageManager();
+ ApplicationInfo appInfo = pm.getApplicationInfo(pkg,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA);
+ Resources res = pm.getResourcesForApplication(appInfo);
+ return forExtras(appInfo, appInfo.metaData,
+ resId -> res.getDrawableForDensity(resId, iconDpi));
+ } catch (Exception e) {
+ Log.d(TAG, "Unable to load clock drawable info", e);
+ }
+ return null;
+ }
+
+ private static ClockDrawableWrapper fromThemeData(Context context, ThemeData themeData) {
+ try {
+ TypedArray ta = themeData.mResources.obtainTypedArray(themeData.mResID);
+ int count = ta.length();
+ Bundle extras = new Bundle();
+ for (int i = 0; i < count; i += 2) {
+ TypedValue v = ta.peekValue(i + 1);
+ extras.putInt(ta.getString(i), v.type >= TypedValue.TYPE_FIRST_INT
+ && v.type <= TypedValue.TYPE_LAST_INT
+ ? v.data : v.resourceId);
+ }
+ ta.recycle();
+ ClockDrawableWrapper drawable = ClockDrawableWrapper.forExtras(
+ context.getApplicationInfo(), extras, resId -> {
+ int[] colors = getColors(context);
+ Drawable bg = new ColorDrawable(colors[0]);
+ Drawable fg = themeData.mResources.getDrawable(resId).mutate();
+ fg.setTint(colors[1]);
+ return new AdaptiveIconDrawable(bg, fg);
+ });
+ if (drawable != null) {
+ return drawable;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error loading themed clock", e);
+ }
+ return null;
+ }
+
+ private static ClockDrawableWrapper forExtras(ApplicationInfo appInfo, Bundle metadata,
+ IntFunction<Drawable> drawableProvider) {
+ if (metadata == null) {
+ return null;
+ }
+ int drawableId = metadata.getInt(ROUND_ICON_METADATA_KEY, 0);
+ if (drawableId == 0) {
+ return null;
+ }
+
+ Drawable drawable = drawableProvider.apply(drawableId).mutate();
+ if (!(drawable instanceof AdaptiveIconDrawable)) {
+ return null;
+ }
+
+ ClockDrawableWrapper wrapper =
+ new ClockDrawableWrapper((AdaptiveIconDrawable) drawable);
+ wrapper.mTargetSdkVersion = appInfo.targetSdkVersion;
+ AnimationInfo info = wrapper.mAnimationInfo;
+
+ info.baseDrawableState = drawable.getConstantState();
+
+ info.hourLayerIndex = metadata.getInt(HOUR_INDEX_METADATA_KEY, INVALID_VALUE);
+ info.minuteLayerIndex = metadata.getInt(MINUTE_INDEX_METADATA_KEY, INVALID_VALUE);
+ info.secondLayerIndex = metadata.getInt(SECOND_INDEX_METADATA_KEY, INVALID_VALUE);
+
+ info.defaultHour = metadata.getInt(DEFAULT_HOUR_METADATA_KEY, 0);
+ info.defaultMinute = metadata.getInt(DEFAULT_MINUTE_METADATA_KEY, 0);
+ info.defaultSecond = metadata.getInt(DEFAULT_SECOND_METADATA_KEY, 0);
+
+ LayerDrawable foreground = (LayerDrawable) wrapper.getForeground();
+ int layerCount = foreground.getNumberOfLayers();
+ if (info.hourLayerIndex < 0 || info.hourLayerIndex >= layerCount) {
+ info.hourLayerIndex = INVALID_VALUE;
+ }
+ if (info.minuteLayerIndex < 0 || info.minuteLayerIndex >= layerCount) {
+ info.minuteLayerIndex = INVALID_VALUE;
+ }
+ if (info.secondLayerIndex < 0 || info.secondLayerIndex >= layerCount) {
+ info.secondLayerIndex = INVALID_VALUE;
+ } else if (DISABLE_SECONDS) {
+ foreground.setDrawable(info.secondLayerIndex, null);
+ info.secondLayerIndex = INVALID_VALUE;
+ }
+ info.applyTime(Calendar.getInstance(), foreground);
+ return wrapper;
+ }
+
+ @Override
+ public ClockBitmapInfo getExtendedInfo(Bitmap bitmap, int color,
+ BaseIconFactory iconFactory, float normalizationScale, UserHandle user) {
+ iconFactory.disableColorExtraction();
+ AdaptiveIconDrawable background = new AdaptiveIconDrawable(
+ getBackground().getConstantState().newDrawable(), null);
+ BitmapInfo bitmapInfo = iconFactory.createBadgedIconBitmap(background,
+ Process.myUserHandle(), mTargetSdkVersion, false);
+
+ return new ClockBitmapInfo(bitmap, color, normalizationScale,
+ mAnimationInfo, bitmapInfo.icon, mThemeData);
+ }
+
+ @Override
+ public void drawForPersistence(Canvas canvas) {
+ LayerDrawable foreground = (LayerDrawable) getForeground();
+ resetLevel(foreground, mAnimationInfo.hourLayerIndex);
+ resetLevel(foreground, mAnimationInfo.minuteLayerIndex);
+ resetLevel(foreground, mAnimationInfo.secondLayerIndex);
+ draw(canvas);
+ mAnimationInfo.applyTime(Calendar.getInstance(), (LayerDrawable) getForeground());
+ }
+
+ @Override
+ public Drawable getThemedDrawable(Context context) {
+ if (mThemeData != null) {
+ ClockDrawableWrapper drawable = fromThemeData(context, mThemeData);
+ return drawable == null ? this : drawable;
+ }
+ return this;
+ }
+
+ private void resetLevel(LayerDrawable drawable, int index) {
+ if (index != INVALID_VALUE) {
+ drawable.getDrawable(index).setLevel(0);
+ }
+ }
+
+ private static class AnimationInfo {
+
+ public ConstantState baseDrawableState;
+
+ public int hourLayerIndex;
+ public int minuteLayerIndex;
+ public int secondLayerIndex;
+ public int defaultHour;
+ public int defaultMinute;
+ public int defaultSecond;
+
+ boolean applyTime(Calendar time, LayerDrawable foregroundDrawable) {
+ time.setTimeInMillis(System.currentTimeMillis());
+
+ // We need to rotate by the difference from the default time if one is specified.
+ int convertedHour = (time.get(Calendar.HOUR) + (12 - defaultHour)) % 12;
+ int convertedMinute = (time.get(Calendar.MINUTE) + (60 - defaultMinute)) % 60;
+ int convertedSecond = (time.get(Calendar.SECOND) + (60 - defaultSecond)) % 60;
+
+ boolean invalidate = false;
+ if (hourLayerIndex != INVALID_VALUE) {
+ final Drawable hour = foregroundDrawable.getDrawable(hourLayerIndex);
+ if (hour.setLevel(convertedHour * 60 + time.get(Calendar.MINUTE))) {
+ invalidate = true;
+ }
+ }
+
+ if (minuteLayerIndex != INVALID_VALUE) {
+ final Drawable minute = foregroundDrawable.getDrawable(minuteLayerIndex);
+ if (minute.setLevel(time.get(Calendar.HOUR) * 60 + convertedMinute)) {
+ invalidate = true;
+ }
+ }
+
+ if (secondLayerIndex != INVALID_VALUE) {
+ final Drawable second = foregroundDrawable.getDrawable(secondLayerIndex);
+ if (second.setLevel(convertedSecond * LEVELS_PER_SECOND)) {
+ invalidate = true;
+ }
+ }
+
+ return invalidate;
+ }
+ }
+
+ static class ClockBitmapInfo extends BitmapInfo {
+
+ public final float scale;
+ public final int offset;
+ public final AnimationInfo animInfo;
+ public final Bitmap mFlattenedBackground;
+
+ public final ThemeData themeData;
+ public final ColorFilter bgFilter;
+
+ ClockBitmapInfo(Bitmap icon, int color, float scale, AnimationInfo animInfo,
+ Bitmap background, ThemeData themeData) {
+ this(icon, color, scale, animInfo, background, themeData, null);
+ }
+
+ ClockBitmapInfo(Bitmap icon, int color, float scale, AnimationInfo animInfo,
+ Bitmap background, ThemeData themeData, ColorFilter bgFilter) {
+ super(icon, color);
+ this.scale = scale;
+ this.animInfo = animInfo;
+ this.offset = (int) Math.ceil(ShadowGenerator.BLUR_FACTOR * icon.getWidth());
+ this.mFlattenedBackground = background;
+ this.themeData = themeData;
+ this.bgFilter = bgFilter;
+ }
+
+ @Override
+ public FastBitmapDrawable newThemedIcon(Context context) {
+ if (themeData != null) {
+ ClockDrawableWrapper wrapper = fromThemeData(context, themeData);
+ if (wrapper != null) {
+ int[] colors = getColors(context);
+ ColorFilter bgFilter = new PorterDuffColorFilter(colors[0], Mode.SRC_ATOP);
+ return new ClockBitmapInfo(icon, colors[1], scale,
+ wrapper.mAnimationInfo, mFlattenedBackground, themeData, bgFilter)
+ .newIcon(context);
+ }
+ }
+ return super.newThemedIcon(context);
+ }
+
+ @Override
+ public FastBitmapDrawable newIcon(Context context) {
+ ClockIconDrawable d = new ClockIconDrawable(this);
+ d.mDisabledAlpha = GraphicsUtils.getFloat(context, R.attr.disabledIconAlpha, 1f);
+ return d;
+ }
+
+ @Nullable
+ @Override
+ public byte[] toByteArray() {
+ return null;
+ }
+
+ void drawBackground(Canvas canvas, Rect bounds, Paint paint) {
+ // draw the background that is already flattened to a bitmap
+ ColorFilter oldFilter = paint.getColorFilter();
+ if (bgFilter != null) {
+ paint.setColorFilter(bgFilter);
+ }
+ canvas.drawBitmap(mFlattenedBackground, null, bounds, paint);
+ paint.setColorFilter(oldFilter);
+ }
+ }
+
+ private static class ClockIconDrawable extends FastBitmapDrawable implements Runnable {
+
+ private final Calendar mTime = Calendar.getInstance();
+
+ private final ClockBitmapInfo mInfo;
+
+ private final AdaptiveIconDrawable mFullDrawable;
+ private final LayerDrawable mForeground;
+
+ ClockIconDrawable(ClockBitmapInfo clockInfo) {
+ super(clockInfo);
+
+ mInfo = clockInfo;
+ mFullDrawable = (AdaptiveIconDrawable) mInfo.animInfo.baseDrawableState
+ .newDrawable().mutate();
+ mForeground = (LayerDrawable) mFullDrawable.getForeground();
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ super.onBoundsChange(bounds);
+ mFullDrawable.setBounds(bounds);
+ }
+
+ @Override
+ public void drawInternal(Canvas canvas, Rect bounds) {
+ if (mInfo == null) {
+ super.drawInternal(canvas, bounds);
+ return;
+ }
+ mInfo.drawBackground(canvas, bounds, mPaint);
+
+ // prepare and draw the foreground
+ mInfo.animInfo.applyTime(mTime, mForeground);
+
+ canvas.scale(mInfo.scale, mInfo.scale,
+ bounds.exactCenterX() + mInfo.offset, bounds.exactCenterY() + mInfo.offset);
+ canvas.clipPath(mFullDrawable.getIconMask());
+ mForeground.draw(canvas);
+
+ reschedule();
+ }
+
+ @Override
+ public boolean isThemed() {
+ return mInfo.bgFilter != null;
+ }
+
+ @Override
+ protected void updateFilter() {
+ super.updateFilter();
+ mFullDrawable.setColorFilter(mPaint.getColorFilter());
+ }
+
+ @Override
+ public void run() {
+ if (mInfo.animInfo.applyTime(mTime, mForeground)) {
+ invalidateSelf();
+ } else {
+ reschedule();
+ }
+ }
+
+ @Override
+ public boolean setVisible(boolean visible, boolean restart) {
+ boolean result = super.setVisible(visible, restart);
+ if (visible) {
+ reschedule();
+ } else {
+ unscheduleSelf(this);
+ }
+ return result;
+ }
+
+ private void reschedule() {
+ if (!isVisible()) {
+ return;
+ }
+
+ unscheduleSelf(this);
+ final long upTime = SystemClock.uptimeMillis();
+ final long step = TICK_MS; /* tick every 200 ms */
+ scheduleSelf(this, upTime - ((upTime % step)) + step);
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ return new ClockConstantState(mInfo, isDisabled());
+ }
+
+ private static class ClockConstantState extends FastBitmapConstantState {
+
+ private final ClockBitmapInfo mInfo;
+
+ ClockConstantState(ClockBitmapInfo info, boolean isDisabled) {
+ super(info.icon, info.color, isDisabled);
+ mInfo = info;
+ }
+
+ @Override
+ public FastBitmapDrawable newDrawable() {
+ ClockIconDrawable drawable = new ClockIconDrawable(mInfo);
+ drawable.setIsDisabled(mIsDisabled);
+ return drawable;
+ }
+ }
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/ColorExtractor.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/ColorExtractor.java
new file mode 100644
index 000000000..87bda825c
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/ColorExtractor.java
@@ -0,0 +1,127 @@
+/*
+ * 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 com.android.launcher3.icons;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.util.SparseArray;
+import java.util.Arrays;
+
+/**
+ * Utility class for extracting colors from a bitmap.
+ */
+public class ColorExtractor {
+
+ private final int NUM_SAMPLES = 20;
+ private final float[] mTmpHsv = new float[3];
+ private final float[] mTmpHueScoreHistogram = new float[360];
+ private final int[] mTmpPixels = new int[NUM_SAMPLES];
+ private final SparseArray<Float> mTmpRgbScores = new SparseArray<>();
+
+ /**
+ * This picks a dominant color, looking for high-saturation, high-value, repeated hues.
+ * @param bitmap The bitmap to scan
+ */
+ public int findDominantColorByHue(Bitmap bitmap) {
+ return findDominantColorByHue(bitmap, NUM_SAMPLES);
+ }
+
+ /**
+ * This picks a dominant color, looking for high-saturation, high-value, repeated hues.
+ * @param bitmap The bitmap to scan
+ */
+ public int findDominantColorByHue(Bitmap bitmap, int samples) {
+ final int height = bitmap.getHeight();
+ final int width = bitmap.getWidth();
+ int sampleStride = (int) Math.sqrt((height * width) / samples);
+ if (sampleStride < 1) {
+ sampleStride = 1;
+ }
+
+ // This is an out-param, for getting the hsv values for an rgb
+ float[] hsv = mTmpHsv;
+ Arrays.fill(hsv, 0);
+
+ // First get the best hue, by creating a histogram over 360 hue buckets,
+ // where each pixel contributes a score weighted by saturation, value, and alpha.
+ float[] hueScoreHistogram = mTmpHueScoreHistogram;
+ Arrays.fill(hueScoreHistogram, 0);
+ float highScore = -1;
+ int bestHue = -1;
+
+ int[] pixels = mTmpPixels;
+ Arrays.fill(pixels, 0);
+ int pixelCount = 0;
+
+ for (int y = 0; y < height; y += sampleStride) {
+ for (int x = 0; x < width; x += sampleStride) {
+ int argb = bitmap.getPixel(x, y);
+ int alpha = 0xFF & (argb >> 24);
+ if (alpha < 0x80) {
+ // Drop mostly-transparent pixels.
+ continue;
+ }
+ // Remove the alpha channel.
+ int rgb = argb | 0xFF000000;
+ Color.colorToHSV(rgb, hsv);
+ // Bucket colors by the 360 integer hues.
+ int hue = (int) hsv[0];
+ if (hue < 0 || hue >= hueScoreHistogram.length) {
+ // Defensively avoid array bounds violations.
+ continue;
+ }
+ if (pixelCount < samples) {
+ pixels[pixelCount++] = rgb;
+ }
+ float score = hsv[1] * hsv[2];
+ hueScoreHistogram[hue] += score;
+ if (hueScoreHistogram[hue] > highScore) {
+ highScore = hueScoreHistogram[hue];
+ bestHue = hue;
+ }
+ }
+ }
+
+ SparseArray<Float> rgbScores = mTmpRgbScores;
+ rgbScores.clear();
+ int bestColor = 0xff000000;
+ highScore = -1;
+ // Go back over the RGB colors that match the winning hue,
+ // creating a histogram of weighted s*v scores, for up to 100*100 [s,v] buckets.
+ // The highest-scoring RGB color wins.
+ for (int i = 0; i < pixelCount; i++) {
+ int rgb = pixels[i];
+ Color.colorToHSV(rgb, hsv);
+ int hue = (int) hsv[0];
+ if (hue == bestHue) {
+ float s = hsv[1];
+ float v = hsv[2];
+ int bucket = (int) (s * 100) + (int) (v * 10000);
+ // Score by cumulative saturation * value.
+ float score = s * v;
+ Float oldTotal = rgbScores.get(bucket);
+ float newTotal = oldTotal == null ? score : oldTotal + score;
+ rgbScores.put(bucket, newTotal);
+ if (newTotal > highScore) {
+ highScore = newTotal;
+ // All the colors in the winning bucket are very similar. Last in wins.
+ bestColor = rgb;
+ }
+ }
+ }
+ return bestColor;
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java
new file mode 100644
index 000000000..97a0fd3ff
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java
@@ -0,0 +1,143 @@
+/*
+ * 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 com.android.launcher3.icons;
+
+import static android.graphics.Paint.ANTI_ALIAS_FLAG;
+import static android.graphics.Paint.FILTER_BITMAP_FLAG;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PathMeasure;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.Log;
+import android.view.ViewDebug;
+
+/**
+ * Used to draw a notification dot on top of an icon.
+ */
+public class DotRenderer {
+
+ private static final String TAG = "DotRenderer";
+
+ // The dot size is defined as a percentage of the app icon size.
+ private static final float SIZE_PERCENTAGE = 0.228f;
+
+ private final float mCircleRadius;
+ private final Paint mCirclePaint = new Paint(ANTI_ALIAS_FLAG | FILTER_BITMAP_FLAG);
+
+ private final Bitmap mBackgroundWithShadow;
+ private final float mBitmapOffset;
+
+ // Stores the center x and y position as a percentage (0 to 1) of the icon size
+ private final float[] mRightDotPosition;
+ private final float[] mLeftDotPosition;
+
+ public DotRenderer(int iconSizePx, Path iconShapePath, int pathSize) {
+ int size = Math.round(SIZE_PERCENTAGE * iconSizePx);
+ ShadowGenerator.Builder builder = new ShadowGenerator.Builder(Color.TRANSPARENT);
+ builder.ambientShadowAlpha = 88;
+ mBackgroundWithShadow = builder.setupBlurForSize(size).createPill(size, size);
+ mCircleRadius = builder.radius;
+
+ mBitmapOffset = -mBackgroundWithShadow.getHeight() * 0.5f; // Same as width.
+
+ // Find the points on the path that are closest to the top left and right corners.
+ mLeftDotPosition = getPathPoint(iconShapePath, pathSize, -1);
+ mRightDotPosition = getPathPoint(iconShapePath, pathSize, 1);
+ }
+
+ private static float[] getPathPoint(Path path, float size, float direction) {
+ float halfSize = size / 2;
+ // Small delta so that we don't get a zero size triangle
+ float delta = 1;
+
+ float x = halfSize + direction * halfSize;
+ Path trianglePath = new Path();
+ trianglePath.moveTo(halfSize, halfSize);
+ trianglePath.lineTo(x + delta * direction, 0);
+ trianglePath.lineTo(x, -delta);
+ trianglePath.close();
+
+ trianglePath.op(path, Path.Op.INTERSECT);
+ float[] pos = new float[2];
+ new PathMeasure(trianglePath, false).getPosTan(0, pos, null);
+
+ pos[0] = pos[0] / size;
+ pos[1] = pos[1] / size;
+ return pos;
+ }
+
+ public float[] getLeftDotPosition() {
+ return mLeftDotPosition;
+ }
+
+ public float[] getRightDotPosition() {
+ return mRightDotPosition;
+ }
+
+ /**
+ * Draw a circle on top of the canvas according to the given params.
+ */
+ public void draw(Canvas canvas, DrawParams params) {
+ if (params == null) {
+ Log.e(TAG, "Invalid null argument(s) passed in call to draw.");
+ return;
+ }
+ canvas.save();
+
+ Rect iconBounds = params.iconBounds;
+ float[] dotPosition = params.leftAlign ? mLeftDotPosition : mRightDotPosition;
+ float dotCenterX = iconBounds.left + iconBounds.width() * dotPosition[0];
+ float dotCenterY = iconBounds.top + iconBounds.height() * dotPosition[1];
+
+ // Ensure dot fits entirely in canvas clip bounds.
+ Rect canvasBounds = canvas.getClipBounds();
+ float offsetX = params.leftAlign
+ ? Math.max(0, canvasBounds.left - (dotCenterX + mBitmapOffset))
+ : Math.min(0, canvasBounds.right - (dotCenterX - mBitmapOffset));
+ float offsetY = Math.max(0, canvasBounds.top - (dotCenterY + mBitmapOffset));
+
+ // We draw the dot relative to its center.
+ canvas.translate(dotCenterX + offsetX, dotCenterY + offsetY);
+ canvas.scale(params.scale, params.scale);
+
+ mCirclePaint.setColor(Color.BLACK);
+ canvas.drawBitmap(mBackgroundWithShadow, mBitmapOffset, mBitmapOffset, mCirclePaint);
+ mCirclePaint.setColor(params.color);
+ canvas.drawCircle(0, 0, mCircleRadius, mCirclePaint);
+ canvas.restore();
+ }
+
+ public static class DrawParams {
+ /** The color (possibly based on the icon) to use for the dot. */
+ @ViewDebug.ExportedProperty(category = "notification dot", formatToHexString = true)
+ public int color;
+ /** The bounds of the icon that the dot is drawn on top of. */
+ @ViewDebug.ExportedProperty(category = "notification dot")
+ public Rect iconBounds = new Rect();
+ /** The progress of the animation, from 0 to 1. */
+ @ViewDebug.ExportedProperty(category = "notification dot")
+ public float scale;
+ /** Whether the dot should align to the top left of the icon rather than the top right. */
+ @ViewDebug.ExportedProperty(category = "notification dot")
+ public boolean leftAlign;
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/FastBitmapDrawable.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/FastBitmapDrawable.java
new file mode 100644
index 000000000..4aa284618
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/FastBitmapDrawable.java
@@ -0,0 +1,314 @@
+/*
+ * 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 com.android.launcher3.icons;
+
+import android.animation.ObjectAnimator;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.Property;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+
+import androidx.annotation.Nullable;
+
+public class FastBitmapDrawable extends Drawable {
+
+ private static final Interpolator ACCEL = new AccelerateInterpolator();
+ private static final Interpolator DEACCEL = new DecelerateInterpolator();
+
+ private static final float PRESSED_SCALE = 1.1f;
+
+ private static final float DISABLED_DESATURATION = 1f;
+ private static final float DISABLED_BRIGHTNESS = 0.5f;
+
+ public static final int CLICK_FEEDBACK_DURATION = 200;
+
+ private static ColorFilter sDisabledFColorFilter;
+
+ protected final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
+ protected Bitmap mBitmap;
+ protected final int mIconColor;
+
+ @Nullable private ColorFilter mColorFilter;
+
+ private boolean mIsPressed;
+ protected boolean mIsDisabled;
+ float mDisabledAlpha = 1f;
+
+ // Animator and properties for the fast bitmap drawable's scale
+ private static final Property<FastBitmapDrawable, Float> SCALE
+ = new Property<FastBitmapDrawable, Float>(Float.TYPE, "scale") {
+ @Override
+ public Float get(FastBitmapDrawable fastBitmapDrawable) {
+ return fastBitmapDrawable.mScale;
+ }
+
+ @Override
+ public void set(FastBitmapDrawable fastBitmapDrawable, Float value) {
+ fastBitmapDrawable.mScale = value;
+ fastBitmapDrawable.invalidateSelf();
+ }
+ };
+ private ObjectAnimator mScaleAnimation;
+ private float mScale = 1;
+
+ private int mAlpha = 255;
+
+ public FastBitmapDrawable(Bitmap b) {
+ this(b, Color.TRANSPARENT);
+ }
+
+ public FastBitmapDrawable(BitmapInfo info) {
+ this(info.icon, info.color);
+ }
+
+ protected FastBitmapDrawable(Bitmap b, int iconColor) {
+ this(b, iconColor, false);
+ }
+
+ protected FastBitmapDrawable(Bitmap b, int iconColor, boolean isDisabled) {
+ mBitmap = b;
+ mIconColor = iconColor;
+ setFilterBitmap(true);
+ setIsDisabled(isDisabled);
+ }
+
+ @Override
+ public final void draw(Canvas canvas) {
+ if (mScale != 1f) {
+ int count = canvas.save();
+ Rect bounds = getBounds();
+ canvas.scale(mScale, mScale, bounds.exactCenterX(), bounds.exactCenterY());
+ drawInternal(canvas, bounds);
+ canvas.restoreToCount(count);
+ } else {
+ drawInternal(canvas, getBounds());
+ }
+ }
+
+ protected void drawInternal(Canvas canvas, Rect bounds) {
+ canvas.drawBitmap(mBitmap, null, bounds, mPaint);
+ }
+
+ /**
+ * Returns the primary icon color
+ */
+ public int getIconColor() {
+ return mIconColor;
+ }
+
+ /**
+ * Returns if this represents a themed icon
+ */
+ public boolean isThemed() {
+ return false;
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ mColorFilter = cf;
+ updateFilter();
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ if (mAlpha != alpha) {
+ mAlpha = alpha;
+ mPaint.setAlpha(alpha);
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ public void setFilterBitmap(boolean filterBitmap) {
+ mPaint.setFilterBitmap(filterBitmap);
+ mPaint.setAntiAlias(filterBitmap);
+ }
+
+ @Override
+ public int getAlpha() {
+ return mAlpha;
+ }
+
+ public void resetScale() {
+ if (mScaleAnimation != null) {
+ mScaleAnimation.cancel();
+ mScaleAnimation = null;
+ }
+ mScale = 1;
+ invalidateSelf();
+ }
+
+ public float getAnimatedScale() {
+ return mScaleAnimation == null ? 1 : mScale;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mBitmap.getWidth();
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mBitmap.getHeight();
+ }
+
+ @Override
+ public int getMinimumWidth() {
+ return getBounds().width();
+ }
+
+ @Override
+ public int getMinimumHeight() {
+ return getBounds().height();
+ }
+
+ @Override
+ public boolean isStateful() {
+ return true;
+ }
+
+ @Override
+ public ColorFilter getColorFilter() {
+ return mPaint.getColorFilter();
+ }
+
+ @Override
+ protected boolean onStateChange(int[] state) {
+ boolean isPressed = false;
+ for (int s : state) {
+ if (s == android.R.attr.state_pressed) {
+ isPressed = true;
+ break;
+ }
+ }
+ if (mIsPressed != isPressed) {
+ mIsPressed = isPressed;
+
+ if (mScaleAnimation != null) {
+ mScaleAnimation.cancel();
+ mScaleAnimation = null;
+ }
+
+ if (mIsPressed) {
+ // Animate when going to pressed state
+ mScaleAnimation = ObjectAnimator.ofFloat(this, SCALE, PRESSED_SCALE);
+ mScaleAnimation.setDuration(CLICK_FEEDBACK_DURATION);
+ mScaleAnimation.setInterpolator(ACCEL);
+ mScaleAnimation.start();
+ } else {
+ if (isVisible()) {
+ mScaleAnimation = ObjectAnimator.ofFloat(this, SCALE, 1f);
+ mScaleAnimation.setDuration(CLICK_FEEDBACK_DURATION);
+ mScaleAnimation.setInterpolator(DEACCEL);
+ mScaleAnimation.start();
+ } else {
+ mScale = 1f;
+ invalidateSelf();
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public void setIsDisabled(boolean isDisabled) {
+ if (mIsDisabled != isDisabled) {
+ mIsDisabled = isDisabled;
+ updateFilter();
+ }
+ }
+
+ protected boolean isDisabled() {
+ return mIsDisabled;
+ }
+
+ private ColorFilter getDisabledColorFilter() {
+ if (sDisabledFColorFilter == null) {
+ sDisabledFColorFilter = getDisabledFColorFilter(mDisabledAlpha);
+ }
+ return sDisabledFColorFilter;
+ }
+
+ /**
+ * Updates the paint to reflect the current brightness and saturation.
+ */
+ protected void updateFilter() {
+ mPaint.setColorFilter(mIsDisabled ? getDisabledColorFilter() : mColorFilter);
+ invalidateSelf();
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ return new FastBitmapConstantState(mBitmap, mIconColor, mIsDisabled);
+ }
+
+ public static ColorFilter getDisabledFColorFilter(float disabledAlpha) {
+ ColorMatrix tempBrightnessMatrix = new ColorMatrix();
+ ColorMatrix tempFilterMatrix = new ColorMatrix();
+
+ tempFilterMatrix.setSaturation(1f - DISABLED_DESATURATION);
+ float scale = 1 - DISABLED_BRIGHTNESS;
+ int brightnessI = (int) (255 * DISABLED_BRIGHTNESS);
+ float[] mat = tempBrightnessMatrix.getArray();
+ mat[0] = scale;
+ mat[6] = scale;
+ mat[12] = scale;
+ mat[4] = brightnessI;
+ mat[9] = brightnessI;
+ mat[14] = brightnessI;
+ mat[18] = disabledAlpha;
+ tempFilterMatrix.preConcat(tempBrightnessMatrix);
+ return new ColorMatrixColorFilter(tempBrightnessMatrix);
+ }
+
+ protected static class FastBitmapConstantState extends ConstantState {
+ protected final Bitmap mBitmap;
+ protected final int mIconColor;
+ protected final boolean mIsDisabled;
+
+ public FastBitmapConstantState(Bitmap bitmap, int color, boolean isDisabled) {
+ mBitmap = bitmap;
+ mIconColor = color;
+ mIsDisabled = isDisabled;
+ }
+
+ @Override
+ public FastBitmapDrawable newDrawable() {
+ return new FastBitmapDrawable(mBitmap, mIconColor, mIsDisabled);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return 0;
+ }
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/FixedScaleDrawable.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/FixedScaleDrawable.java
new file mode 100644
index 000000000..516965ec2
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/FixedScaleDrawable.java
@@ -0,0 +1,53 @@
+package com.android.launcher3.icons;
+
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.graphics.Canvas;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.DrawableWrapper;
+import android.util.AttributeSet;
+
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Extension of {@link DrawableWrapper} which scales the child drawables by a fixed amount.
+ */
+public class FixedScaleDrawable extends DrawableWrapper {
+
+ // TODO b/33553066 use the constant defined in MaskableIconDrawable
+ private static final float LEGACY_ICON_SCALE = .7f * .6667f;
+ private float mScaleX, mScaleY;
+
+ public FixedScaleDrawable() {
+ super(new ColorDrawable());
+ mScaleX = LEGACY_ICON_SCALE;
+ mScaleY = LEGACY_ICON_SCALE;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ int saveCount = canvas.save();
+ canvas.scale(mScaleX, mScaleY,
+ getBounds().exactCenterX(), getBounds().exactCenterY());
+ super.draw(canvas);
+ canvas.restoreToCount(saveCount);
+ }
+
+ @Override
+ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) { }
+
+ @Override
+ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) { }
+
+ public void setScale(float scale) {
+ float h = getIntrinsicHeight();
+ float w = getIntrinsicWidth();
+ mScaleX = scale * LEGACY_ICON_SCALE;
+ mScaleY = scale * LEGACY_ICON_SCALE;
+ if (h > w && w > 0) {
+ mScaleX *= w / h;
+ } else if (w > h && h > 0) {
+ mScaleY *= h / w;
+ }
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/GraphicsUtils.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/GraphicsUtils.java
new file mode 100644
index 000000000..17b001642
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/GraphicsUtils.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.icons;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.graphics.RegionIterator;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.util.Log;
+
+import androidx.annotation.ColorInt;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class GraphicsUtils {
+
+ private static final String TAG = "GraphicsUtils";
+
+ public static Runnable sOnNewBitmapRunnable = () -> { };
+
+ /**
+ * Set the alpha component of {@code color} to be {@code alpha}. Unlike the support lib version,
+ * it bounds the alpha in valid range instead of throwing an exception to allow for safer
+ * interpolation of color animations
+ */
+ @ColorInt
+ public static int setColorAlphaBound(int color, int alpha) {
+ if (alpha < 0) {
+ alpha = 0;
+ } else if (alpha > 255) {
+ alpha = 255;
+ }
+ return (color & 0x00ffffff) | (alpha << 24);
+ }
+
+ /**
+ * Compresses the bitmap to a byte array for serialization.
+ */
+ public static byte[] flattenBitmap(Bitmap bitmap) {
+ ByteArrayOutputStream out = new ByteArrayOutputStream(getExpectedBitmapSize(bitmap));
+ try {
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
+ out.flush();
+ out.close();
+ return out.toByteArray();
+ } catch (IOException e) {
+ Log.w(TAG, "Could not write bitmap");
+ return null;
+ }
+ }
+
+ /**
+ * Try go guesstimate how much space the icon will take when serialized to avoid unnecessary
+ * allocations/copies during the write (4 bytes per pixel).
+ */
+ static int getExpectedBitmapSize(Bitmap bitmap) {
+ return bitmap.getWidth() * bitmap.getHeight() * 4;
+ }
+
+ public static int getArea(Region r) {
+ RegionIterator itr = new RegionIterator(r);
+ int area = 0;
+ Rect tempRect = new Rect();
+ while (itr.next(tempRect)) {
+ area += tempRect.width() * tempRect.height();
+ }
+ return area;
+ }
+
+ /**
+ * Utility method to track new bitmap creation
+ */
+ public static void noteNewBitmapCreated() {
+ sOnNewBitmapRunnable.run();
+ }
+
+
+ /**
+ * Returns the default path to be used by an icon
+ */
+ public static Path getShapePath(int size) {
+ AdaptiveIconDrawable drawable = new AdaptiveIconDrawable(
+ new ColorDrawable(Color.BLACK), new ColorDrawable(Color.BLACK));
+ drawable.setBounds(0, 0, size, size);
+ return new Path(drawable.getIconMask());
+ }
+
+ /**
+ * Returns the color associated with the attribute
+ */
+ public static int getAttrColor(Context context, int attr) {
+ TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
+ int colorAccent = ta.getColor(0, 0);
+ ta.recycle();
+ return colorAccent;
+ }
+
+ /**
+ * Returns the alpha corresponding to the theme attribute {@param attr}
+ */
+ public static float getFloat(Context context, int attr, float defValue) {
+ TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
+ float value = ta.getFloat(0, defValue);
+ ta.recycle();
+ return value;
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java
new file mode 100644
index 000000000..de39e79fe
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java
@@ -0,0 +1,411 @@
+/*
+ * 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.launcher3.icons;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Region;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.util.Log;
+
+import java.nio.ByteBuffer;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+public class IconNormalizer {
+
+ private static final String TAG = "IconNormalizer";
+ private static final boolean DEBUG = false;
+ // Ratio of icon visible area to full icon size for a square shaped icon
+ private static final float MAX_SQUARE_AREA_FACTOR = 375.0f / 576;
+ // Ratio of icon visible area to full icon size for a circular shaped icon
+ private static final float MAX_CIRCLE_AREA_FACTOR = 380.0f / 576;
+
+ private static final float CIRCLE_AREA_BY_RECT = (float) Math.PI / 4;
+
+ // Slope used to calculate icon visible area to full icon size for any generic shaped icon.
+ private static final float LINEAR_SCALE_SLOPE =
+ (MAX_CIRCLE_AREA_FACTOR - MAX_SQUARE_AREA_FACTOR) / (1 - CIRCLE_AREA_BY_RECT);
+
+ private static final int MIN_VISIBLE_ALPHA = 40;
+
+ // Shape detection related constants
+ private static final float BOUND_RATIO_MARGIN = .05f;
+ private static final float PIXEL_DIFF_PERCENTAGE_THRESHOLD = 0.005f;
+ private static final float SCALE_NOT_INITIALIZED = 0;
+
+ // Ratio of the diameter of an normalized circular icon to the actual icon size.
+ public static final float ICON_VISIBLE_AREA_FACTOR = 0.92f;
+
+ private final int mMaxSize;
+ private final Bitmap mBitmap;
+ private final Canvas mCanvas;
+ private final Paint mPaintMaskShape;
+ private final Paint mPaintMaskShapeOutline;
+ private final byte[] mPixels;
+
+ private final RectF mAdaptiveIconBounds;
+ private float mAdaptiveIconScale;
+
+ private boolean mEnableShapeDetection;
+
+ // for each y, stores the position of the leftmost x and the rightmost x
+ private final float[] mLeftBorder;
+ private final float[] mRightBorder;
+ private final Rect mBounds;
+ private final Path mShapePath;
+ private final Matrix mMatrix;
+
+ /** package private **/
+ IconNormalizer(Context context, int iconBitmapSize, boolean shapeDetection) {
+ // Use twice the icon size as maximum size to avoid scaling down twice.
+ mMaxSize = iconBitmapSize * 2;
+ mBitmap = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ALPHA_8);
+ mCanvas = new Canvas(mBitmap);
+ mPixels = new byte[mMaxSize * mMaxSize];
+ mLeftBorder = new float[mMaxSize];
+ mRightBorder = new float[mMaxSize];
+ mBounds = new Rect();
+ mAdaptiveIconBounds = new RectF();
+
+ mPaintMaskShape = new Paint();
+ mPaintMaskShape.setColor(Color.RED);
+ mPaintMaskShape.setStyle(Paint.Style.FILL);
+ mPaintMaskShape.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
+
+ mPaintMaskShapeOutline = new Paint();
+ mPaintMaskShapeOutline.setStrokeWidth(
+ 2 * context.getResources().getDisplayMetrics().density);
+ mPaintMaskShapeOutline.setStyle(Paint.Style.STROKE);
+ mPaintMaskShapeOutline.setColor(Color.BLACK);
+ mPaintMaskShapeOutline.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+
+ mShapePath = new Path();
+ mMatrix = new Matrix();
+ mAdaptiveIconScale = SCALE_NOT_INITIALIZED;
+ mEnableShapeDetection = shapeDetection;
+ }
+
+ private static float getScale(float hullArea, float boundingArea, float fullArea) {
+ float hullByRect = hullArea / boundingArea;
+ float scaleRequired;
+ if (hullByRect < CIRCLE_AREA_BY_RECT) {
+ scaleRequired = MAX_CIRCLE_AREA_FACTOR;
+ } else {
+ scaleRequired = MAX_SQUARE_AREA_FACTOR + LINEAR_SCALE_SLOPE * (1 - hullByRect);
+ }
+
+ float areaScale = hullArea / fullArea;
+ // Use sqrt of the final ratio as the images is scaled across both width and height.
+ return areaScale > scaleRequired ? (float) Math.sqrt(scaleRequired / areaScale) : 1;
+ }
+
+ /**
+ * @param d Should be AdaptiveIconDrawable
+ * @param size Canvas size to use
+ */
+ @TargetApi(Build.VERSION_CODES.O)
+ public static float normalizeAdaptiveIcon(Drawable d, int size, @Nullable RectF outBounds) {
+ Rect tmpBounds = new Rect(d.getBounds());
+ d.setBounds(0, 0, size, size);
+
+ Path path = ((AdaptiveIconDrawable) d).getIconMask();
+ Region region = new Region();
+ region.setPath(path, new Region(0, 0, size, size));
+
+ Rect hullBounds = region.getBounds();
+ int hullArea = GraphicsUtils.getArea(region);
+
+ if (outBounds != null) {
+ float sizeF = size;
+ outBounds.set(
+ hullBounds.left / sizeF,
+ hullBounds.top / sizeF,
+ 1 - (hullBounds.right / sizeF),
+ 1 - (hullBounds.bottom / sizeF));
+ }
+ d.setBounds(tmpBounds);
+ return getScale(hullArea, hullArea, size * size);
+ }
+
+ /**
+ * Returns if the shape of the icon is same as the path.
+ * For this method to work, the shape path bounds should be in [0,1]x[0,1] bounds.
+ */
+ private boolean isShape(Path maskPath) {
+ // Condition1:
+ // If width and height of the path not close to a square, then the icon shape is
+ // not same as the mask shape.
+ float iconRatio = ((float) mBounds.width()) / mBounds.height();
+ if (Math.abs(iconRatio - 1) > BOUND_RATIO_MARGIN) {
+ if (DEBUG) {
+ Log.d(TAG, "Not same as mask shape because width != height. " + iconRatio);
+ }
+ return false;
+ }
+
+ // Condition 2:
+ // Actual icon (white) and the fitted shape (e.g., circle)(red) XOR operation
+ // should generate transparent image, if the actual icon is equivalent to the shape.
+
+ // Fit the shape within the icon's bounding box
+ mMatrix.reset();
+ mMatrix.setScale(mBounds.width(), mBounds.height());
+ mMatrix.postTranslate(mBounds.left, mBounds.top);
+ maskPath.transform(mMatrix, mShapePath);
+
+ // XOR operation
+ mCanvas.drawPath(mShapePath, mPaintMaskShape);
+
+ // DST_OUT operation around the mask path outline
+ mCanvas.drawPath(mShapePath, mPaintMaskShapeOutline);
+
+ // Check if the result is almost transparent
+ return isTransparentBitmap();
+ }
+
+ /**
+ * Used to determine if certain the bitmap is transparent.
+ */
+ private boolean isTransparentBitmap() {
+ ByteBuffer buffer = ByteBuffer.wrap(mPixels);
+ buffer.rewind();
+ mBitmap.copyPixelsToBuffer(buffer);
+
+ int y = mBounds.top;
+ // buffer position
+ int index = y * mMaxSize;
+ // buffer shift after every row, width of buffer = mMaxSize
+ int rowSizeDiff = mMaxSize - mBounds.right;
+
+ int sum = 0;
+ for (; y < mBounds.bottom; y++) {
+ index += mBounds.left;
+ for (int x = mBounds.left; x < mBounds.right; x++) {
+ if ((mPixels[index] & 0xFF) > MIN_VISIBLE_ALPHA) {
+ sum++;
+ }
+ index++;
+ }
+ index += rowSizeDiff;
+ }
+
+ float percentageDiffPixels = ((float) sum) / (mBounds.width() * mBounds.height());
+ return percentageDiffPixels < PIXEL_DIFF_PERCENTAGE_THRESHOLD;
+ }
+
+ /**
+ * Returns the amount by which the {@param d} should be scaled (in both dimensions) so that it
+ * matches the design guidelines for a launcher icon.
+ *
+ * We first calculate the convex hull of the visible portion of the icon.
+ * This hull then compared with the bounding rectangle of the hull to find how closely it
+ * resembles a circle and a square, by comparing the ratio of the areas. Note that this is not an
+ * ideal solution but it gives satisfactory result without affecting the performance.
+ *
+ * This closeness is used to determine the ratio of hull area to the full icon size.
+ * Refer {@link #MAX_CIRCLE_AREA_FACTOR} and {@link #MAX_SQUARE_AREA_FACTOR}
+ *
+ * @param outBounds optional rect to receive the fraction distance from each edge.
+ */
+ public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds,
+ @Nullable Path path, @Nullable boolean[] outMaskShape) {
+ if (BaseIconFactory.ATLEAST_OREO && d instanceof AdaptiveIconDrawable) {
+ if (mAdaptiveIconScale == SCALE_NOT_INITIALIZED) {
+ mAdaptiveIconScale = normalizeAdaptiveIcon(d, mMaxSize, mAdaptiveIconBounds);
+ }
+ if (outBounds != null) {
+ outBounds.set(mAdaptiveIconBounds);
+ }
+ return mAdaptiveIconScale;
+ }
+ int width = d.getIntrinsicWidth();
+ int height = d.getIntrinsicHeight();
+ if (width <= 0 || height <= 0) {
+ width = width <= 0 || width > mMaxSize ? mMaxSize : width;
+ height = height <= 0 || height > mMaxSize ? mMaxSize : height;
+ } else if (width > mMaxSize || height > mMaxSize) {
+ int max = Math.max(width, height);
+ width = mMaxSize * width / max;
+ height = mMaxSize * height / max;
+ }
+
+ mBitmap.eraseColor(Color.TRANSPARENT);
+ d.setBounds(0, 0, width, height);
+ d.draw(mCanvas);
+
+ ByteBuffer buffer = ByteBuffer.wrap(mPixels);
+ buffer.rewind();
+ mBitmap.copyPixelsToBuffer(buffer);
+
+ // Overall bounds of the visible icon.
+ int topY = -1;
+ int bottomY = -1;
+ int leftX = mMaxSize + 1;
+ int rightX = -1;
+
+ // Create border by going through all pixels one row at a time and for each row find
+ // the first and the last non-transparent pixel. Set those values to mLeftBorder and
+ // mRightBorder and use -1 if there are no visible pixel in the row.
+
+ // buffer position
+ int index = 0;
+ // buffer shift after every row, width of buffer = mMaxSize
+ int rowSizeDiff = mMaxSize - width;
+ // first and last position for any row.
+ int firstX, lastX;
+
+ for (int y = 0; y < height; y++) {
+ firstX = lastX = -1;
+ for (int x = 0; x < width; x++) {
+ if ((mPixels[index] & 0xFF) > MIN_VISIBLE_ALPHA) {
+ if (firstX == -1) {
+ firstX = x;
+ }
+ lastX = x;
+ }
+ index++;
+ }
+ index += rowSizeDiff;
+
+ mLeftBorder[y] = firstX;
+ mRightBorder[y] = lastX;
+
+ // If there is at least one visible pixel, update the overall bounds.
+ if (firstX != -1) {
+ bottomY = y;
+ if (topY == -1) {
+ topY = y;
+ }
+
+ leftX = Math.min(leftX, firstX);
+ rightX = Math.max(rightX, lastX);
+ }
+ }
+
+ if (topY == -1 || rightX == -1) {
+ // No valid pixels found. Do not scale.
+ return 1;
+ }
+
+ convertToConvexArray(mLeftBorder, 1, topY, bottomY);
+ convertToConvexArray(mRightBorder, -1, topY, bottomY);
+
+ // Area of the convex hull
+ float area = 0;
+ for (int y = 0; y < height; y++) {
+ if (mLeftBorder[y] <= -1) {
+ continue;
+ }
+ area += mRightBorder[y] - mLeftBorder[y] + 1;
+ }
+
+ mBounds.left = leftX;
+ mBounds.right = rightX;
+
+ mBounds.top = topY;
+ mBounds.bottom = bottomY;
+
+ if (outBounds != null) {
+ outBounds.set(((float) mBounds.left) / width, ((float) mBounds.top) / height,
+ 1 - ((float) mBounds.right) / width,
+ 1 - ((float) mBounds.bottom) / height);
+ }
+ if (outMaskShape != null && mEnableShapeDetection && outMaskShape.length > 0) {
+ outMaskShape[0] = isShape(path);
+ }
+ // Area of the rectangle required to fit the convex hull
+ float rectArea = (bottomY + 1 - topY) * (rightX + 1 - leftX);
+ return getScale(area, rectArea, width * height);
+ }
+
+ /**
+ * Modifies {@param xCoordinates} to represent a convex border. Fills in all missing values
+ * (except on either ends) with appropriate values.
+ * @param xCoordinates map of x coordinate per y.
+ * @param direction 1 for left border and -1 for right border.
+ * @param topY the first Y position (inclusive) with a valid value.
+ * @param bottomY the last Y position (inclusive) with a valid value.
+ */
+ private static void convertToConvexArray(
+ float[] xCoordinates, int direction, int topY, int bottomY) {
+ int total = xCoordinates.length;
+ // The tangent at each pixel.
+ float[] angles = new float[total - 1];
+
+ int first = topY; // First valid y coordinate
+ int last = -1; // Last valid y coordinate which didn't have a missing value
+
+ float lastAngle = Float.MAX_VALUE;
+
+ for (int i = topY + 1; i <= bottomY; i++) {
+ if (xCoordinates[i] <= -1) {
+ continue;
+ }
+ int start;
+
+ if (lastAngle == Float.MAX_VALUE) {
+ start = first;
+ } else {
+ float currentAngle = (xCoordinates[i] - xCoordinates[last]) / (i - last);
+ start = last;
+ // If this position creates a concave angle, keep moving up until we find a
+ // position which creates a convex angle.
+ if ((currentAngle - lastAngle) * direction < 0) {
+ while (start > first) {
+ start --;
+ currentAngle = (xCoordinates[i] - xCoordinates[start]) / (i - start);
+ if ((currentAngle - angles[start]) * direction >= 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ // Reset from last check
+ lastAngle = (xCoordinates[i] - xCoordinates[start]) / (i - start);
+ // Update all the points from start.
+ for (int j = start; j < i; j++) {
+ angles[j] = lastAngle;
+ xCoordinates[j] = xCoordinates[start] + lastAngle * (j - start);
+ }
+ last = i;
+ }
+ }
+
+ /**
+ * @return The diameter of the normalized circle that fits inside of the square (size x size).
+ */
+ public static int getNormalizedCircleSize(int size) {
+ float area = size * size * MAX_CIRCLE_AREA_FACTOR;
+ return (int) Math.round(Math.sqrt((4 * area) / Math.PI));
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java
new file mode 100644
index 000000000..449c0daa5
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java
@@ -0,0 +1,377 @@
+/*
+ * 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 com.android.launcher3.icons;
+
+import static android.content.Intent.ACTION_DATE_CHANGED;
+import static android.content.Intent.ACTION_TIMEZONE_CHANGED;
+import static android.content.Intent.ACTION_TIME_CHANGED;
+import static android.content.res.Resources.ID_NULL;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.LauncherActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.PatternMatcher;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.launcher3.icons.ThemedIconDrawable.ThemeData;
+import com.android.launcher3.util.SafeCloseable;
+
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Map;
+import java.util.function.Supplier;
+
+/**
+ * Class to handle icon loading from different packages
+ */
+public class IconProvider {
+
+ private final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED";
+ private static final int CONFIG_ICON_MASK_RES_ID = Resources.getSystem().getIdentifier(
+ "config_icon_mask", "string", "android");
+
+ private static final String TAG_ICON = "icon";
+ private static final String ATTR_PACKAGE = "package";
+ private static final String ATTR_DRAWABLE = "drawable";
+
+ private static final String TAG = "IconProvider";
+ private static final boolean DEBUG = false;
+
+ private static final String ICON_METADATA_KEY_PREFIX = ".dynamic_icons";
+
+ private static final String SYSTEM_STATE_SEPARATOR = " ";
+ private static final String THEMED_ICON_MAP_FILE = "grayscale_icon_map";
+
+ private static final Map<String, ThemeData> DISABLED_MAP = Collections.emptyMap();
+
+ private Map<String, ThemeData> mThemedIconMap;
+
+ private final Context mContext;
+ private final ComponentName mCalendar;
+ private final ComponentName mClock;
+
+ static final int ICON_TYPE_DEFAULT = 0;
+ static final int ICON_TYPE_CALENDAR = 1;
+ static final int ICON_TYPE_CLOCK = 2;
+
+ public IconProvider(Context context) {
+ this(context, false);
+ }
+
+ public IconProvider(Context context, boolean supportsIconTheme) {
+ mContext = context;
+ mCalendar = parseComponentOrNull(context, R.string.calendar_component_name);
+ mClock = parseComponentOrNull(context, R.string.clock_component_name);
+ if (!supportsIconTheme) {
+ // Initialize an empty map if theming is not supported
+ mThemedIconMap = DISABLED_MAP;
+ }
+ }
+
+ /**
+ * Enables or disables icon theme support
+ */
+ public void setIconThemeSupported(boolean isSupported) {
+ mThemedIconMap = isSupported ? null : DISABLED_MAP;
+ }
+
+ /**
+ * Adds any modification to the provided systemState for dynamic icons. This system state
+ * is used by caches to check for icon invalidation.
+ */
+ public String getSystemStateForPackage(String systemState, String packageName) {
+ if (mCalendar != null && mCalendar.getPackageName().equals(packageName)) {
+ return systemState + SYSTEM_STATE_SEPARATOR + getDay();
+ } else {
+ return systemState;
+ }
+ }
+
+ /**
+ * Loads the icon for the provided LauncherActivityInfo
+ */
+ public Drawable getIcon(LauncherActivityInfo info, int iconDpi) {
+ return getIconWithOverrides(info.getApplicationInfo().packageName, info.getUser(), iconDpi,
+ () -> info.getIcon(iconDpi));
+ }
+
+ /**
+ * Loads the icon for the provided activity info
+ */
+ public Drawable getIcon(ActivityInfo info) {
+ return getIcon(info, mContext.getResources().getConfiguration().densityDpi);
+ }
+
+ /**
+ * Loads the icon for the provided activity info
+ */
+ public Drawable getIcon(ActivityInfo info, int iconDpi) {
+ return getIconWithOverrides(info.applicationInfo.packageName,
+ UserHandle.getUserHandleForUid(info.applicationInfo.uid),
+ iconDpi, () -> loadActivityInfoIcon(info, iconDpi));
+ }
+
+ private Drawable getIconWithOverrides(String packageName, UserHandle user, int iconDpi,
+ Supplier<Drawable> fallback) {
+ Drawable icon = null;
+
+ int iconType = ICON_TYPE_DEFAULT;
+ if (mCalendar != null && mCalendar.getPackageName().equals(packageName)) {
+ icon = loadCalendarDrawable(iconDpi);
+ iconType = ICON_TYPE_CALENDAR;
+ } else if (mClock != null
+ && mClock.getPackageName().equals(packageName)
+ && Process.myUserHandle().equals(user)) {
+ icon = loadClockDrawable(iconDpi);
+ iconType = ICON_TYPE_CLOCK;
+ }
+ if (icon == null) {
+ icon = fallback.get();
+ iconType = ICON_TYPE_DEFAULT;
+ }
+
+ ThemeData td = getThemedIconMap().get(packageName);
+ return td != null ? td.wrapDrawable(icon, iconType) : icon;
+ }
+
+ private Drawable loadActivityInfoIcon(ActivityInfo ai, int density) {
+ final int iconRes = ai.getIconResource();
+ Drawable icon = null;
+ // Get the preferred density icon from the app's resources
+ if (density != 0 && iconRes != 0) {
+ try {
+ final Resources resources = mContext.getPackageManager()
+ .getResourcesForApplication(ai.applicationInfo);
+ icon = resources.getDrawableForDensity(iconRes, density);
+ } catch (NameNotFoundException | Resources.NotFoundException exc) { }
+ }
+ // Get the default density icon
+ if (icon == null) {
+ icon = ai.loadIcon(mContext.getPackageManager());
+ }
+ return icon;
+ }
+
+ private Map<String, ThemeData> getThemedIconMap() {
+ if (mThemedIconMap != null) {
+ return mThemedIconMap;
+ }
+ ArrayMap<String, ThemeData> map = new ArrayMap<>();
+ try {
+ Resources res = mContext.getResources();
+ int resID = res.getIdentifier(THEMED_ICON_MAP_FILE, "xml", mContext.getPackageName());
+ if (resID != 0) {
+ XmlResourceParser parser = res.getXml(resID);
+ final int depth = parser.getDepth();
+
+ int type;
+
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT);
+
+ while (((type = parser.next()) != XmlPullParser.END_TAG ||
+ parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ if (TAG_ICON.equals(parser.getName())) {
+ String pkg = parser.getAttributeValue(null, ATTR_PACKAGE);
+ int iconId = parser.getAttributeResourceValue(null, ATTR_DRAWABLE, 0);
+ if (iconId != 0 && !TextUtils.isEmpty(pkg)) {
+ map.put(pkg, new ThemeData(res, iconId));
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to parse icon map", e);
+ }
+ mThemedIconMap = map;
+ return mThemedIconMap;
+ }
+
+ private Drawable loadCalendarDrawable(int iconDpi) {
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ final Bundle metadata = pm.getActivityInfo(
+ mCalendar,
+ PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA)
+ .metaData;
+ final Resources resources = pm.getResourcesForApplication(mCalendar.getPackageName());
+ final int id = getDynamicIconId(metadata, resources);
+ if (id != ID_NULL) {
+ if (DEBUG) Log.d(TAG, "Got icon #" + id);
+ return resources.getDrawableForDensity(id, iconDpi, null /* theme */);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ if (DEBUG) {
+ Log.d(TAG, "Could not get activityinfo or resources for package: "
+ + mCalendar.getPackageName());
+ }
+ }
+ return null;
+ }
+
+ private Drawable loadClockDrawable(int iconDpi) {
+ return ClockDrawableWrapper.forPackage(mContext, mClock.getPackageName(), iconDpi);
+ }
+
+ /**
+ * @param metadata metadata of the default activity of Calendar
+ * @param resources from the Calendar package
+ * @return the resource id for today's Calendar icon; 0 if resources cannot be found.
+ */
+ private int getDynamicIconId(Bundle metadata, Resources resources) {
+ if (metadata == null) {
+ return ID_NULL;
+ }
+ String key = mCalendar.getPackageName() + ICON_METADATA_KEY_PREFIX;
+ final int arrayId = metadata.getInt(key, ID_NULL);
+ if (arrayId == ID_NULL) {
+ return ID_NULL;
+ }
+ try {
+ return resources.obtainTypedArray(arrayId).getResourceId(getDay(), ID_NULL);
+ } catch (Resources.NotFoundException e) {
+ if (DEBUG) {
+ Log.d(TAG, "package defines '" + key + "' but corresponding array not found");
+ }
+ return ID_NULL;
+ }
+ }
+
+ /**
+ * @return Today's day of the month, zero-indexed.
+ */
+ static int getDay() {
+ return Calendar.getInstance().get(Calendar.DAY_OF_MONTH) - 1;
+ }
+
+ private static ComponentName parseComponentOrNull(Context context, int resId) {
+ String cn = context.getString(resId);
+ return TextUtils.isEmpty(cn) ? null : ComponentName.unflattenFromString(cn);
+ }
+
+ /**
+ * Returns a string representation of the current system icon state
+ */
+ public String getSystemIconState() {
+ return (CONFIG_ICON_MASK_RES_ID == ID_NULL
+ ? "" : mContext.getResources().getString(CONFIG_ICON_MASK_RES_ID))
+ + (mThemedIconMap == DISABLED_MAP ? ",no-theme" : ",with-theme");
+ }
+
+ /**
+ * Registers a callback to listen for various system dependent icon changes.
+ */
+ public SafeCloseable registerIconChangeListener(IconChangeListener listener, Handler handler) {
+ return new IconChangeReceiver(listener, handler);
+ }
+
+ private class IconChangeReceiver extends BroadcastReceiver implements SafeCloseable {
+
+ private final IconChangeListener mCallback;
+ private String mIconState;
+
+ IconChangeReceiver(IconChangeListener callback, Handler handler) {
+ mCallback = callback;
+ mIconState = getSystemIconState();
+
+
+ IntentFilter packageFilter = new IntentFilter(ACTION_OVERLAY_CHANGED);
+ packageFilter.addDataScheme("package");
+ packageFilter.addDataSchemeSpecificPart("android", PatternMatcher.PATTERN_LITERAL);
+ mContext.registerReceiver(this, packageFilter, null, handler);
+
+ if (mCalendar != null || mClock != null) {
+ final IntentFilter filter = new IntentFilter(ACTION_TIMEZONE_CHANGED);
+ if (mCalendar != null) {
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
+ filter.addAction(ACTION_DATE_CHANGED);
+ }
+ mContext.registerReceiver(this, filter, null, handler);
+ }
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ switch (intent.getAction()) {
+ case ACTION_TIMEZONE_CHANGED:
+ if (mClock != null) {
+ mCallback.onAppIconChanged(mClock.getPackageName(), Process.myUserHandle());
+ }
+ // follow through
+ case ACTION_DATE_CHANGED:
+ case ACTION_TIME_CHANGED:
+ if (mCalendar != null) {
+ for (UserHandle user
+ : context.getSystemService(UserManager.class).getUserProfiles()) {
+ mCallback.onAppIconChanged(mCalendar.getPackageName(), user);
+ }
+ }
+ break;
+ case ACTION_OVERLAY_CHANGED: {
+ String newState = getSystemIconState();
+ if (!mIconState.equals(newState)) {
+ mIconState = newState;
+ mCallback.onSystemIconStateChanged(mIconState);
+ }
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void close() {
+ mContext.unregisterReceiver(this);
+ }
+ }
+
+ /**
+ * Listener for receiving icon changes
+ */
+ public interface IconChangeListener {
+
+ /**
+ * Called when the icon for a particular app changes
+ */
+ void onAppIconChanged(String packageName, UserHandle user);
+
+ /**
+ * Called when the global icon state changed, which can typically affect all icons
+ */
+ void onSystemIconStateChanged(String iconState);
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/PlaceHolderIconDrawable.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/PlaceHolderIconDrawable.java
new file mode 100644
index 000000000..5f3343e31
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/PlaceHolderIconDrawable.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.icons;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Path;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+
+import androidx.core.graphics.ColorUtils;
+
+/**
+ * Subclass which draws a placeholder icon when the actual icon is not yet loaded
+ */
+public class PlaceHolderIconDrawable extends FastBitmapDrawable {
+
+ // Path in [0, 100] bounds.
+ private final Path mProgressPath;
+
+ public PlaceHolderIconDrawable(BitmapInfo info, Context context) {
+ super(info);
+
+ mProgressPath = GraphicsUtils.getShapePath(100);
+ mPaint.setColor(ColorUtils.compositeColors(
+ GraphicsUtils.getAttrColor(context, R.attr.loadingIconColor), info.color));
+ }
+
+ @Override
+ protected void drawInternal(Canvas canvas, Rect bounds) {
+ int saveCount = canvas.save();
+ canvas.translate(bounds.left, bounds.top);
+ canvas.scale(bounds.width() / 100f, bounds.height() / 100f);
+ canvas.drawPath(mProgressPath, mPaint);
+ canvas.restoreToCount(saveCount);
+ }
+
+ /** Updates this placeholder to {@code newIcon} with animation. */
+ public void animateIconUpdate(Drawable newIcon) {
+ int placeholderColor = mPaint.getColor();
+ int originalAlpha = Color.alpha(placeholderColor);
+
+ ValueAnimator iconUpdateAnimation = ValueAnimator.ofInt(originalAlpha, 0);
+ iconUpdateAnimation.setDuration(375);
+ iconUpdateAnimation.addUpdateListener(valueAnimator -> {
+ int newAlpha = (int) valueAnimator.getAnimatedValue();
+ int newColor = ColorUtils.setAlphaComponent(placeholderColor, newAlpha);
+
+ newIcon.setColorFilter(new PorterDuffColorFilter(newColor, PorterDuff.Mode.SRC_ATOP));
+ });
+ iconUpdateAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ newIcon.setColorFilter(null);
+ }
+ });
+ iconUpdateAnimation.start();
+ }
+
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/RoundDrawableWrapper.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/RoundDrawableWrapper.java
new file mode 100644
index 000000000..e569c1ea0
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/RoundDrawableWrapper.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.icons;
+
+import android.graphics.Canvas;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableWrapper;
+
+/**
+ * A drawable which clips rounded corner around a child drawable
+ */
+public class RoundDrawableWrapper extends DrawableWrapper {
+
+ private final RectF mTempRect = new RectF();
+ private final Path mClipPath = new Path();
+ private final float mRoundedCornersRadius;
+
+ public RoundDrawableWrapper(Drawable dr, float radius) {
+ super(dr);
+ mRoundedCornersRadius = radius;
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ mTempRect.set(getBounds());
+ mClipPath.reset();
+ mClipPath.addRoundRect(mTempRect, mRoundedCornersRadius,
+ mRoundedCornersRadius, Path.Direction.CCW);
+ super.onBoundsChange(bounds);
+ }
+
+ @Override
+ public final void draw(Canvas canvas) {
+ int saveCount = canvas.save();
+ canvas.clipPath(mClipPath);
+ super.draw(canvas);
+ canvas.restoreToCount(saveCount);
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/ShadowGenerator.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/ShadowGenerator.java
new file mode 100644
index 000000000..e24f353ad
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/ShadowGenerator.java
@@ -0,0 +1,183 @@
+/*
+ * 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 com.android.launcher3.icons;
+
+import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
+
+import android.graphics.Bitmap;
+import android.graphics.BlurMaskFilter;
+import android.graphics.BlurMaskFilter.Blur;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.RectF;
+
+/**
+ * Utility class to add shadows to bitmaps.
+ */
+public class ShadowGenerator {
+
+ public static final boolean ENABLE_SHADOWS = true;
+
+ public static final float BLUR_FACTOR = 1.5f/48;
+
+ // Percent of actual icon size
+ public static final float KEY_SHADOW_DISTANCE = 1f/48;
+ private static final int KEY_SHADOW_ALPHA = 10;
+ // Percent of actual icon size
+ private static final float HALF_DISTANCE = 0.5f;
+ private static final int AMBIENT_SHADOW_ALPHA = 7;
+
+ private final int mIconSize;
+
+ private final Paint mBlurPaint;
+ private final Paint mDrawPaint;
+ private final BlurMaskFilter mDefaultBlurMaskFilter;
+
+ public ShadowGenerator(int iconSize) {
+ mIconSize = iconSize;
+ mBlurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+ mDrawPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+ mDefaultBlurMaskFilter = new BlurMaskFilter(mIconSize * BLUR_FACTOR, Blur.NORMAL);
+ }
+
+ public synchronized void recreateIcon(Bitmap icon, Canvas out) {
+ recreateIcon(icon, mDefaultBlurMaskFilter, AMBIENT_SHADOW_ALPHA, KEY_SHADOW_ALPHA, out);
+ }
+
+ public synchronized void recreateIcon(Bitmap icon, BlurMaskFilter blurMaskFilter,
+ int ambientAlpha, int keyAlpha, Canvas out) {
+ if (ENABLE_SHADOWS) {
+ int[] offset = new int[2];
+ mBlurPaint.setMaskFilter(blurMaskFilter);
+ Bitmap shadow = icon.extractAlpha(mBlurPaint, offset);
+
+ // Draw ambient shadow
+ mDrawPaint.setAlpha(ambientAlpha);
+ out.drawBitmap(shadow, offset[0], offset[1], mDrawPaint);
+
+ // Draw key shadow
+ mDrawPaint.setAlpha(keyAlpha);
+ out.drawBitmap(shadow, offset[0], offset[1] + KEY_SHADOW_DISTANCE * mIconSize,
+ mDrawPaint);
+ }
+
+ // Draw the icon
+ mDrawPaint.setAlpha(255);
+ out.drawBitmap(icon, 0, 0, mDrawPaint);
+ }
+
+ /**
+ * Returns the minimum amount by which an icon with {@param bounds} should be scaled
+ * so that the shadows do not get clipped.
+ */
+ public static float getScaleForBounds(RectF bounds) {
+ float scale = 1;
+
+ if (ENABLE_SHADOWS) {
+ // For top, left & right, we need same space.
+ float minSide = Math.min(Math.min(bounds.left, bounds.right), bounds.top);
+ if (minSide < BLUR_FACTOR) {
+ scale = (HALF_DISTANCE - BLUR_FACTOR) / (HALF_DISTANCE - minSide);
+ }
+
+ float bottomSpace = BLUR_FACTOR + KEY_SHADOW_DISTANCE;
+ if (bounds.bottom < bottomSpace) {
+ scale = Math.min(scale,
+ (HALF_DISTANCE - bottomSpace) / (HALF_DISTANCE - bounds.bottom));
+ }
+ }
+ return scale;
+ }
+
+ public static class Builder {
+
+ public final RectF bounds = new RectF();
+ public final int color;
+
+ public int ambientShadowAlpha = AMBIENT_SHADOW_ALPHA;
+
+ public float shadowBlur;
+
+ public float keyShadowDistance;
+ public int keyShadowAlpha = KEY_SHADOW_ALPHA;
+ public float radius;
+
+ public Builder(int color) {
+ this.color = color;
+ }
+
+ public Builder setupBlurForSize(int height) {
+ if (ENABLE_SHADOWS) {
+ shadowBlur = height * 1f / 24;
+ keyShadowDistance = height * 1f / 16;
+ } else {
+ shadowBlur = 0;
+ keyShadowDistance = 0;
+ }
+ return this;
+ }
+
+ public Bitmap createPill(int width, int height) {
+ return createPill(width, height, height / 2f);
+ }
+
+ public Bitmap createPill(int width, int height, float r) {
+ radius = r;
+
+ int centerX = Math.round(width / 2f + shadowBlur);
+ int centerY = Math.round(radius + shadowBlur + keyShadowDistance);
+ int center = Math.max(centerX, centerY);
+ bounds.set(0, 0, width, height);
+ bounds.offsetTo(center - width / 2f, center - height / 2f);
+
+ int size = center * 2;
+ return BitmapRenderer.createHardwareBitmap(size, size, this::drawShadow);
+ }
+
+ public void drawShadow(Canvas c) {
+ Paint p = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+ p.setColor(color);
+
+ if (ENABLE_SHADOWS) {
+ // Key shadow
+ p.setShadowLayer(shadowBlur, 0, keyShadowDistance,
+ setColorAlphaBound(Color.BLACK, keyShadowAlpha));
+ c.drawRoundRect(bounds, radius, radius, p);
+
+ // Ambient shadow
+ p.setShadowLayer(shadowBlur, 0, 0,
+ setColorAlphaBound(Color.BLACK, ambientShadowAlpha));
+ c.drawRoundRect(bounds, radius, radius, p);
+ }
+
+ if (Color.alpha(color) < 255) {
+ // Clear any content inside the pill-rect for translucent fill.
+ p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+ p.clearShadowLayer();
+ p.setColor(Color.BLACK);
+ c.drawRoundRect(bounds, radius, radius, p);
+
+ p.setXfermode(null);
+ p.setColor(color);
+ c.drawRoundRect(bounds, radius, radius, p);
+ }
+ }
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/ThemedIconDrawable.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/ThemedIconDrawable.java
new file mode 100644
index 000000000..b2e554b7b
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/ThemedIconDrawable.java
@@ -0,0 +1,296 @@
+/*
+ * 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.launcher3.icons;
+
+import static android.content.res.Configuration.UI_MODE_NIGHT_MASK;
+import static android.content.res.Configuration.UI_MODE_NIGHT_YES;
+import static android.content.res.Resources.ID_NULL;
+
+import static com.android.launcher3.icons.GraphicsUtils.getExpectedBitmapSize;
+import static com.android.launcher3.icons.IconProvider.ICON_TYPE_CALENDAR;
+import static com.android.launcher3.icons.IconProvider.ICON_TYPE_CLOCK;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
+import android.os.Process;
+import android.os.UserHandle;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.icons.BitmapInfo.Extender;
+import com.android.launcher3.icons.cache.BaseIconCache;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Class to handle monochrome themed app icons
+ */
+@SuppressWarnings("NewApi")
+public class ThemedIconDrawable extends FastBitmapDrawable {
+
+ public static final String TAG = "ThemedIconDrawable";
+
+ final ThemedBitmapInfo bitmapInfo;
+ final int colorFg, colorBg;
+
+ // The foreground/monochrome icon for the app
+ private final Drawable mMonochromeIcon;
+ private final AdaptiveIconDrawable mBgWrapper;
+ private final Rect mBadgeBounds;
+
+ protected ThemedIconDrawable(ThemedConstantState constantState) {
+ super(constantState.mBitmap, constantState.colorFg, constantState.mIsDisabled);
+ bitmapInfo = constantState.bitmapInfo;
+ colorBg = constantState.colorBg;
+ colorFg = constantState.colorFg;
+
+ mMonochromeIcon = bitmapInfo.mThemeData.loadMonochromeDrawable(colorFg);
+ mBgWrapper = new AdaptiveIconDrawable(new ColorDrawable(colorBg), null);
+ mBadgeBounds = bitmapInfo.mUserBadge == null ? null :
+ new Rect(0, 0, bitmapInfo.mUserBadge.getWidth(), bitmapInfo.mUserBadge.getHeight());
+
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ super.onBoundsChange(bounds);
+ mBgWrapper.setBounds(bounds);
+ mMonochromeIcon.setBounds(bounds);
+ }
+
+ @Override
+ protected void drawInternal(Canvas canvas, Rect bounds) {
+ int count = canvas.save();
+ canvas.scale(bitmapInfo.mNormalizationScale, bitmapInfo.mNormalizationScale,
+ bounds.exactCenterX(), bounds.exactCenterY());
+ mPaint.setColor(colorBg);
+ canvas.drawPath(mBgWrapper.getIconMask(), mPaint);
+ mMonochromeIcon.draw(canvas);
+ canvas.restoreToCount(count);
+ if (mBadgeBounds != null) {
+ canvas.drawBitmap(bitmapInfo.mUserBadge, mBadgeBounds, getBounds(), mPaint);
+ }
+ }
+
+ @Override
+ public boolean isThemed() {
+ return true;
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ return new ThemedConstantState(bitmapInfo, colorBg, colorFg, mIsDisabled);
+ }
+
+ static class ThemedConstantState extends FastBitmapConstantState {
+
+ final ThemedBitmapInfo bitmapInfo;
+ final int colorFg, colorBg;
+
+ public ThemedConstantState(ThemedBitmapInfo bitmapInfo,
+ int colorBg, int colorFg, boolean isDisabled) {
+ super(bitmapInfo.icon, bitmapInfo.color, isDisabled);
+ this.bitmapInfo = bitmapInfo;
+ this.colorBg = colorBg;
+ this.colorFg = colorFg;
+ }
+
+ @Override
+ public FastBitmapDrawable newDrawable() {
+ return new ThemedIconDrawable(this);
+ }
+ }
+
+ public static class ThemedBitmapInfo extends BitmapInfo {
+
+ final ThemeData mThemeData;
+ final float mNormalizationScale;
+ final Bitmap mUserBadge;
+
+ public ThemedBitmapInfo(Bitmap icon, int color, ThemeData themeData,
+ float normalizationScale, Bitmap userBadge) {
+ super(icon, color);
+ mThemeData = themeData;
+ mNormalizationScale = normalizationScale;
+ mUserBadge = userBadge;
+ }
+
+ @Override
+ public FastBitmapDrawable newThemedIcon(Context context) {
+ int[] colors = getColors(context);
+ FastBitmapDrawable drawable = new ThemedConstantState(this, colors[0], colors[1], false)
+ .newDrawable();
+ drawable.mDisabledAlpha = GraphicsUtils.getFloat(context, R.attr.disabledIconAlpha, 1f);
+ return drawable;
+ }
+
+ @Nullable
+ public byte[] toByteArray() {
+ if (isNullOrLowRes()) {
+ return null;
+ }
+ String resName = mThemeData.mResources.getResourceName(mThemeData.mResID);
+ ByteArrayOutputStream out = new ByteArrayOutputStream(
+ getExpectedBitmapSize(icon) + 3 + resName.length());
+ try {
+ DataOutputStream dos = new DataOutputStream(out);
+ dos.writeByte(TYPE_THEMED);
+ dos.writeFloat(mNormalizationScale);
+ dos.writeUTF(resName);
+ icon.compress(Bitmap.CompressFormat.PNG, 100, dos);
+
+ dos.flush();
+ dos.close();
+ return out.toByteArray();
+ } catch (IOException e) {
+ Log.w(TAG, "Could not write bitmap");
+ return null;
+ }
+ }
+
+ static ThemedBitmapInfo decode(byte[] data, int color,
+ BitmapFactory.Options decodeOptions, UserHandle user, BaseIconCache iconCache,
+ Context context) {
+ try (DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data))) {
+ dis.readByte(); // type
+ float normalizationScale = dis.readFloat();
+
+ String resName = dis.readUTF();
+ int resId = context.getResources()
+ .getIdentifier(resName, "drawable", context.getPackageName());
+ if (resId == ID_NULL) {
+ return null;
+ }
+
+ Bitmap userBadgeBitmap = null;
+ if (!Process.myUserHandle().equals(user)) {
+ try (BaseIconFactory iconFactory = iconCache.getIconFactory()) {
+ userBadgeBitmap = iconFactory.getUserBadgeBitmap(user);
+ }
+ }
+
+ ThemeData themeData = new ThemeData(context.getResources(), resId);
+ Bitmap icon = BitmapFactory.decodeStream(dis, null, decodeOptions);
+ return new ThemedBitmapInfo(icon, color, themeData, normalizationScale,
+ userBadgeBitmap);
+ } catch (IOException e) {
+ return null;
+ }
+ }
+ }
+
+ public static class ThemeData {
+
+ final Resources mResources;
+ final int mResID;
+
+ public ThemeData(Resources resources, int resID) {
+ mResources = resources;
+ mResID = resID;
+ }
+
+ Drawable loadMonochromeDrawable(int accentColor) {
+ Drawable d = mResources.getDrawable(mResID).mutate();
+ d.setTint(accentColor);
+ d = new InsetDrawable(d, .2f);
+ return d;
+ }
+
+ public Drawable wrapDrawable(Drawable original, int iconType) {
+ if (!(original instanceof AdaptiveIconDrawable)) {
+ return original;
+ }
+ AdaptiveIconDrawable aid = (AdaptiveIconDrawable) original;
+ String resourceType = mResources.getResourceTypeName(mResID);
+ if (iconType == ICON_TYPE_CALENDAR && "array".equals(resourceType)) {
+ TypedArray ta = mResources.obtainTypedArray(mResID);
+ int id = ta.getResourceId(IconProvider.getDay(), ID_NULL);
+ ta.recycle();
+ return id == ID_NULL ? original
+ : new ThemedAdaptiveIcon(aid, new ThemeData(mResources, id));
+ } else if (iconType == ICON_TYPE_CLOCK && "array".equals(resourceType)) {
+ ((ClockDrawableWrapper) original).mThemeData = this;
+ return original;
+ } else if ("drawable".equals(resourceType)) {
+ return new ThemedAdaptiveIcon(aid, this);
+ } else {
+ return original;
+ }
+ }
+ }
+
+ static class ThemedAdaptiveIcon extends AdaptiveIconDrawable implements Extender {
+
+ protected final ThemeData mThemeData;
+
+ public ThemedAdaptiveIcon(AdaptiveIconDrawable parent, ThemeData themeData) {
+ super(parent.getBackground(), parent.getForeground());
+ mThemeData = themeData;
+ }
+
+ @Override
+ public BitmapInfo getExtendedInfo(Bitmap bitmap, int color, BaseIconFactory iconFactory,
+ float normalizationScale, UserHandle user) {
+ Bitmap userBadge = Process.myUserHandle().equals(user)
+ ? null : iconFactory.getUserBadgeBitmap(user);
+ return new ThemedBitmapInfo(bitmap, color, mThemeData, normalizationScale, userBadge);
+ }
+
+ @Override
+ public void drawForPersistence(Canvas canvas) {
+ draw(canvas);
+ }
+
+ @Override
+ public Drawable getThemedDrawable(Context context) {
+ int[] colors = getColors(context);
+ Drawable bg = new ColorDrawable(colors[0]);
+ float inset = getExtraInsetFraction() / (1 + 2 * getExtraInsetFraction());
+ Drawable fg = new InsetDrawable(mThemeData.loadMonochromeDrawable(colors[1]), inset);
+ return new AdaptiveIconDrawable(bg, fg);
+ }
+ }
+
+ /**
+ * Get an int array representing background and foreground colors for themed icons
+ */
+ public static int[] getColors(Context context) {
+ Resources res = context.getResources();
+ int[] colors = new int[2];
+ if ((res.getConfiguration().uiMode & UI_MODE_NIGHT_MASK) == UI_MODE_NIGHT_YES) {
+ colors[0] = res.getColor(android.R.color.system_neutral1_800);
+ colors[1] = res.getColor(android.R.color.system_accent1_100);
+ } else {
+ colors[0] = res.getColor(android.R.color.system_accent1_100);
+ colors[1] = res.getColor(android.R.color.system_neutral2_700);
+ }
+ return colors;
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
new file mode 100644
index 000000000..d685737c4
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
@@ -0,0 +1,570 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.icons.cache;
+
+import static com.android.launcher3.icons.BaseIconFactory.getFullResDefaultActivityIcon;
+import static com.android.launcher3.icons.BitmapInfo.LOW_RES_ICON;
+import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
+
+import android.content.ComponentName;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteException;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Handler;
+import android.os.LocaleList;
+import android.os.Looper;
+import android.os.Process;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.launcher3.icons.BaseIconFactory;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.SQLiteCacheHelper;
+
+import java.util.AbstractMap;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
+public abstract class BaseIconCache {
+
+ private static final String TAG = "BaseIconCache";
+ private static final boolean DEBUG = false;
+
+ private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
+
+ // Empty class name is used for storing package default entry.
+ public static final String EMPTY_CLASS_NAME = ".";
+
+ public static class CacheEntry {
+
+ @NonNull
+ public BitmapInfo bitmap = BitmapInfo.LOW_RES_INFO;
+ public CharSequence title = "";
+ public CharSequence contentDescription = "";
+ }
+
+ private final HashMap<UserHandle, BitmapInfo> mDefaultIcons = new HashMap<>();
+
+ protected final Context mContext;
+ protected final PackageManager mPackageManager;
+
+ private final Map<ComponentKey, CacheEntry> mCache;
+ protected final Handler mWorkerHandler;
+
+ protected int mIconDpi;
+ protected IconDB mIconDb;
+ protected LocaleList mLocaleList = LocaleList.getEmptyLocaleList();
+ protected String mSystemState = "";
+
+ private final String mDbFileName;
+ private final Looper mBgLooper;
+
+ public BaseIconCache(Context context, String dbFileName, Looper bgLooper,
+ int iconDpi, int iconPixelSize, boolean inMemoryCache) {
+ mContext = context;
+ mDbFileName = dbFileName;
+ mPackageManager = context.getPackageManager();
+ mBgLooper = bgLooper;
+ mWorkerHandler = new Handler(mBgLooper);
+
+ if (inMemoryCache) {
+ mCache = new HashMap<>(INITIAL_ICON_CACHE_CAPACITY);
+ } else {
+ // Use a dummy cache
+ mCache = new AbstractMap<ComponentKey, CacheEntry>() {
+ @Override
+ public Set<Entry<ComponentKey, CacheEntry>> entrySet() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public CacheEntry put(ComponentKey key, CacheEntry value) {
+ return value;
+ }
+ };
+ }
+
+ updateSystemState();
+ mIconDpi = iconDpi;
+ mIconDb = new IconDB(context, dbFileName, iconPixelSize);
+ }
+
+ /**
+ * Returns the persistable serial number for {@param user}. Subclass should implement proper
+ * caching strategy to avoid making binder call every time.
+ */
+ protected abstract long getSerialNumberForUser(UserHandle user);
+
+ /**
+ * Return true if the given app is an instant app and should be badged appropriately.
+ */
+ protected abstract boolean isInstantApp(ApplicationInfo info);
+
+ /**
+ * Opens and returns an icon factory. The factory is recycled by the caller.
+ */
+ public abstract BaseIconFactory getIconFactory();
+
+ public void updateIconParams(int iconDpi, int iconPixelSize) {
+ mWorkerHandler.post(() -> updateIconParamsBg(iconDpi, iconPixelSize));
+ }
+
+ private synchronized void updateIconParamsBg(int iconDpi, int iconPixelSize) {
+ mIconDpi = iconDpi;
+ mDefaultIcons.clear();
+ mIconDb.clear();
+ mIconDb.close();
+ mIconDb = new IconDB(mContext, mDbFileName, iconPixelSize);
+ mCache.clear();
+ }
+
+ private Drawable getFullResIcon(Resources resources, int iconId) {
+ if (resources != null && iconId != 0) {
+ try {
+ return resources.getDrawableForDensity(iconId, mIconDpi);
+ } catch (Resources.NotFoundException e) { }
+ }
+ return getFullResDefaultActivityIcon(mIconDpi);
+ }
+
+ public Drawable getFullResIcon(String packageName, int iconId) {
+ try {
+ return getFullResIcon(mPackageManager.getResourcesForApplication(packageName), iconId);
+ } catch (PackageManager.NameNotFoundException e) { }
+ return getFullResDefaultActivityIcon(mIconDpi);
+ }
+
+ public Drawable getFullResIcon(ActivityInfo info) {
+ try {
+ return getFullResIcon(mPackageManager.getResourcesForApplication(info.applicationInfo),
+ info.getIconResource());
+ } catch (PackageManager.NameNotFoundException e) { }
+ return getFullResDefaultActivityIcon(mIconDpi);
+ }
+
+ private BitmapInfo makeDefaultIcon(UserHandle user) {
+ try (BaseIconFactory li = getIconFactory()) {
+ return li.makeDefaultIcon(user);
+ }
+ }
+
+ /**
+ * Remove any records for the supplied ComponentName.
+ */
+ public synchronized void remove(ComponentName componentName, UserHandle user) {
+ mCache.remove(new ComponentKey(componentName, user));
+ }
+
+ /**
+ * Remove any records for the supplied package name from memory.
+ */
+ private void removeFromMemCacheLocked(String packageName, UserHandle user) {
+ HashSet<ComponentKey> forDeletion = new HashSet<>();
+ for (ComponentKey key: mCache.keySet()) {
+ if (key.componentName.getPackageName().equals(packageName)
+ && key.user.equals(user)) {
+ forDeletion.add(key);
+ }
+ }
+ for (ComponentKey condemned: forDeletion) {
+ mCache.remove(condemned);
+ }
+ }
+
+ /**
+ * Removes the entries related to the given package in memory and persistent DB.
+ */
+ public synchronized void removeIconsForPkg(String packageName, UserHandle user) {
+ removeFromMemCacheLocked(packageName, user);
+ long userSerial = getSerialNumberForUser(user);
+ mIconDb.delete(
+ IconDB.COLUMN_COMPONENT + " LIKE ? AND " + IconDB.COLUMN_USER + " = ?",
+ new String[]{packageName + "/%", Long.toString(userSerial)});
+ }
+
+ public IconCacheUpdateHandler getUpdateHandler() {
+ updateSystemState();
+ return new IconCacheUpdateHandler(this);
+ }
+
+ /**
+ * Refreshes the system state definition used to check the validity of the cache. It
+ * incorporates all the properties that can affect the cache like the list of enabled locale
+ * and system-version.
+ */
+ private void updateSystemState() {
+ mLocaleList = mContext.getResources().getConfiguration().getLocales();
+ mSystemState = mLocaleList.toLanguageTags() + "," + Build.VERSION.SDK_INT;
+ }
+
+ protected String getIconSystemState(String packageName) {
+ return mSystemState;
+ }
+
+ /**
+ * Adds an entry into the DB and the in-memory cache.
+ * @param replaceExisting if true, it will recreate the bitmap even if it already exists in
+ * the memory. This is useful then the previous bitmap was created using
+ * old data.
+ */
+ @VisibleForTesting
+ public synchronized <T> void addIconToDBAndMemCache(T object, CachingLogic<T> cachingLogic,
+ PackageInfo info, long userSerial, boolean replaceExisting) {
+ UserHandle user = cachingLogic.getUser(object);
+ ComponentName componentName = cachingLogic.getComponent(object);
+
+ final ComponentKey key = new ComponentKey(componentName, user);
+ CacheEntry entry = null;
+ if (!replaceExisting) {
+ entry = mCache.get(key);
+ // We can't reuse the entry if the high-res icon is not present.
+ if (entry == null || entry.bitmap.isNullOrLowRes()) {
+ entry = null;
+ }
+ }
+ if (entry == null) {
+ entry = new CacheEntry();
+ entry.bitmap = cachingLogic.loadIcon(mContext, object);
+ }
+ // Icon can't be loaded from cachingLogic, which implies alternative icon was loaded
+ // (e.g. fallback icon, default icon). So we drop here since there's no point in caching
+ // an empty entry.
+ if (entry.bitmap.isNullOrLowRes()) return;
+ entry.title = cachingLogic.getLabel(object);
+ entry.contentDescription = mPackageManager.getUserBadgedLabel(entry.title, user);
+ if (cachingLogic.addToMemCache()) mCache.put(key, entry);
+
+ ContentValues values = newContentValues(entry.bitmap, entry.title.toString(),
+ componentName.getPackageName(), cachingLogic.getKeywords(object, mLocaleList));
+ addIconToDB(values, componentName, info, userSerial,
+ cachingLogic.getLastUpdatedTime(object, info));
+ }
+
+ /**
+ * Updates {@param values} to contain versioning information and adds it to the DB.
+ * @param values {@link ContentValues} containing icon & title
+ */
+ private void addIconToDB(ContentValues values, ComponentName key,
+ PackageInfo info, long userSerial, long lastUpdateTime) {
+ values.put(IconDB.COLUMN_COMPONENT, key.flattenToString());
+ values.put(IconDB.COLUMN_USER, userSerial);
+ values.put(IconDB.COLUMN_LAST_UPDATED, lastUpdateTime);
+ values.put(IconDB.COLUMN_VERSION, info.versionCode);
+ mIconDb.insertOrReplace(values);
+ }
+
+ public synchronized BitmapInfo getDefaultIcon(UserHandle user) {
+ if (!mDefaultIcons.containsKey(user)) {
+ mDefaultIcons.put(user, makeDefaultIcon(user));
+ }
+ return mDefaultIcons.get(user);
+ }
+
+ public boolean isDefaultIcon(BitmapInfo icon, UserHandle user) {
+ return getDefaultIcon(user).icon == icon.icon;
+ }
+
+ /**
+ * Retrieves the entry from the cache. If the entry is not present, it creates a new entry.
+ * This method is not thread safe, it must be called from a synchronized method.
+ */
+ protected <T> CacheEntry cacheLocked(
+ @NonNull ComponentName componentName, @NonNull UserHandle user,
+ @NonNull Supplier<T> infoProvider, @NonNull CachingLogic<T> cachingLogic,
+ boolean usePackageIcon, boolean useLowResIcon) {
+ assertWorkerThread();
+ ComponentKey cacheKey = new ComponentKey(componentName, user);
+ CacheEntry entry = mCache.get(cacheKey);
+ if (entry == null || (entry.bitmap.isLowRes() && !useLowResIcon)) {
+ entry = new CacheEntry();
+ if (cachingLogic.addToMemCache()) {
+ mCache.put(cacheKey, entry);
+ }
+
+ // Check the DB first.
+ T object = null;
+ boolean providerFetchedOnce = false;
+
+ if (!getEntryFromDB(cacheKey, entry, useLowResIcon)) {
+ object = infoProvider.get();
+ providerFetchedOnce = true;
+
+ if (object != null) {
+ entry.bitmap = cachingLogic.loadIcon(mContext, object);
+ } else {
+ if (usePackageIcon) {
+ CacheEntry packageEntry = getEntryForPackageLocked(
+ componentName.getPackageName(), user, false);
+ if (packageEntry != null) {
+ if (DEBUG) Log.d(TAG, "using package default icon for " +
+ componentName.toShortString());
+ entry.bitmap = packageEntry.bitmap;
+ entry.title = packageEntry.title;
+ entry.contentDescription = packageEntry.contentDescription;
+ }
+ }
+ if (entry.bitmap == null) {
+ if (DEBUG) Log.d(TAG, "using default icon for " +
+ componentName.toShortString());
+ entry.bitmap = getDefaultIcon(user);
+ }
+ }
+ }
+
+ if (TextUtils.isEmpty(entry.title)) {
+ if (object == null && !providerFetchedOnce) {
+ object = infoProvider.get();
+ providerFetchedOnce = true;
+ }
+ if (object != null) {
+ entry.title = cachingLogic.getLabel(object);
+ entry.contentDescription = mPackageManager.getUserBadgedLabel(
+ cachingLogic.getDescription(object, entry.title), user);
+ }
+ }
+ }
+ return entry;
+ }
+
+ public synchronized void clear() {
+ assertWorkerThread();
+ mIconDb.clear();
+ }
+
+ /**
+ * Adds a default package entry in the cache. This entry is not persisted and will be removed
+ * when the cache is flushed.
+ */
+ protected synchronized void cachePackageInstallInfo(String packageName, UserHandle user,
+ Bitmap icon, CharSequence title) {
+ removeFromMemCacheLocked(packageName, user);
+
+ ComponentKey cacheKey = getPackageKey(packageName, user);
+ CacheEntry entry = mCache.get(cacheKey);
+
+ // For icon caching, do not go through DB. Just update the in-memory entry.
+ if (entry == null) {
+ entry = new CacheEntry();
+ }
+ if (!TextUtils.isEmpty(title)) {
+ entry.title = title;
+ }
+ if (icon != null) {
+ BaseIconFactory li = getIconFactory();
+ entry.bitmap = li.createShapedIconBitmap(icon, user);
+ li.close();
+ }
+ if (!TextUtils.isEmpty(title) && entry.bitmap.icon != null) {
+ mCache.put(cacheKey, entry);
+ }
+ }
+
+ private static ComponentKey getPackageKey(String packageName, UserHandle user) {
+ ComponentName cn = new ComponentName(packageName, packageName + EMPTY_CLASS_NAME);
+ return new ComponentKey(cn, user);
+ }
+
+ /**
+ * Gets an entry for the package, which can be used as a fallback entry for various components.
+ * This method is not thread safe, it must be called from a synchronized method.
+ */
+ protected CacheEntry getEntryForPackageLocked(String packageName, UserHandle user,
+ boolean useLowResIcon) {
+ assertWorkerThread();
+ ComponentKey cacheKey = getPackageKey(packageName, user);
+ CacheEntry entry = mCache.get(cacheKey);
+
+ if (entry == null || (entry.bitmap.isLowRes() && !useLowResIcon)) {
+ entry = new CacheEntry();
+ boolean entryUpdated = true;
+
+ // Check the DB first.
+ if (!getEntryFromDB(cacheKey, entry, useLowResIcon)) {
+ try {
+ int flags = Process.myUserHandle().equals(user) ? 0 :
+ PackageManager.GET_UNINSTALLED_PACKAGES;
+ PackageInfo info = mPackageManager.getPackageInfo(packageName, flags);
+ ApplicationInfo appInfo = info.applicationInfo;
+ if (appInfo == null) {
+ throw new NameNotFoundException("ApplicationInfo is null");
+ }
+
+ BaseIconFactory li = getIconFactory();
+ // Load the full res icon for the application, but if useLowResIcon is set, then
+ // only keep the low resolution icon instead of the larger full-sized icon
+ BitmapInfo iconInfo = li.createBadgedIconBitmap(
+ appInfo.loadIcon(mPackageManager), user, appInfo.targetSdkVersion,
+ isInstantApp(appInfo));
+ li.close();
+
+ entry.title = appInfo.loadLabel(mPackageManager);
+ entry.contentDescription = mPackageManager.getUserBadgedLabel(entry.title, user);
+ entry.bitmap = BitmapInfo.of(
+ useLowResIcon ? LOW_RES_ICON : iconInfo.icon, iconInfo.color);
+
+ // Add the icon in the DB here, since these do not get written during
+ // package updates.
+ ContentValues values = newContentValues(
+ iconInfo, entry.title.toString(), packageName, null);
+ addIconToDB(values, cacheKey.componentName, info, getSerialNumberForUser(user),
+ info.lastUpdateTime);
+
+ } catch (NameNotFoundException e) {
+ if (DEBUG) Log.d(TAG, "Application not installed " + packageName);
+ entryUpdated = false;
+ }
+ }
+
+ // Only add a filled-out entry to the cache
+ if (entryUpdated) {
+ mCache.put(cacheKey, entry);
+ }
+ }
+ return entry;
+ }
+
+ protected boolean getEntryFromDB(ComponentKey cacheKey, CacheEntry entry, boolean lowRes) {
+ Cursor c = null;
+ try {
+ c = mIconDb.query(
+ lowRes ? IconDB.COLUMNS_LOW_RES : IconDB.COLUMNS_HIGH_RES,
+ IconDB.COLUMN_COMPONENT + " = ? AND " + IconDB.COLUMN_USER + " = ?",
+ new String[]{
+ cacheKey.componentName.flattenToString(),
+ Long.toString(getSerialNumberForUser(cacheKey.user))});
+ if (c.moveToNext()) {
+ // Set the alpha to be 255, so that we never have a wrong color
+ entry.bitmap = BitmapInfo.of(LOW_RES_ICON, setColorAlphaBound(c.getInt(0), 255));
+ entry.title = c.getString(1);
+ if (entry.title == null) {
+ entry.title = "";
+ entry.contentDescription = "";
+ } else {
+ entry.contentDescription = mPackageManager.getUserBadgedLabel(
+ entry.title, cacheKey.user);
+ }
+
+ if (!lowRes) {
+ try {
+ entry.bitmap = BitmapInfo.fromByteArray(
+ c.getBlob(2), entry.bitmap.color, cacheKey.user, this, mContext);
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ return entry.bitmap != null;
+ }
+ } catch (SQLiteException e) {
+ Log.d(TAG, "Error reading icon cache", e);
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns a cursor for an arbitrary query to the cache db
+ */
+ public synchronized Cursor queryCacheDb(String[] columns, String selection,
+ String[] selectionArgs) {
+ return mIconDb.query(columns, selection, selectionArgs);
+ }
+
+ /**
+ * Cache class to store the actual entries on disk
+ */
+ public static final class IconDB extends SQLiteCacheHelper {
+ private static final int RELEASE_VERSION = 31;
+
+ public static final String TABLE_NAME = "icons";
+ public static final String COLUMN_ROWID = "rowid";
+ public static final String COLUMN_COMPONENT = "componentName";
+ public static final String COLUMN_USER = "profileId";
+ public static final String COLUMN_LAST_UPDATED = "lastUpdated";
+ public static final String COLUMN_VERSION = "version";
+ public static final String COLUMN_ICON = "icon";
+ public static final String COLUMN_ICON_COLOR = "icon_color";
+ public static final String COLUMN_LABEL = "label";
+ public static final String COLUMN_SYSTEM_STATE = "system_state";
+ public static final String COLUMN_KEYWORDS = "keywords";
+
+ public static final String[] COLUMNS_HIGH_RES = new String[] {
+ IconDB.COLUMN_ICON_COLOR, IconDB.COLUMN_LABEL, IconDB.COLUMN_ICON };
+ public static final String[] COLUMNS_LOW_RES = new String[] {
+ IconDB.COLUMN_ICON_COLOR, IconDB.COLUMN_LABEL };
+
+ public IconDB(Context context, String dbFileName, int iconPixelSize) {
+ super(context, dbFileName, (RELEASE_VERSION << 16) + iconPixelSize, TABLE_NAME);
+ }
+
+ @Override
+ protected void onCreateTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " ("
+ + COLUMN_COMPONENT + " TEXT NOT NULL, "
+ + COLUMN_USER + " INTEGER NOT NULL, "
+ + COLUMN_LAST_UPDATED + " INTEGER NOT NULL DEFAULT 0, "
+ + COLUMN_VERSION + " INTEGER NOT NULL DEFAULT 0, "
+ + COLUMN_ICON + " BLOB, "
+ + COLUMN_ICON_COLOR + " INTEGER NOT NULL DEFAULT 0, "
+ + COLUMN_LABEL + " TEXT, "
+ + COLUMN_SYSTEM_STATE + " TEXT, "
+ + COLUMN_KEYWORDS + " TEXT, "
+ + "PRIMARY KEY (" + COLUMN_COMPONENT + ", " + COLUMN_USER + ") "
+ + ");");
+ }
+ }
+
+ private ContentValues newContentValues(BitmapInfo bitmapInfo, String label,
+ String packageName, @Nullable String keywords) {
+ ContentValues values = new ContentValues();
+ values.put(IconDB.COLUMN_ICON, bitmapInfo.toByteArray());
+ values.put(IconDB.COLUMN_ICON_COLOR, bitmapInfo.color);
+
+ values.put(IconDB.COLUMN_LABEL, label);
+ values.put(IconDB.COLUMN_SYSTEM_STATE, getIconSystemState(packageName));
+ values.put(IconDB.COLUMN_KEYWORDS, keywords);
+ return values;
+ }
+
+ private void assertWorkerThread() {
+ if (Looper.myLooper() != mBgLooper) {
+ throw new IllegalStateException("Cache accessed on wrong thread " + Looper.myLooper());
+ }
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java
new file mode 100644
index 000000000..c12e9dcc1
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.icons.cache;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.os.LocaleList;
+import android.os.UserHandle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.icons.BitmapInfo;
+
+public interface CachingLogic<T> {
+
+ ComponentName getComponent(T object);
+
+ UserHandle getUser(T object);
+
+ CharSequence getLabel(T object);
+
+ default CharSequence getDescription(T object, CharSequence fallback) {
+ return fallback;
+ }
+
+ @NonNull
+ BitmapInfo loadIcon(Context context, T object);
+
+ /**
+ * Provides a option list of keywords to associate with this object
+ */
+ @Nullable
+ default String getKeywords(T object, LocaleList localeList) {
+ return null;
+ }
+
+ /**
+ * Returns the timestamp the entry was last updated in cache.
+ */
+ default long getLastUpdatedTime(T object, PackageInfo info) {
+ return info.lastUpdateTime;
+ }
+
+ /**
+ * Returns true the object should be added to mem cache; otherwise returns false.
+ */
+ default boolean addToMemCache() {
+ return true;
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/cache/HandlerRunnable.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/cache/HandlerRunnable.java
new file mode 100644
index 000000000..3dfb3840f
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/cache/HandlerRunnable.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.icons.cache;
+
+import android.os.Handler;
+
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * A runnable that can be posted to a {@link Handler} which can be canceled.
+ */
+public class HandlerRunnable<T> implements Runnable {
+
+ private final Handler mWorkerHandler;
+ private final Supplier<T> mTask;
+
+ private final Executor mCallbackExecutor;
+ private final Consumer<T> mCallback;
+ private final Runnable mEndRunnable;
+
+ private boolean mEnded = false;
+ private boolean mCanceled = false;
+
+ public HandlerRunnable(Handler workerHandler, Supplier<T> task, Executor callbackExecutor,
+ Consumer<T> callback) {
+ this(workerHandler, task, callbackExecutor, callback, () -> { });
+ }
+
+ public HandlerRunnable(Handler workerHandler, Supplier<T> task, Executor callbackExecutor,
+ Consumer<T> callback, Runnable endRunnable) {
+ mWorkerHandler = workerHandler;
+ mTask = task;
+ mCallbackExecutor = callbackExecutor;
+ mCallback = callback;
+ mEndRunnable = endRunnable;
+ }
+
+ /**
+ * Cancels this runnable from being run, only if it has not already run.
+ */
+ public void cancel() {
+ mWorkerHandler.removeCallbacks(this);
+ mCanceled = true;
+ mCallbackExecutor.execute(this::onEnd);
+ }
+
+ @Override
+ public void run() {
+ T value = mTask.get();
+ mCallbackExecutor.execute(() -> {
+ if (!mCanceled) {
+ mCallback.accept(value);
+ }
+ onEnd();
+ });
+ }
+
+ private void onEnd() {
+ if (!mEnded) {
+ mEnded = true;
+ mEndRunnable.run();
+ }
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java
new file mode 100644
index 000000000..9e1ad7b7b
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.icons.cache;
+
+import android.content.ComponentName;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.SparseBooleanArray;
+
+import com.android.launcher3.icons.cache.BaseIconCache.IconDB;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.Stack;
+
+/**
+ * Utility class to handle updating the Icon cache
+ */
+public class IconCacheUpdateHandler {
+
+ private static final String TAG = "IconCacheUpdateHandler";
+
+ /**
+ * In this mode, all invalid icons are marked as to-be-deleted in {@link #mItemsToDelete}.
+ * This mode is used for the first run.
+ */
+ private static final boolean MODE_SET_INVALID_ITEMS = true;
+
+ /**
+ * In this mode, any valid icon is removed from {@link #mItemsToDelete}. This is used for all
+ * subsequent runs, which essentially acts as set-union of all valid items.
+ */
+ private static final boolean MODE_CLEAR_VALID_ITEMS = false;
+
+ private static final Object ICON_UPDATE_TOKEN = new Object();
+
+ private final HashMap<String, PackageInfo> mPkgInfoMap;
+ private final BaseIconCache mIconCache;
+
+ private final ArrayMap<UserHandle, Set<String>> mPackagesToIgnore = new ArrayMap<>();
+
+ private final SparseBooleanArray mItemsToDelete = new SparseBooleanArray();
+ private boolean mFilterMode = MODE_SET_INVALID_ITEMS;
+
+ IconCacheUpdateHandler(BaseIconCache cache) {
+ mIconCache = cache;
+
+ mPkgInfoMap = new HashMap<>();
+
+ // Remove all active icon update tasks.
+ mIconCache.mWorkerHandler.removeCallbacksAndMessages(ICON_UPDATE_TOKEN);
+
+ createPackageInfoMap();
+ }
+
+ /**
+ * Sets a package to ignore for processing
+ */
+ public void addPackagesToIgnore(UserHandle userHandle, String packageName) {
+ Set<String> packages = mPackagesToIgnore.get(userHandle);
+ if (packages == null) {
+ packages = new HashSet<>();
+ mPackagesToIgnore.put(userHandle, packages);
+ }
+ packages.add(packageName);
+ }
+
+ private void createPackageInfoMap() {
+ PackageManager pm = mIconCache.mPackageManager;
+ for (PackageInfo info :
+ pm.getInstalledPackages(PackageManager.MATCH_UNINSTALLED_PACKAGES)) {
+ mPkgInfoMap.put(info.packageName, info);
+ }
+ }
+
+ /**
+ * Updates the persistent DB, such that only entries corresponding to {@param apps} remain in
+ * the DB and are updated.
+ * @return The set of packages for which icons have updated.
+ */
+ public <T> void updateIcons(List<T> apps, CachingLogic<T> cachingLogic,
+ OnUpdateCallback onUpdateCallback) {
+ // Filter the list per user
+ HashMap<UserHandle, HashMap<ComponentName, T>> userComponentMap = new HashMap<>();
+ int count = apps.size();
+ for (int i = 0; i < count; i++) {
+ T app = apps.get(i);
+ UserHandle userHandle = cachingLogic.getUser(app);
+ HashMap<ComponentName, T> componentMap = userComponentMap.get(userHandle);
+ if (componentMap == null) {
+ componentMap = new HashMap<>();
+ userComponentMap.put(userHandle, componentMap);
+ }
+ componentMap.put(cachingLogic.getComponent(app), app);
+ }
+
+ for (Entry<UserHandle, HashMap<ComponentName, T>> entry : userComponentMap.entrySet()) {
+ updateIconsPerUser(entry.getKey(), entry.getValue(), cachingLogic, onUpdateCallback);
+ }
+
+ // From now on, clear every valid item from the global valid map.
+ mFilterMode = MODE_CLEAR_VALID_ITEMS;
+ }
+
+ /**
+ * Updates the persistent DB, such that only entries corresponding to {@param apps} remain in
+ * the DB and are updated.
+ * @return The set of packages for which icons have updated.
+ */
+ @SuppressWarnings("unchecked")
+ private <T> void updateIconsPerUser(UserHandle user, HashMap<ComponentName, T> componentMap,
+ CachingLogic<T> cachingLogic, OnUpdateCallback onUpdateCallback) {
+ Set<String> ignorePackages = mPackagesToIgnore.get(user);
+ if (ignorePackages == null) {
+ ignorePackages = Collections.emptySet();
+ }
+ long userSerial = mIconCache.getSerialNumberForUser(user);
+
+ Stack<T> appsToUpdate = new Stack<>();
+
+ try (Cursor c = mIconCache.mIconDb.query(
+ new String[]{IconDB.COLUMN_ROWID, IconDB.COLUMN_COMPONENT,
+ IconDB.COLUMN_LAST_UPDATED, IconDB.COLUMN_VERSION,
+ IconDB.COLUMN_SYSTEM_STATE},
+ IconDB.COLUMN_USER + " = ? ",
+ new String[]{Long.toString(userSerial)})) {
+
+ final int indexComponent = c.getColumnIndex(IconDB.COLUMN_COMPONENT);
+ final int indexLastUpdate = c.getColumnIndex(IconDB.COLUMN_LAST_UPDATED);
+ final int indexVersion = c.getColumnIndex(IconDB.COLUMN_VERSION);
+ final int rowIndex = c.getColumnIndex(IconDB.COLUMN_ROWID);
+ final int systemStateIndex = c.getColumnIndex(IconDB.COLUMN_SYSTEM_STATE);
+
+ while (c.moveToNext()) {
+ String cn = c.getString(indexComponent);
+ ComponentName component = ComponentName.unflattenFromString(cn);
+ PackageInfo info = mPkgInfoMap.get(component.getPackageName());
+
+ int rowId = c.getInt(rowIndex);
+ if (info == null) {
+ if (!ignorePackages.contains(component.getPackageName())) {
+
+ if (mFilterMode == MODE_SET_INVALID_ITEMS) {
+ mIconCache.remove(component, user);
+ mItemsToDelete.put(rowId, true);
+ }
+ }
+ continue;
+ }
+ if ((info.applicationInfo.flags & ApplicationInfo.FLAG_IS_DATA_ONLY) != 0) {
+ // Application is not present
+ continue;
+ }
+
+ long updateTime = c.getLong(indexLastUpdate);
+ int version = c.getInt(indexVersion);
+ T app = componentMap.remove(component);
+ if (version == info.versionCode && updateTime == info.lastUpdateTime
+ && TextUtils.equals(c.getString(systemStateIndex),
+ mIconCache.getIconSystemState(info.packageName))) {
+
+ if (mFilterMode == MODE_CLEAR_VALID_ITEMS) {
+ mItemsToDelete.put(rowId, false);
+ }
+ continue;
+ }
+
+ if (app == null) {
+ if (mFilterMode == MODE_SET_INVALID_ITEMS) {
+ mIconCache.remove(component, user);
+ mItemsToDelete.put(rowId, true);
+ }
+ } else {
+ appsToUpdate.add(app);
+ }
+ }
+ } catch (SQLiteException e) {
+ Log.d(TAG, "Error reading icon cache", e);
+ // Continue updating whatever we have read so far
+ }
+
+ // Insert remaining apps.
+ if (!componentMap.isEmpty() || !appsToUpdate.isEmpty()) {
+ Stack<T> appsToAdd = new Stack<>();
+ appsToAdd.addAll(componentMap.values());
+ new SerializedIconUpdateTask(userSerial, user, appsToAdd, appsToUpdate, cachingLogic,
+ onUpdateCallback).scheduleNext();
+ }
+ }
+
+ /**
+ * Commits all updates as part of the update handler to disk. Not more calls should be made
+ * to this class after this.
+ */
+ public void finish() {
+ // Commit all deletes
+ int deleteCount = 0;
+ StringBuilder queryBuilder = new StringBuilder()
+ .append(IconDB.COLUMN_ROWID)
+ .append(" IN (");
+
+ int count = mItemsToDelete.size();
+ for (int i = 0; i < count; i++) {
+ if (mItemsToDelete.valueAt(i)) {
+ if (deleteCount > 0) {
+ queryBuilder.append(", ");
+ }
+ queryBuilder.append(mItemsToDelete.keyAt(i));
+ deleteCount++;
+ }
+ }
+ queryBuilder.append(')');
+
+ if (deleteCount > 0) {
+ mIconCache.mIconDb.delete(queryBuilder.toString(), null);
+ }
+ }
+
+ /**
+ * A runnable that updates invalid icons and adds missing icons in the DB for the provided
+ * LauncherActivityInfo list. Items are updated/added one at a time, so that the
+ * worker thread doesn't get blocked.
+ */
+ private class SerializedIconUpdateTask<T> implements Runnable {
+ private final long mUserSerial;
+ private final UserHandle mUserHandle;
+ private final Stack<T> mAppsToAdd;
+ private final Stack<T> mAppsToUpdate;
+ private final CachingLogic<T> mCachingLogic;
+ private final HashSet<String> mUpdatedPackages = new HashSet<>();
+ private final OnUpdateCallback mOnUpdateCallback;
+
+ SerializedIconUpdateTask(long userSerial, UserHandle userHandle,
+ Stack<T> appsToAdd, Stack<T> appsToUpdate, CachingLogic<T> cachingLogic,
+ OnUpdateCallback onUpdateCallback) {
+ mUserHandle = userHandle;
+ mUserSerial = userSerial;
+ mAppsToAdd = appsToAdd;
+ mAppsToUpdate = appsToUpdate;
+ mCachingLogic = cachingLogic;
+ mOnUpdateCallback = onUpdateCallback;
+ }
+
+ @Override
+ public void run() {
+ if (!mAppsToUpdate.isEmpty()) {
+ T app = mAppsToUpdate.pop();
+ String pkg = mCachingLogic.getComponent(app).getPackageName();
+ PackageInfo info = mPkgInfoMap.get(pkg);
+
+ mIconCache.addIconToDBAndMemCache(
+ app, mCachingLogic, info, mUserSerial, true /*replace existing*/);
+ mUpdatedPackages.add(pkg);
+
+ if (mAppsToUpdate.isEmpty() && !mUpdatedPackages.isEmpty()) {
+ // No more app to update. Notify callback.
+ mOnUpdateCallback.onPackageIconsUpdated(mUpdatedPackages, mUserHandle);
+ }
+
+ // Let it run one more time.
+ scheduleNext();
+ } else if (!mAppsToAdd.isEmpty()) {
+ T app = mAppsToAdd.pop();
+ PackageInfo info = mPkgInfoMap.get(mCachingLogic.getComponent(app).getPackageName());
+ // We do not check the mPkgInfoMap when generating the mAppsToAdd. Although every
+ // app should have package info, this is not guaranteed by the api
+ if (info != null) {
+ mIconCache.addIconToDBAndMemCache(app, mCachingLogic, info,
+ mUserSerial, false /*replace existing*/);
+ }
+
+ if (!mAppsToAdd.isEmpty()) {
+ scheduleNext();
+ }
+ }
+ }
+
+ public void scheduleNext() {
+ mIconCache.mWorkerHandler.postAtTime(this, ICON_UPDATE_TOKEN,
+ SystemClock.uptimeMillis() + 1);
+ }
+ }
+
+ public interface OnUpdateCallback {
+
+ void onPackageIconsUpdated(HashSet<String> updatedPackages, UserHandle user);
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/util/ComponentKey.java b/PermissionController/iconloaderlib/src/com/android/launcher3/util/ComponentKey.java
new file mode 100644
index 000000000..71451031d
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/util/ComponentKey.java
@@ -0,0 +1,84 @@
+package com.android.launcher3.util;
+
+/**
+ * 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.
+ */
+
+import android.content.ComponentName;
+import android.os.UserHandle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.Arrays;
+
+public class ComponentKey {
+
+ public final ComponentName componentName;
+ public final UserHandle user;
+
+ private final int mHashCode;
+
+ public ComponentKey(ComponentName componentName, UserHandle user) {
+ if (componentName == null || user == null) {
+ throw new NullPointerException();
+ }
+ this.componentName = componentName;
+ this.user = user;
+ mHashCode = Arrays.hashCode(new Object[] {componentName, user});
+
+ }
+
+ @Override
+ public int hashCode() {
+ return mHashCode;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ ComponentKey other = (ComponentKey) o;
+ return other.componentName.equals(componentName) && other.user.equals(user);
+ }
+
+ /**
+ * Encodes a component key as a string of the form [flattenedComponentString#userId].
+ */
+ @Override
+ public String toString() {
+ return componentName.flattenToString() + "#" + user.hashCode();
+ }
+
+ /**
+ * Parses and returns ComponentKey objected from string representation
+ * Returns null if string is not properly formatted
+ */
+ @Nullable
+ public static ComponentKey fromString(@NonNull String str) {
+ int sep = str.indexOf('#');
+ if (sep < 0 || (sep + 1) >= str.length()) {
+ return null;
+ }
+ ComponentName componentName = ComponentName.unflattenFromString(str.substring(0, sep));
+ if (componentName == null) {
+ return null;
+ }
+ try {
+ return new ComponentKey(componentName,
+ UserHandle.getUserHandleForUid(Integer.parseInt(str.substring(sep + 1))));
+ } catch (NumberFormatException ex) {
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/util/NoLocaleSQLiteHelper.java b/PermissionController/iconloaderlib/src/com/android/launcher3/util/NoLocaleSQLiteHelper.java
new file mode 100644
index 000000000..fe864a284
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/util/NoLocaleSQLiteHelper.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import static android.database.sqlite.SQLiteDatabase.NO_LOCALIZED_COLLATORS;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.database.DatabaseErrorHandler;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteDatabase.CursorFactory;
+import android.database.sqlite.SQLiteDatabase.OpenParams;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.os.Build;
+
+/**
+ * Extension of {@link SQLiteOpenHelper} which avoids creating default locale table by
+ * A context wrapper which creates databases without support for localized collators.
+ */
+public abstract class NoLocaleSQLiteHelper extends SQLiteOpenHelper {
+
+ private static final boolean ATLEAST_P =
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
+
+ public NoLocaleSQLiteHelper(Context context, String name, int version) {
+ super(ATLEAST_P ? context : new NoLocalContext(context), name, null, version);
+ if (ATLEAST_P) {
+ setOpenParams(new OpenParams.Builder().addOpenFlags(NO_LOCALIZED_COLLATORS).build());
+ }
+ }
+
+ private static class NoLocalContext extends ContextWrapper {
+ public NoLocalContext(Context base) {
+ super(base);
+ }
+
+ @Override
+ public SQLiteDatabase openOrCreateDatabase(
+ String name, int mode, CursorFactory factory, DatabaseErrorHandler errorHandler) {
+ return super.openOrCreateDatabase(
+ name, mode | Context.MODE_NO_LOCALIZED_COLLATORS, factory, errorHandler);
+ }
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/util/SQLiteCacheHelper.java b/PermissionController/iconloaderlib/src/com/android/launcher3/util/SQLiteCacheHelper.java
new file mode 100644
index 000000000..49de4bd1b
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/util/SQLiteCacheHelper.java
@@ -0,0 +1,125 @@
+package com.android.launcher3.util;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteException;
+import android.database.sqlite.SQLiteFullException;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Log;
+
+/**
+ * An extension of {@link SQLiteOpenHelper} with utility methods for a single table cache DB.
+ * Any exception during write operations are ignored, and any version change causes a DB reset.
+ */
+public abstract class SQLiteCacheHelper {
+ private static final String TAG = "SQLiteCacheHelper";
+
+ private static final boolean IN_MEMORY_CACHE = false;
+
+ private final String mTableName;
+ private final MySQLiteOpenHelper mOpenHelper;
+
+ private boolean mIgnoreWrites;
+
+ public SQLiteCacheHelper(Context context, String name, int version, String tableName) {
+ if (IN_MEMORY_CACHE) {
+ name = null;
+ }
+ mTableName = tableName;
+ mOpenHelper = new MySQLiteOpenHelper(context, name, version);
+
+ mIgnoreWrites = false;
+ }
+
+ /**
+ * @see SQLiteDatabase#delete(String, String, String[])
+ */
+ public void delete(String whereClause, String[] whereArgs) {
+ if (mIgnoreWrites) {
+ return;
+ }
+ try {
+ mOpenHelper.getWritableDatabase().delete(mTableName, whereClause, whereArgs);
+ } catch (SQLiteFullException e) {
+ onDiskFull(e);
+ } catch (SQLiteException e) {
+ Log.d(TAG, "Ignoring sqlite exception", e);
+ }
+ }
+
+ /**
+ * @see SQLiteDatabase#insertWithOnConflict(String, String, ContentValues, int)
+ */
+ public void insertOrReplace(ContentValues values) {
+ if (mIgnoreWrites) {
+ return;
+ }
+ try {
+ mOpenHelper.getWritableDatabase().insertWithOnConflict(
+ mTableName, null, values, SQLiteDatabase.CONFLICT_REPLACE);
+ } catch (SQLiteFullException e) {
+ onDiskFull(e);
+ } catch (SQLiteException e) {
+ Log.d(TAG, "Ignoring sqlite exception", e);
+ }
+ }
+
+ private void onDiskFull(SQLiteFullException e) {
+ Log.e(TAG, "Disk full, all write operations will be ignored", e);
+ mIgnoreWrites = true;
+ }
+
+ /**
+ * @see SQLiteDatabase#query(String, String[], String, String[], String, String, String)
+ */
+ public Cursor query(String[] columns, String selection, String[] selectionArgs) {
+ return mOpenHelper.getReadableDatabase().query(
+ mTableName, columns, selection, selectionArgs, null, null, null);
+ }
+
+ public void clear() {
+ mOpenHelper.clearDB(mOpenHelper.getWritableDatabase());
+ }
+
+ public void close() {
+ mOpenHelper.close();
+ }
+
+ protected abstract void onCreateTable(SQLiteDatabase db);
+
+ /**
+ * A private inner class to prevent direct DB access.
+ */
+ private class MySQLiteOpenHelper extends NoLocaleSQLiteHelper {
+
+ public MySQLiteOpenHelper(Context context, String name, int version) {
+ super(context, name, version);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ onCreateTable(db);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ if (oldVersion != newVersion) {
+ clearDB(db);
+ }
+ }
+
+ @Override
+ public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ if (oldVersion != newVersion) {
+ clearDB(db);
+ }
+ }
+
+ private void clearDB(SQLiteDatabase db) {
+ db.execSQL("DROP TABLE IF EXISTS " + mTableName);
+ onCreate(db);
+ }
+ }
+}
diff --git a/PermissionController/iconloaderlib/src/com/android/launcher3/util/SafeCloseable.java b/PermissionController/iconloaderlib/src/com/android/launcher3/util/SafeCloseable.java
new file mode 100644
index 000000000..ba8ee04d2
--- /dev/null
+++ b/PermissionController/iconloaderlib/src/com/android/launcher3/util/SafeCloseable.java
@@ -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 com.android.launcher3.util;
+
+/**
+ * Extension of closeable which does not throw an exception
+ */
+public interface SafeCloseable extends AutoCloseable {
+
+ @Override
+ void close();
+}
diff --git a/PermissionController/iconloaderlib/src_full_lib/com/android/launcher3/icons/IconFactory.java b/PermissionController/iconloaderlib/src_full_lib/com/android/launcher3/icons/IconFactory.java
new file mode 100644
index 000000000..48f11fde3
--- /dev/null
+++ b/PermissionController/iconloaderlib/src_full_lib/com/android/launcher3/icons/IconFactory.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.icons;
+
+import android.content.Context;
+
+/**
+ * Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class
+ * that are threadsafe.
+ */
+public class IconFactory extends BaseIconFactory {
+
+ private static final Object sPoolSync = new Object();
+ private static IconFactory sPool;
+ private static int sPoolId = 0;
+
+ /**
+ * Return a new Message instance from the global pool. Allows us to
+ * avoid allocating new objects in many cases.
+ */
+ public static IconFactory obtain(Context context) {
+ int poolId;
+ synchronized (sPoolSync) {
+ if (sPool != null) {
+ IconFactory m = sPool;
+ sPool = m.next;
+ m.next = null;
+ return m;
+ }
+ poolId = sPoolId;
+ }
+
+ return new IconFactory(context,
+ context.getResources().getConfiguration().densityDpi,
+ context.getResources().getDimensionPixelSize(R.dimen.default_icon_bitmap_size),
+ poolId);
+ }
+
+ public static void clearPool() {
+ synchronized (sPoolSync) {
+ sPool = null;
+ sPoolId++;
+ }
+ }
+
+ private final int mPoolId;
+
+ private IconFactory next;
+
+ private IconFactory(Context context, int fillResIconDpi, int iconBitmapSize, int poolId) {
+ super(context, fillResIconDpi, iconBitmapSize);
+ mPoolId = poolId;
+ }
+
+ /**
+ * Recycles a LauncherIcons that may be in-use.
+ */
+ public void recycle() {
+ synchronized (sPoolSync) {
+ if (sPoolId != mPoolId) {
+ return;
+ }
+ // Clear any temporary state variables
+ clear();
+
+ next = sPool;
+ sPool = this;
+ }
+ }
+
+ @Override
+ public void close() {
+ recycle();
+ }
+}
diff --git a/PermissionController/iconloaderlib/src_full_lib/com/android/launcher3/icons/SimpleIconCache.java b/PermissionController/iconloaderlib/src_full_lib/com/android/launcher3/icons/SimpleIconCache.java
new file mode 100644
index 000000000..cc4ad7b0b
--- /dev/null
+++ b/PermissionController/iconloaderlib/src_full_lib/com/android/launcher3/icons/SimpleIconCache.java
@@ -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 com.android.launcher3.icons;
+
+import static android.content.Intent.ACTION_MANAGED_PROFILE_ADDED;
+import static android.content.Intent.ACTION_MANAGED_PROFILE_REMOVED;
+
+import android.annotation.TargetApi;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.SparseLongArray;
+
+import com.android.launcher3.icons.cache.BaseIconCache;
+
+/**
+ * Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class
+ * that are threadsafe.
+ */
+@TargetApi(Build.VERSION_CODES.P)
+public class SimpleIconCache extends BaseIconCache {
+
+ private static SimpleIconCache sIconCache = null;
+ private static final Object CACHE_LOCK = new Object();
+
+ private final SparseLongArray mUserSerialMap = new SparseLongArray(2);
+ private final UserManager mUserManager;
+
+ public SimpleIconCache(Context context, String dbFileName, Looper bgLooper, int iconDpi,
+ int iconPixelSize, boolean inMemoryCache) {
+ super(context, dbFileName, bgLooper, iconDpi, iconPixelSize, inMemoryCache);
+ mUserManager = context.getSystemService(UserManager.class);
+
+ // Listen for user cache changes.
+ IntentFilter filter = new IntentFilter(ACTION_MANAGED_PROFILE_ADDED);
+ filter.addAction(ACTION_MANAGED_PROFILE_REMOVED);
+ context.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ resetUserCache();
+ }
+ }, filter, null, new Handler(bgLooper), 0);
+ }
+
+ @Override
+ protected long getSerialNumberForUser(UserHandle user) {
+ synchronized (mUserSerialMap) {
+ int index = mUserSerialMap.indexOfKey(user.getIdentifier());
+ if (index >= 0) {
+ return mUserSerialMap.valueAt(index);
+ }
+ long serial = mUserManager.getSerialNumberForUser(user);
+ mUserSerialMap.put(user.getIdentifier(), serial);
+ return serial;
+ }
+ }
+
+ private void resetUserCache() {
+ synchronized (mUserSerialMap) {
+ mUserSerialMap.clear();
+ }
+ }
+
+ @Override
+ protected boolean isInstantApp(ApplicationInfo info) {
+ return info.isInstantApp();
+ }
+
+ @Override
+ public BaseIconFactory getIconFactory() {
+ return IconFactory.obtain(mContext);
+ }
+
+ public static SimpleIconCache getIconCache(Context context) {
+ synchronized (CACHE_LOCK) {
+ if (sIconCache != null) {
+ return sIconCache;
+ }
+ boolean inMemoryCache =
+ context.getResources().getBoolean(R.bool.simple_cache_enable_im_memory);
+ String dbFileName = context.getString(R.string.cache_db_name);
+
+ HandlerThread bgThread = new HandlerThread("simple-icon-cache");
+ bgThread.start();
+
+ sIconCache = new SimpleIconCache(context.getApplicationContext(), dbFileName,
+ bgThread.getLooper(), context.getResources().getConfiguration().densityDpi,
+ context.getResources().getDimensionPixelSize(R.dimen.default_icon_bitmap_size),
+ inMemoryCache);
+ return sIconCache;
+ }
+ }
+}
diff --git a/PermissionController/lint-baseline.xml b/PermissionController/lint-baseline.xml
new file mode 100644
index 000000000..05a307234
--- /dev/null
+++ b/PermissionController/lint-baseline.xml
@@ -0,0 +1,565 @@
+<?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">
+
+ <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=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightHistoricalPackageOps.kt"
+ line="191"
+ column="67"/>
+ </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=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightHistoricalPackageOps.kt"
+ line="156"
+ column="57"/>
+ </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=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightHistoricalPackageOps.kt"
+ line="155"
+ column="38"/>
+ </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=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightHistoricalPackageOps.kt"
+ line="190"
+ column="38"/>
+ </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=" ~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightHistoricalPackageOpsLiveData.kt"
+ line="101"
+ 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=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/HibernatedPackagesLiveData.kt"
+ line="56"
+ column="44"/>
+ </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=" ~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt"
+ line="125"
+ column="72"/>
+ </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=" ~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt"
+ line="125"
+ column="62"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ 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/permission/service/PermissionControllerServiceImpl.java"
+ line="517"
+ 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="517"
+ column="24"/>
+ </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=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java"
+ line="516"
+ column="43"/>
+ </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=" ~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java"
+ line="516"
+ column="75"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ 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/permission/ui/television/AppPermissionsFragment.java"
+ line="159"
+ column="35"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ 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/permission/ui/television/PermissionAppsFragment.java"
+ line="114"
+ column="35"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ 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/ui/television/AppPermissionsFragment.java"
+ line="367"
+ column="35"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ 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/ui/television/PermissionAppsFragment.java"
+ line="365"
+ column="35"/>
+ </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=" ~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/StatusUiData.kt"
+ line="18"
+ column="68"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterData#getIssues`"
+ errorLine1=" issues"
+ errorLine2=" ~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
+ line="309"
+ column="5"/>
+ </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=" ~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
+ line="323"
+ column="64"/>
+ </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=" ~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/StatusUiData.kt"
+ line="18"
+ column="31"/>
+ </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=" ~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
+ line="321"
+ column="5"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ 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/LiveSafetyCenterViewModel.kt"
+ line="311"
+ column="19"/>
+ </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=" ~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
+ line="315"
+ column="30"/>
+ </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=" ~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
+ line="323"
+ column="80"/>
+ </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=" ~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
+ line="315"
+ column="39"/>
+ </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=" ~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
+ line="314"
+ column="48"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterIssue.Action#getSuccessMessage`"
+ errorLine1=" var successMessage = action.successMessage"
+ errorLine2=" ~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardAnimator.kt"
+ line="47"
+ column="37"/>
+ </issue>
+
+ <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=" ~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
+ line="314"
+ column="30"/>
+ </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="96"
+ column="34"/>
+ </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="149"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterManager#isSafetyCenterEnabled`"
+ errorLine1=" if (!scManager.isSafetyCenterEnabled) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/v33/SafetyCenterQsTileService.kt"
+ line="48"
+ column="24"/>
+ </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="155"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 33 (current min is 30): `android.safetycenter.SafetyCenterStatus#getRefreshStatus`"
+ errorLine1=" when (status.refreshStatus) {"
+ errorLine2=" ~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/StatusUiData.kt"
+ line="65"
+ column="26"/>
+ </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=" ~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
+ line="321"
+ column="12"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 33 (current min is 30): `recordPermissionDecision`"
+ errorLine1=" PermissionDecisionStorageImpl.recordPermissionDecision(app.applicationContext,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt"
+ line="1147"
+ column="39"/>
+ </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=" ~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/SafetyLabelInfoLiveData.kt"
+ line="116"
+ column="32"/>
+ </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=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt"
+ line="1465"
+ column="48"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 34 (current min is 30): `android.health.connect.HealthConnectManager#isHealthPermission`"
+ errorLine1=" isHealthPermission(activity, permission)"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt"
+ line="1268"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 34 (current min is 33): `getParentGroupId`"
+ errorLine1=" String groupId = getParentGroupId(preferenceKey);"
+ errorLine2=" ~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java"
+ line="89"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 34 (current min is 33): `openRelevantSubpage`"
+ errorLine1=" frag = openRelevantSubpage(groupId);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java"
+ line="86"
+ column="20"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 34 (current min is 33): `openRelevantSubpage`"
+ errorLine1=" frag = openRelevantSubpage(groupId);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java"
+ line="90"
+ column="20"/>
+ </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=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/HibernatedPackagesLiveData.kt"
+ line="53"
+ column="74"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ 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/service/SafetyCenterBackgroundRefreshJobService.java"
+ line="84"
+ column="42"/>
+ </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="144"
+ column="73"/>
+ </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=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/v33/SafetyCenterQsTileService.kt"
+ line="41"
+ column="42"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Class requires API level 34 (current min is 30): `android.app.AppOpsManager.OnOpNotedListener`"
+ errorLine1=" AppOpsManager.OnOpNotedListener,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightHistoricalPackageOpsLiveData.kt"
+ line="45"
+ column="5"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Class requires API level 34 (current min is 30): `android.app.AppOpsManager.OnOpNotedListener`"
+ errorLine1=" AppOpsManager.OnOpNotedListener,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightPackageOpsLiveData.kt"
+ line="38"
+ column="5"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ 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/ui/MoreIssuesCardAnimator.kt"
+ line="107"
+ column="46"/>
+ </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=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/StatusUiData.kt"
+ line="30"
+ column="31"/>
+ </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=" ~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/StatusUiData.kt"
+ line="29"
+ 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=" ~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/StatusUiData.kt"
+ line="28"
+ column="32"/>
+ </issue>
+
+</issues> \ No newline at end of file
diff --git a/PermissionController/proguard.flags b/PermissionController/proguard.flags
index 1f0b03269..13590aa39 100644
--- a/PermissionController/proguard.flags
+++ b/PermissionController/proguard.flags
@@ -8,7 +8,12 @@
-dontwarn androidx.core.**
# Keep classes that implements RoleBehavior, which are used by reflection.
--keep class * implements com.android.permissioncontroller.role.model.RoleBehavior {
+-keep class * implements com.android.role.controller.model.RoleBehavior {
+ *;
+}
+
+# Keep classes that implements RoleUiBehavior, which are used by reflection.
+-keep class * implements com.android.permissioncontroller.role.ui.behavior.RoleUiBehavior {
*;
}
@@ -25,4 +30,4 @@
*** get*();
*** set*(***);
*** has*();
-} \ No newline at end of file
+}
diff --git a/PermissionController/res/color-v33/safety_center_button_info.xml b/PermissionController/res/color-v33/safety_center_button_info.xml
new file mode 100644
index 000000000..ef4b24050
--- /dev/null
+++ b/PermissionController/res/color-v33/safety_center_button_info.xml
@@ -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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- disabled is 30% opacity -->
+ <item android:state_enabled="false" android:color="@color/gm_green_400" android:alpha="0.3" />
+ <item android:color="@color/gm_green_400" />
+</selector>
diff --git a/PermissionController/res/color-v33/safety_center_button_recommend.xml b/PermissionController/res/color-v33/safety_center_button_recommend.xml
new file mode 100644
index 000000000..1db5b7cc6
--- /dev/null
+++ b/PermissionController/res/color-v33/safety_center_button_recommend.xml
@@ -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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- disabled is 30% opacity -->
+ <item android:state_enabled="false" android:color="@color/gm_yellow_400" android:alpha="0.3" />
+ <item android:color="@color/gm_yellow_400" />
+</selector>
diff --git a/PermissionController/res/color-v33/safety_center_button_warn.xml b/PermissionController/res/color-v33/safety_center_button_warn.xml
new file mode 100644
index 000000000..8a21c0150
--- /dev/null
+++ b/PermissionController/res/color-v33/safety_center_button_warn.xml
@@ -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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- disabled is 30% opacity -->
+ <item android:state_enabled="false" android:color="@color/gm_red_400" android:alpha="0.3" />
+ <item android:color="@color/gm_red_400" />
+</selector>
diff --git a/PermissionController/res/color-v33/safety_center_outline_button_info.xml b/PermissionController/res/color-v33/safety_center_outline_button_info.xml
new file mode 100644
index 000000000..19c5167af
--- /dev/null
+++ b/PermissionController/res/color-v33/safety_center_outline_button_info.xml
@@ -0,0 +1,23 @@
+<!--
+ ~ 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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- disabled is 30% opacity -->
+ <item android:state_enabled="false"
+ android:color="?attr/colorScOutlineButtonInfoBase"
+ android:alpha="0.3" />
+ <item android:color="?attr/colorScOutlineButtonInfoBase" />
+</selector>
diff --git a/PermissionController/res/color-v33/safety_center_outline_button_recommend.xml b/PermissionController/res/color-v33/safety_center_outline_button_recommend.xml
new file mode 100644
index 000000000..daed711e4
--- /dev/null
+++ b/PermissionController/res/color-v33/safety_center_outline_button_recommend.xml
@@ -0,0 +1,23 @@
+<!--
+ ~ 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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- disabled is 30% opacity -->
+ <item android:state_enabled="false"
+ android:color="?attr/colorScOutlineButtonRecommendBase"
+ android:alpha="0.3" />
+ <item android:color="?attr/colorScOutlineButtonRecommendBase" />
+</selector>
diff --git a/PermissionController/res/color-v33/safety_center_outline_button_warn.xml b/PermissionController/res/color-v33/safety_center_outline_button_warn.xml
new file mode 100644
index 000000000..b29b8f717
--- /dev/null
+++ b/PermissionController/res/color-v33/safety_center_outline_button_warn.xml
@@ -0,0 +1,23 @@
+<!--
+ ~ 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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- disabled is 30% opacity -->
+ <item android:state_enabled="false"
+ android:color="?attr/colorScOutlineButtonWarnBase"
+ android:alpha="0.3" />
+ <item android:color="?attr/colorScOutlineButtonWarnBase" />
+</selector>
diff --git a/PermissionController/res/color-v33/safety_center_toggle_disabled.xml b/PermissionController/res/color-v33/safety_center_toggle_disabled.xml
new file mode 100644
index 000000000..496ede7fe
--- /dev/null
+++ b/PermissionController/res/color-v33/safety_center_toggle_disabled.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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- disabled is 30% opacity -->
+ <item android:color="#000000" android:alpha="0.3" />
+</selector>
diff --git a/PermissionController/res/color-v33/sc_surface_light.xml b/PermissionController/res/color-v33/sc_surface_light.xml
new file mode 100644
index 000000000..ac63072a9
--- /dev/null
+++ b/PermissionController/res/color-v33/sc_surface_light.xml
@@ -0,0 +1,19 @@
+<?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.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_neutral1_500" android:lStar="98" />
+</selector> \ No newline at end of file
diff --git a/PermissionController/res/color-v34/preference_highlight_color.xml b/PermissionController/res/color-v34/preference_highlight_color.xml
new file mode 100644
index 000000000..c2889bf48
--- /dev/null
+++ b/PermissionController/res/color-v34/preference_highlight_color.xml
@@ -0,0 +1,20 @@
+<?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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:alpha="0.26" android:color="?android:attr/colorAccent" />
+</selector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v31/safety_status_info.xml b/PermissionController/res/drawable-v31/safety_status_info.xml
deleted file mode 100644
index d1c1a6e6a..000000000
--- a/PermissionController/res/drawable-v31/safety_status_info.xml
+++ /dev/null
@@ -1,37 +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.
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="102dp"
- android:height="88dp"
- android:viewportWidth="102"
- android:viewportHeight="88">
- <path
- android:fillColor="@color/safety_center_info"
- android:pathData="M18.727,87.496c-0.874,0 -1.75,-0.325 -2.428,-0.98c-3.775,-3.639 -6.949,-7.851 -9.434,-12.519c-3.843,-7.218 -5.874,-15.329 -5.874,-23.455c0,-2.959 0.266,-5.94 0.791,-8.861c0.342,-1.902 2.16,-3.167 4.064,-2.825c1.902,0.342 3.167,2.162 2.825,4.064c-0.452,2.513 -0.681,5.078 -0.681,7.622c0,6.983 1.747,13.956 5.053,20.166c2.139,4.018 4.869,7.641 8.113,10.768c1.392,1.341 1.433,3.557 0.091,4.949C20.56,87.137 19.645,87.496 18.727,87.496z"/>
- <path
- android:fillColor="@color/safety_center_info"
- android:pathData="M9.166,33.688c-0.512,0 -1.032,-0.113 -1.524,-0.352c-1.74,-0.843 -2.466,-2.937 -1.623,-4.676c4.639,-9.572 12.068,-17.282 21.485,-22.294c5.227,-2.783 10.826,-4.601 16.642,-5.405c1.914,-0.266 3.682,1.073 3.946,2.987c0.265,1.915 -1.073,3.682 -2.987,3.946c-4.998,0.691 -9.814,2.256 -14.312,4.65c-8.099,4.312 -14.487,10.94 -18.476,19.169C11.713,32.961 10.465,33.688 9.166,33.688z"/>
- <path
- android:fillColor="@color/safety_center_info"
- android:pathData="M92.828,33.683c-1.298,0 -2.544,-0.725 -3.15,-1.971c-0.231,-0.475 -0.471,-0.947 -0.721,-1.416C82.501,18.167 70.51,9.796 56.882,7.902c-1.915,-0.266 -3.251,-2.034 -2.985,-3.949c0.267,-1.915 2.032,-3.247 3.949,-2.985c15.843,2.202 29.783,11.936 37.29,26.037c0.29,0.545 0.57,1.094 0.838,1.646c0.845,1.738 0.122,3.832 -1.617,4.678C93.863,33.569 93.342,33.683 92.828,33.683z"/>
- <path
- android:fillColor="@color/safety_center_info"
- android:pathData="M83.278,87.49c-0.918,0 -1.834,-0.359 -2.522,-1.072c-1.34,-1.393 -1.299,-3.608 0.094,-4.949c8.363,-8.052 13.159,-19.354 13.159,-31.008c0,-2.527 -0.226,-5.068 -0.672,-7.552c-0.342,-1.903 0.924,-3.722 2.827,-4.063c1.903,-0.343 3.722,0.924 4.063,2.826c0.519,2.891 0.782,5.848 0.782,8.79c0,13.546 -5.578,26.685 -15.304,36.05C85.026,87.165 84.152,87.49 83.278,87.49z"/>
- <path
- android:fillColor="@color/safety_center_info"
- android:pathData="M50.992,16.542c-18.778,0 -34,15.222 -34,34s15.222,34 34,34c18.778,0 34,-15.222 34,-34S69.77,16.542 50.992,16.542zM46.325,62.25L36.285,52.2l3.997,-4l6.043,6.025l15.378,-15.393l3.994,4.026L46.325,62.25z"/>
-</vector>
diff --git a/PermissionController/res/drawable-v31/safety_status_info_review.xml b/PermissionController/res/drawable-v31/safety_status_info_review.xml
deleted file mode 100644
index f043cd0e6..000000000
--- a/PermissionController/res/drawable-v31/safety_status_info_review.xml
+++ /dev/null
@@ -1,37 +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.
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="102dp"
- android:height="88dp"
- android:viewportWidth="102"
- android:viewportHeight="88">
- <path
- android:fillColor="@color/safety_center_info"
- android:pathData="M18.727,87.496c-0.874,0 -1.75,-0.325 -2.428,-0.98c-3.775,-3.639 -6.949,-7.851 -9.434,-12.519c-3.843,-7.218 -5.874,-15.329 -5.874,-23.455c0,-2.959 0.266,-5.94 0.791,-8.861c0.342,-1.902 2.16,-3.167 4.064,-2.825c1.902,0.342 3.167,2.162 2.825,4.064c-0.452,2.513 -0.681,5.078 -0.681,7.622c0,6.983 1.747,13.956 5.053,20.166c2.139,4.018 4.869,7.641 8.113,10.768c1.392,1.341 1.433,3.557 0.091,4.949C20.56,87.137 19.645,87.496 18.727,87.496z"/>
- <path
- android:fillColor="@color/safety_center_info"
- android:pathData="M9.166,33.688c-0.512,0 -1.032,-0.113 -1.524,-0.352c-1.74,-0.843 -2.466,-2.937 -1.623,-4.676c4.639,-9.572 12.068,-17.282 21.485,-22.294c5.227,-2.783 10.826,-4.601 16.642,-5.405c1.914,-0.266 3.682,1.073 3.946,2.987c0.265,1.915 -1.073,3.682 -2.987,3.946c-4.998,0.691 -9.814,2.256 -14.312,4.65c-8.099,4.312 -14.487,10.94 -18.476,19.169C11.713,32.961 10.465,33.688 9.166,33.688z"/>
- <path
- android:fillColor="@color/safety_center_info"
- android:pathData="M92.828,33.683c-1.298,0 -2.544,-0.725 -3.15,-1.971c-0.231,-0.475 -0.471,-0.947 -0.721,-1.416C82.501,18.167 70.51,9.796 56.882,7.902c-1.915,-0.266 -3.251,-2.034 -2.985,-3.949c0.267,-1.915 2.032,-3.247 3.949,-2.985c15.843,2.202 29.783,11.936 37.29,26.037c0.29,0.545 0.57,1.094 0.838,1.646c0.845,1.738 0.122,3.832 -1.617,4.678C93.863,33.569 93.342,33.683 92.828,33.683z"/>
- <path
- android:fillColor="@color/safety_center_status_unfilled_wedge"
- android:pathData="M83.278,87.49c-0.918,0 -1.834,-0.359 -2.522,-1.072c-1.34,-1.393 -1.299,-3.608 0.094,-4.949c8.363,-8.052 13.159,-19.354 13.159,-31.008c0,-2.527 -0.226,-5.068 -0.672,-7.552c-0.342,-1.903 0.924,-3.722 2.827,-4.063c1.903,-0.343 3.722,0.924 4.063,2.826c0.519,2.891 0.782,5.848 0.782,8.79c0,13.546 -5.578,26.685 -15.304,36.05C85.026,87.165 84.152,87.49 83.278,87.49z"/>
- <path
- android:fillColor="@color/safety_center_info"
- android:pathData="M50.992,16.542c-18.778,0 -34,15.222 -34,34s15.222,34 34,34c18.778,0 34,-15.222 34,-34S69.77,16.542 50.992,16.542zM46.325,62.25L36.285,52.2l3.997,-4l6.043,6.025l15.378,-15.393l3.994,4.026L46.325,62.25z"/>
-</vector>
diff --git a/PermissionController/res/drawable-v31/safety_status_recommendation.xml b/PermissionController/res/drawable-v31/safety_status_recommendation.xml
deleted file mode 100644
index c1c341bd6..000000000
--- a/PermissionController/res/drawable-v31/safety_status_recommendation.xml
+++ /dev/null
@@ -1,37 +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.
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="102dp"
- android:height="88dp"
- android:viewportWidth="102"
- android:viewportHeight="88">
- <path
- android:fillColor="@color/safety_center_recommend"
- android:pathData="M18.727,87.496c-0.874,0 -1.75,-0.325 -2.428,-0.98c-3.775,-3.639 -6.949,-7.851 -9.434,-12.519c-3.843,-7.218 -5.874,-15.329 -5.874,-23.455c0,-2.959 0.266,-5.94 0.791,-8.861c0.342,-1.902 2.16,-3.167 4.064,-2.825c1.902,0.342 3.167,2.162 2.825,4.064c-0.452,2.513 -0.681,5.078 -0.681,7.622c0,6.983 1.747,13.956 5.053,20.166c2.139,4.018 4.869,7.641 8.113,10.768c1.392,1.341 1.433,3.557 0.091,4.949C20.56,87.137 19.645,87.496 18.727,87.496z"/>
- <path
- android:fillColor="@color/safety_center_recommend"
- android:pathData="M9.166,33.688c-0.512,0 -1.032,-0.113 -1.524,-0.352c-1.74,-0.843 -2.466,-2.937 -1.623,-4.676c4.639,-9.572 12.068,-17.282 21.485,-22.294c5.227,-2.783 10.826,-4.601 16.642,-5.405c1.914,-0.266 3.682,1.073 3.946,2.987c0.265,1.915 -1.073,3.682 -2.987,3.946c-4.998,0.691 -9.814,2.256 -14.312,4.65c-8.099,4.312 -14.487,10.94 -18.476,19.169C11.713,32.961 10.465,33.688 9.166,33.688z"/>
- <path
- android:fillColor="@color/safety_center_status_unfilled_wedge"
- android:pathData="M92.828,33.683c-1.298,0 -2.544,-0.725 -3.15,-1.971c-0.231,-0.475 -0.471,-0.947 -0.721,-1.416C82.501,18.167 70.51,9.796 56.882,7.902c-1.915,-0.266 -3.251,-2.034 -2.985,-3.949c0.267,-1.915 2.032,-3.247 3.949,-2.985c15.843,2.202 29.783,11.936 37.29,26.037c0.29,0.545 0.57,1.094 0.838,1.646c0.845,1.738 0.122,3.832 -1.617,4.678C93.863,33.569 93.342,33.683 92.828,33.683z"/>
- <path
- android:fillColor="@color/safety_center_status_unfilled_wedge"
- android:pathData="M83.278,87.49c-0.918,0 -1.834,-0.359 -2.522,-1.072c-1.34,-1.393 -1.299,-3.608 0.094,-4.949c8.363,-8.052 13.159,-19.354 13.159,-31.008c0,-2.527 -0.226,-5.068 -0.672,-7.552c-0.342,-1.903 0.924,-3.722 2.827,-4.063c1.903,-0.343 3.722,0.924 4.063,2.826c0.519,2.891 0.782,5.848 0.782,8.79c0,13.546 -5.578,26.685 -15.304,36.05C85.026,87.165 84.152,87.49 83.278,87.49z" />
- <path
- android:fillColor="@color/safety_center_recommend"
- android:pathData="M51.057,17.501c-18.778,0 -34,15.222 -34,34c0,18.778 15.222,34 34,34c18.778,0 34,-15.222 34,-34C85.057,32.723 69.835,17.501 51.057,17.501zM54,67h-6v-6h6V67zM54,57h-6V38h6V57z"/>
-</vector>
diff --git a/PermissionController/res/drawable-v31/safety_status_warn.xml b/PermissionController/res/drawable-v31/safety_status_warn.xml
deleted file mode 100644
index 2c69c0483..000000000
--- a/PermissionController/res/drawable-v31/safety_status_warn.xml
+++ /dev/null
@@ -1,37 +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.
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="102dp"
- android:height="88dp"
- android:viewportWidth="102"
- android:viewportHeight="88">
- <path
- android:fillColor="@color/safety_center_warn"
- android:pathData="M18.727,87.496c-0.874,0 -1.75,-0.325 -2.428,-0.98c-3.775,-3.639 -6.949,-7.851 -9.434,-12.519c-3.843,-7.218 -5.874,-15.329 -5.874,-23.455c0,-2.959 0.266,-5.94 0.791,-8.861c0.342,-1.902 2.16,-3.167 4.064,-2.825c1.902,0.342 3.167,2.162 2.825,4.064c-0.452,2.513 -0.681,5.078 -0.681,7.622c0,6.983 1.747,13.956 5.053,20.166c2.139,4.018 4.869,7.641 8.113,10.768c1.392,1.341 1.433,3.557 0.091,4.949C20.56,87.137 19.645,87.496 18.727,87.496z"/>
- <path
- android:fillColor="@color/safety_center_status_unfilled_wedge"
- android:pathData="M9.166,33.688c-0.512,0 -1.032,-0.113 -1.524,-0.352c-1.74,-0.843 -2.466,-2.937 -1.623,-4.676c4.639,-9.572 12.068,-17.282 21.485,-22.294c5.227,-2.783 10.826,-4.601 16.642,-5.405c1.914,-0.266 3.682,1.073 3.946,2.987c0.265,1.915 -1.073,3.682 -2.987,3.946c-4.998,0.691 -9.814,2.256 -14.312,4.65c-8.099,4.312 -14.487,10.94 -18.476,19.169C11.713,32.961 10.465,33.688 9.166,33.688z"/>
- <path
- android:fillColor="@color/safety_center_status_unfilled_wedge"
- android:pathData="M92.828,33.683c-1.298,0 -2.544,-0.725 -3.15,-1.971c-0.231,-0.475 -0.471,-0.947 -0.721,-1.416C82.501,18.167 70.51,9.796 56.882,7.902c-1.915,-0.266 -3.251,-2.034 -2.985,-3.949c0.267,-1.915 2.032,-3.247 3.949,-2.985c15.843,2.202 29.783,11.936 37.29,26.037c0.29,0.545 0.57,1.094 0.838,1.646c0.845,1.738 0.122,3.832 -1.617,4.678C93.863,33.569 93.342,33.683 92.828,33.683z"/>
- <path
- android:fillColor="@color/safety_center_status_unfilled_wedge"
- android:pathData="M83.278,87.49c-0.918,0 -1.834,-0.359 -2.522,-1.072c-1.34,-1.393 -1.299,-3.608 0.094,-4.949c8.363,-8.052 13.159,-19.354 13.159,-31.008c0,-2.527 -0.226,-5.068 -0.672,-7.552c-0.342,-1.903 0.924,-3.722 2.827,-4.063c1.903,-0.343 3.722,0.924 4.063,2.826c0.519,2.891 0.782,5.848 0.782,8.79c0,13.546 -5.578,26.685 -15.304,36.05C85.026,87.165 84.152,87.49 83.278,87.49z"/>
- <path
- android:fillColor="@color/safety_center_warn"
- android:pathData="M51.057,17.501c-18.778,0 -34,15.222 -34,34c0,18.778 15.222,34 34,34c18.778,0 34,-15.222 34,-34C85.057,32.723 69.835,17.501 51.057,17.501zM54,67h-6v-6h6V67zM54,57h-6V38h6V57z"/>
-</vector>
diff --git a/PermissionController/res/drawable-v31/ic_check.xml b/PermissionController/res/drawable-v33/ic_check.xml
index 0b67c6c94..0b67c6c94 100644
--- a/PermissionController/res/drawable-v31/ic_check.xml
+++ b/PermissionController/res/drawable-v33/ic_check.xml
diff --git a/PermissionController/res/drawable-v31/ic_block.xml b/PermissionController/res/drawable-v33/ic_chevron_right.xml
index b77c26034..be997e8de 100644
--- a/PermissionController/res/drawable-v31/ic_block.xml
+++ b/PermissionController/res/drawable-v33/ic_chevron_right.xml
@@ -22,5 +22,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM4,12c0,-4.42 3.58,-8 8,-8 1.85,0 3.55,0.63 4.9,1.69L5.69,16.9C4.63,15.55 4,13.85 4,12zM12,20c-1.85,0 -3.55,-0.63 -4.9,-1.69L18.31,7.1C19.37,8.45 20,10.15 20,12c0,4.42 -3.58,8 -8,8z"/>
+ android:pathData="M9.4,18 L8,16.6 12.6,12 8,7.4 9.4,6 15.4,12Z"/>
</vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable/safety_shield.xml b/PermissionController/res/drawable-v33/ic_collapse_issues.xml
index d41f37853..182371d86 100644
--- a/PermissionController/res/drawable/safety_shield.xml
+++ b/PermissionController/res/drawable-v33/ic_collapse_issues.xml
@@ -1,5 +1,5 @@
<!--
- ~ Copyright (C) 2021 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.
@@ -20,6 +20,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
- android:fillColor="@android:color/white"
- android:pathData="M12,22q-3.475,-0.875 -5.737,-3.988Q4,14.9 4,11.1L4,5l8,-3 8,3v6.1q0,3.8 -2.262,6.912Q15.475,21.125 12,22zM12,19.9q2.425,-0.75 4.05,-2.962 1.625,-2.213 1.9,-4.938L12,12L12,4.125l-6,2.25v5.175q0,0.175 0.05,0.45L12,12z"/>
+ android:pathData="M16.3934,14.9393L17.3334,13.9993L12.0001,8.666L6.6667,13.9993L7.6068,14.9393L12.0001,10.5527"
+ android:fillColor="?android:attr/textColorPrimary"/>
</vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/ic_expand_issues.xml b/PermissionController/res/drawable-v33/ic_expand_issues.xml
new file mode 100644
index 000000000..6e64ec38f
--- /dev/null
+++ b/PermissionController/res/drawable-v33/ic_expand_issues.xml
@@ -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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M7.607,9.059L6.667,9.999L12,15.332L17.333,9.999L16.393,9.059L12,13.445"
+ android:fillColor="?android:attr/textColorPrimary"/>
+</vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v31/ic_expand_less.xml b/PermissionController/res/drawable-v33/ic_expand_less.xml
index bc561e60f..bc561e60f 100644
--- a/PermissionController/res/drawable-v31/ic_expand_less.xml
+++ b/PermissionController/res/drawable-v33/ic_expand_less.xml
diff --git a/PermissionController/res/drawable-v31/ic_expand_more.xml b/PermissionController/res/drawable-v33/ic_expand_more.xml
index 5cb3b2a9b..5cb3b2a9b 100644
--- a/PermissionController/res/drawable-v31/ic_expand_more.xml
+++ b/PermissionController/res/drawable-v33/ic_expand_more.xml
diff --git a/PermissionController/res/drawable-v31/ic_safety_null_state.xml b/PermissionController/res/drawable-v33/ic_privacy.xml
index d08e6097b..00e9ff099 100644
--- a/PermissionController/res/drawable-v31/ic_safety_null_state.xml
+++ b/PermissionController/res/drawable-v33/ic_privacy.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2021 The Android Open Source Project
+ ~ Copyright (C) 2022 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -14,18 +14,13 @@
~ limitations under the License.
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:height="24dp"
- android:width="24dp"
- android:viewportHeight="24"
- android:viewportWidth="24">
-
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="16dp"
+ android:height="20dp"
+ android:viewportWidth="16"
+ android:viewportHeight="20">
<path
- android:pathData="M10,10m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
+ android:pathData="M8,0L0,3V9.09C0,14.14 3.41,18.85 8,20C12.59,18.85 16,14.14 16,9.09V3L8,0ZM14,9.09C14,13.09 11.45,16.79 8,17.92C4.55,16.79 2,13.1 2,9.09V4.39L8,2.14L14,4.39V9.09ZM8.93,9.77L9.5,13H6.5L7.07,9.77C6.43,9.44 6,8.77 6,8C6,6.9 6.9,6 8,6C9.1,6 10,6.9 10,8C10,8.77 9.57,9.44 8.93,9.77Z"
android:fillColor="?android:attr/textColorSecondary"/>
-
- <path
- android:pathData="M4.0179,10V9.0079H10,15.9821V10,10.9921H10,4.0179Z"
- android:strokeWidth="0.0198413"
- android:fillColor="?android:attr/colorBackground"/>
</vector>
diff --git a/PermissionController/res/drawable-v31/ic_safety_info_outline.xml b/PermissionController/res/drawable-v33/ic_safety_center_shield.xml
index b680ff1ae..e817b7194 100644
--- a/PermissionController/res/drawable-v31/ic_safety_info_outline.xml
+++ b/PermissionController/res/drawable-v33/ic_safety_center_shield.xml
@@ -1,4 +1,4 @@
-<?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");
@@ -13,16 +13,19 @@
~ 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:viewportHeight="24"
+ android:tint="?android:attr/textColorPrimary">
+
+ <path
+ android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
<path
- android:fillColor="@color/safety_center_info"
- android:pathData="M10,20C4.4858,20 0,15.5142 0,10S4.4858,0 10,0s10,4.4858 10,10S15.5142,20 10,20zM10,2c-4.4111,0 -8,3.5889 -8,8s3.5889,8 8,8s8,-3.5889 8,-8S14.4111,2 10,2z"/>
+ android:fillColor="#000000"
+ android:pathData="M12,4.14l6,2.25v4.71c0,2.12-0.62,4-1.88,5.74c-1.13,1.55-2.48,2.56-4.12,3.09c-1.64-0.52-2.99-1.54-4.12-3.09 C6.62,15.1,6,13.22,6,11.1V6.39L12,4.14 M12,2L4,5v6.1c0,2.53,0.75,4.84,2.26,6.91C7.77,20.09,9.68,21.42,12,22 c2.32-0.58,4.23-1.91,5.74-3.99C19.25,15.94,20,13.63,20,11.1V5L12,2L12,2z" />
<path
- android:fillColor="@color/safety_center_info"
- android:pathData="M8.4137,13.9806l-3.4137,-3.4167l1.3588,-1.3598l2.0547,2.0486l5.2285,-5.2333l1.358,1.3689z"/>
-</vector>
+ android:fillColor="#000000"
+ android:pathData="M 10.95 15.55 L 7.42 12.02 L 8.85 10.6 L 10.95 12.7 L 15.17 8.47 L 16.6 9.9 Z" />
+</vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v31/ic_safety_empty.xml b/PermissionController/res/drawable-v33/ic_safety_empty.xml
index 78b9e34ab..78b9e34ab 100644
--- a/PermissionController/res/drawable-v31/ic_safety_empty.xml
+++ b/PermissionController/res/drawable-v33/ic_safety_empty.xml
diff --git a/PermissionController/res/drawable-v31/ic_safety_recommendation_outline.xml b/PermissionController/res/drawable-v33/ic_safety_group_collapse.xml
index 2b7f554d9..a804b6e9e 100644
--- a/PermissionController/res/drawable-v31/ic_safety_recommendation_outline.xml
+++ b/PermissionController/res/drawable-v33/ic_safety_group_collapse.xml
@@ -19,8 +19,10 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
- <path
- android:pathData="M1,21L12,2L23,21H1ZM19.53,19L12,5.99L4.47,19H19.53ZM11,16V18H13V16H11ZM11,10H13V14H11V10Z"
- android:fillColor="@color/safety_center_recommend"
- android:fillType="evenOdd"/>
+ <path
+ android:pathData="M0,12C0,5.3726 5.3726,0 12,0C18.6274,0 24,5.3726 24,12C24,18.6274 18.6274,24 12,24C5.3726,24 0,18.6274 0,12Z"
+ android:fillColor="?attr/colorSurfaceVariant"/>
+ <path
+ android:pathData="M16.3934,14.9393L17.3334,13.9993L12.0001,8.666L6.6667,13.9993L7.6068,14.9393L12.0001,10.5527"
+ android:fillColor="?android:attr/textColorPrimary"/>
</vector>
diff --git a/PermissionController/res/drawable-v33/ic_safety_group_expand.xml b/PermissionController/res/drawable-v33/ic_safety_group_expand.xml
new file mode 100644
index 000000000..bf0606d7a
--- /dev/null
+++ b/PermissionController/res/drawable-v33/ic_safety_group_expand.xml
@@ -0,0 +1,12 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M0,12C0,5.373 5.373,0 12,0C18.627,0 24,5.373 24,12C24,18.627 18.627,24 12,24C5.373,24 0,18.627 0,12Z"
+ android:fillColor="?attr/colorSurfaceVariant"/>
+ <path
+ android:pathData="M7.607,9.059L6.667,9.999L12,15.332L17.333,9.999L16.393,9.059L12,13.445"
+ android:fillColor="?android:attr/textColorPrimary"/>
+</vector>
diff --git a/PermissionController/res/drawable-v33/ic_safety_info.xml b/PermissionController/res/drawable-v33/ic_safety_info.xml
new file mode 100644
index 000000000..a3032ae72
--- /dev/null
+++ b/PermissionController/res/drawable-v33/ic_safety_info.xml
@@ -0,0 +1,26 @@
+<?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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <path
+ android:fillColor="?attr/colorScIconInfo"
+ android:pathData="M10,2a8,8 0,1 0,8 8,8 8,0 0,0 -8,-8ZM8.41,14 L5.24,10.79l1.11,-1.1 2.06,2.05L13.65,6.5l1.11,1.12Z"/>
+</vector>
diff --git a/PermissionController/res/drawable-v31/ic_safety_info.xml b/PermissionController/res/drawable-v33/ic_safety_issue_dismiss.xml
index e245d92d5..c2188c459 100644
--- a/PermissionController/res/drawable-v31/ic_safety_info.xml
+++ b/PermissionController/res/drawable-v33/ic_safety_issue_dismiss.xml
@@ -1,5 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2021 The Android Open Source Project
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -19,7 +19,8 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
- <path
- android:pathData="M10,0C4.4772,0 0,4.4772 0,10s4.4772,10 10,10s10,-4.4772 10,-10S15.5228,0 10,0zM8.4137,13.9806L5,10.5639l1.3588,-1.3597l2.0547,2.0485l5.2285,-5.2333L15,7.3883L8.4137,13.9806z"
- android:fillColor="@color/safety_center_info"/>
-</vector>
+ <path android:pathData="M12,0L12,0A12,12 0,0 1,24 12L24,12A12,12 0,0 1,12 24L12,24A12,12 0,0 1,0 12L0,12A12,12 0,0 1,12 0z"
+ android:fillColor="?attr/colorSurfaceVariant" />
+ <path android:pathData="M16.666,8.273L15.726,7.333L12,11.06L8.273,7.333L7.333,8.273L11.06,12L7.333,15.726L8.273,16.666L12,12.94L15.726,16.666L16.666,15.726L12.94,12L16.666,8.273Z"
+ android:fillColor="?android:attr/textColorPrimary" />
+</vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v31/ic_safety_issue_dismiss.xml b/PermissionController/res/drawable-v33/ic_safety_null_state.xml
index d32a8a789..ff9c3e4e9 100644
--- a/PermissionController/res/drawable-v31/ic_safety_issue_dismiss.xml
+++ b/PermissionController/res/drawable-v33/ic_safety_null_state.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
@@ -15,11 +16,11 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:fillColor="?android:attr/textColorSecondary"
- android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12 19,6.41z"/>
-</vector> \ No newline at end of file
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <path
+ android:fillColor="?attr/colorScIconNull"
+ android:pathData="M10,2a8,8 0,1 0,8 8A8,8 0,0 0,10 2ZM15,11L5,11L5,9L15,9Z"/>
+</vector>
diff --git a/PermissionController/res/drawable-v31/ic_safety_recommendation.xml b/PermissionController/res/drawable-v33/ic_safety_recommendation.xml
index a11963d45..13366c25c 100644
--- a/PermissionController/res/drawable-v31/ic_safety_recommendation.xml
+++ b/PermissionController/res/drawable-v33/ic_safety_recommendation.xml
@@ -1,5 +1,6 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2021 The Android Open Source Project
+<?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.
@@ -15,11 +16,12 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:pathData="M10,0C4.4772,0 0,4.4772 0,10s4.4772,10 10,10s10,-4.4772 10,-10S15.5228,0 10,0zM11,15H9v-2h2V15zM11,11H9V5h2V11z"
- android:fillColor="@color/safety_center_recommend" />
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <path
+ android:fillColor="?attr/colorScIconRecommend"
+ android:pathData="M10,2a8,8 0,1 0,8 8,8 8,0 0,0 -8,-8ZM9.2,14L9.2,12.4h1.6L10.8,14ZM9.2,6v4.76h1.6L10.8,6Z"
+ android:fillType="evenOdd"/>
</vector>
diff --git a/PermissionController/res/drawable-v31/ic_safety_warn.xml b/PermissionController/res/drawable-v33/ic_safety_warn.xml
index 94cfa7831..d4bc306c0 100644
--- a/PermissionController/res/drawable-v31/ic_safety_warn.xml
+++ b/PermissionController/res/drawable-v33/ic_safety_warn.xml
@@ -1,5 +1,6 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2021 The Android Open Source Project
+<?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.
@@ -15,11 +16,12 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:pathData="M10,0C4.4772,0 0,4.4772 0,10s4.4772,10 10,10s10,-4.4772 10,-10S15.5228,0 10,0zM11,15H9v-2h2V15zM11,11H9V5h2V11z"
- android:fillColor="@color/safety_center_warn" />
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <path
+ android:fillColor="?attr/colorScIconWarn"
+ android:pathData="M10,2a8,8 0,1 0,8 8,8 8,0 0,0 -8,-8ZM9.2,14L9.2,12.4h1.6L10.8,14ZM9.2,6v4.76h1.6L10.8,6Z"
+ android:fillType="evenOdd"/>
</vector>
diff --git a/PermissionController/res/drawable-v33/ic_settings_gear.xml b/PermissionController/res/drawable-v33/ic_settings_gear.xml
new file mode 100644
index 000000000..e2284a71b
--- /dev/null
+++ b/PermissionController/res/drawable-v33/ic_settings_gear.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="?android:attr/textColorSecondary"
+ android:pathData="M13.85,22.25h-3.7c-0.74,0 -1.36,-0.54 -1.45,-1.27l-0.27,-1.89c-0.27,-0.14 -0.53,-0.29 -0.79,-0.46l-1.8,0.72c-0.7,0.26 -1.47,-0.03 -1.81,-0.65L2.2,15.53c-0.35,-0.66 -0.2,-1.44 0.36,-1.88l1.53,-1.19c-0.01,-0.15 -0.02,-0.3 -0.02,-0.46c0,-0.15 0.01,-0.31 0.02,-0.46l-1.52,-1.19C1.98,9.9 1.83,9.09 2.2,8.47l1.85,-3.19c0.34,-0.62 1.11,-0.9 1.79,-0.63l1.81,0.73c0.26,-0.17 0.52,-0.32 0.78,-0.46l0.27,-1.91c0.09,-0.7 0.71,-1.25 1.44,-1.25h3.7c0.74,0 1.36,0.54 1.45,1.27l0.27,1.89c0.27,0.14 0.53,0.29 0.79,0.46l1.8,-0.72c0.71,-0.26 1.48,0.03 1.82,0.65l1.84,3.18c0.36,0.66 0.2,1.44 -0.36,1.88l-1.52,1.19c0.01,0.15 0.02,0.3 0.02,0.46s-0.01,0.31 -0.02,0.46l1.52,1.19c0.56,0.45 0.72,1.23 0.37,1.86l-1.86,3.22c-0.34,0.62 -1.11,0.9 -1.8,0.63l-1.8,-0.72c-0.26,0.17 -0.52,0.32 -0.78,0.46l-0.27,1.91C15.21,21.71 14.59,22.25 13.85,22.25zM13.32,20.72c0,0.01 0,0.01 0,0.02L13.32,20.72zM10.68,20.7l0,0.02C10.69,20.72 10.69,20.71 10.68,20.7zM10.62,20.25h2.76l0.37,-2.55l0.53,-0.22c0.44,-0.18 0.88,-0.44 1.34,-0.78l0.45,-0.34l2.38,0.96l1.38,-2.4l-2.03,-1.58l0.07,-0.56c0.03,-0.26 0.06,-0.51 0.06,-0.78c0,-0.27 -0.03,-0.53 -0.06,-0.78l-0.07,-0.56l2.03,-1.58l-1.39,-2.4l-2.39,0.96l-0.45,-0.35c-0.42,-0.32 -0.87,-0.58 -1.33,-0.77L13.75,6.3l-0.37,-2.55h-2.76L10.25,6.3L9.72,6.51C9.28,6.7 8.84,6.95 8.38,7.3L7.93,7.63L5.55,6.68L4.16,9.07l2.03,1.58l-0.07,0.56C6.09,11.47 6.06,11.74 6.06,12c0,0.26 0.02,0.53 0.06,0.78l0.07,0.56l-2.03,1.58l1.38,2.4l2.39,-0.96l0.45,0.35c0.43,0.33 0.86,0.58 1.33,0.77l0.53,0.22L10.62,20.25zM18.22,17.72c0,0.01 -0.01,0.02 -0.01,0.03L18.22,17.72zM5.77,17.71l0.01,0.02C5.78,17.72 5.77,17.71 5.77,17.71zM3.93,9.47L3.93,9.47C3.93,9.47 3.93,9.47 3.93,9.47zM18.22,6.27c0,0.01 0.01,0.02 0.01,0.02L18.22,6.27zM5.79,6.25L5.78,6.27C5.78,6.27 5.79,6.26 5.79,6.25zM13.31,3.28c0,0.01 0,0.01 0,0.02L13.31,3.28zM10.69,3.26l0,0.02C10.69,3.27 10.69,3.27 10.69,3.26z"/>
+ <path
+ android:fillColor="?android:attr/textColorSecondary"
+ android:pathData="M12,12m-3.5,0a3.5,3.5 0,1 1,7 0a3.5,3.5 0,1 1,-7 0"/>
+</vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v31/ic_history.xml b/PermissionController/res/drawable-v33/ic_settings_info.xml
index 24ed38a65..f5fee3a52 100644
--- a/PermissionController/res/drawable-v31/ic_history.xml
+++ b/PermissionController/res/drawable-v33/ic_settings_info.xml
@@ -13,17 +13,18 @@
~ 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">
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
<path
- android:fillColor="@android:color/white"
- android:pathData="M4,4v2.01C5.83,3.58 8.73,2 12.01,2 17.53,2 22,6.48 22,12s-4.47,10 -9.99,10C6.48,22 2,17.52 2,12h2c0,4.42 3.58,8 8,8s8,-3.58 8,-8 -3.58,-8 -8,-8C9.04,4 6.47,5.61 5.09,8H8v2H2V4h2z"/>
+ android:fillColor="?android:attr/textColorSecondary"
+ android:pathData="M11,7h2v2h-2z"/>
<path
- android:fillColor="@android:color/white"
- android:pathData="M13,12V6h-2v7l4.97,3.49 1.26,-1.55z"/>
-</vector> \ No newline at end of file
+ android:fillColor="?android:attr/textColorSecondary"
+ android:pathData="M11,11h2v6h-2z"/>
+ <path
+ android:fillColor="?android:attr/textColorSecondary"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8c0,-4.41 3.59,-8 8,-8s8,3.59 8,8C20,16.41 16.41,20 12,20z"/>
+</vector>
diff --git a/PermissionController/res/drawable-v33/indicator_background_circle.xml b/PermissionController/res/drawable-v33/indicator_background_circle.xml
new file mode 100644
index 000000000..2292a9e5c
--- /dev/null
+++ b/PermissionController/res/drawable-v33/indicator_background_circle.xml
@@ -0,0 +1,29 @@
+<!--
+ ~ 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.
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+ <item android:id="@android:id/background">
+ <shape
+ android:shape="oval"
+ android:id="@id/background"
+ android:gravity="center">
+ <size
+ android:height="@dimen/ongoing_appops_dialog_circle_size"
+ android:width="@dimen/ongoing_appops_dialog_circle_size"/>
+ <solid android:color="@android:color/white"/>
+ </shape>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/more_issues_collapse_anim.xml b/PermissionController/res/drawable-v33/more_issues_collapse_anim.xml
new file mode 100644
index 000000000..8bac610bf
--- /dev/null
+++ b/PermissionController/res/drawable-v33/more_issues_collapse_anim.xml
@@ -0,0 +1,311 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="240dp"
+ android:height="240dp"
+ android:viewportWidth="240"
+ android:viewportHeight="240">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="135.511"
+ android:translateY="123.157">
+ <group
+ android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:rotation="-45"
+ android:translateX="-35"
+ android:translateY="-3.157">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?android:attr/textColorPrimary"
+ android:fillType="nonZero"
+ android:pathData=" M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.36,-6 30.36,-6 C30.36,-6 32.5,-6 32.5,-6c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"
+ android:rotation="45"
+ android:translateX="2.5"
+ android:translateY="-3.157">
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?android:attr/textColorPrimary"
+ android:fillType="nonZero"
+ android:pathData=" M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -27.84,6 -27.84,6 C-27.84,6 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 -30.39,-6 -30.39,-6 C-30.39,-6 32.5,-6 32.5,-6c " />
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-45"
+ android:valueTo="45"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.36,-6 30.36,-6 C30.36,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M26.11 -4.58 C26.11,-4.58 31.89,5.93 31.89,5.93 C31.89,5.93 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 25.42,-6 25.42,-6 C25.42,-6 26.11,-4.58 26.11,-4.58c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="17"
+ android:valueFrom="M26.11 -4.58 C26.11,-4.58 31.89,5.93 31.89,5.93 C31.89,5.93 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 25.42,-6 25.42,-6 C25.42,-6 26.11,-4.58 26.11,-4.58c "
+ android:valueTo="M26.82 -4.74 C26.82,-4.74 31.96,5.93 31.96,5.93 C31.96,5.93 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 25.97,-6 25.97,-6 C25.97,-6 26.82,-4.74 26.82,-4.74c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="33"
+ android:valueFrom="M26.82 -4.74 C26.82,-4.74 31.96,5.93 31.96,5.93 C31.96,5.93 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 25.97,-6 25.97,-6 C25.97,-6 26.82,-4.74 26.82,-4.74c "
+ android:valueTo="M27.53 -4.9 C27.53,-4.9 21.59,5.98 21.59,5.98 C21.59,5.98 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 26.52,-6 26.52,-6 C26.52,-6 27.53,-4.9 27.53,-4.9c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="pathData"
+ android:startOffset="50"
+ android:valueFrom="M27.53 -4.9 C27.53,-4.9 21.59,5.98 21.59,5.98 C21.59,5.98 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 26.52,-6 26.52,-6 C26.52,-6 27.53,-4.9 27.53,-4.9c "
+ android:valueTo="M28.95 -5.21 C28.95,-5.21 26.96,5.75 26.96,5.75 C26.96,5.75 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 27.62,-6 27.62,-6 C27.62,-6 28.95,-5.21 28.95,-5.21c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="83"
+ android:valueFrom="M28.95 -5.21 C28.95,-5.21 26.96,5.75 26.96,5.75 C26.96,5.75 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 27.62,-6 27.62,-6 C27.62,-6 28.95,-5.21 28.95,-5.21c "
+ android:valueTo="M29.66 -5.37 C29.66,-5.37 29.2,5.22 29.2,5.22 C29.2,5.22 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 28.16,-6 28.16,-6 C28.16,-6 29.66,-5.37 29.66,-5.37c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="100"
+ android:valueFrom="M29.66 -5.37 C29.66,-5.37 29.2,5.22 29.2,5.22 C29.2,5.22 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 28.16,-6 28.16,-6 C28.16,-6 29.66,-5.37 29.66,-5.37c "
+ android:valueTo="M30.37 -5.53 C30.37,-5.53 30.63,4.87 30.63,4.87 C30.63,4.87 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 28.71,-6 28.71,-6 C28.71,-6 30.37,-5.53 30.37,-5.53c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="117"
+ android:valueFrom="M30.37 -5.53 C30.37,-5.53 30.63,4.87 30.63,4.87 C30.63,4.87 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 28.71,-6 28.71,-6 C28.71,-6 30.37,-5.53 30.37,-5.53c "
+ android:valueTo="M31.08 -5.68 C31.08,-5.68 31.7,4.9 31.7,4.9 C31.7,4.9 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 29.26,-6 29.26,-6 C29.26,-6 31.08,-5.68 31.08,-5.68c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="133"
+ android:valueFrom="M31.08 -5.68 C31.08,-5.68 31.7,4.9 31.7,4.9 C31.7,4.9 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 29.26,-6 29.26,-6 C29.26,-6 31.08,-5.68 31.08,-5.68c "
+ android:valueTo="M31.79 -5.84 C31.79,-5.84 31.71,5.05 31.71,5.05 C31.71,5.05 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 29.81,-6 29.81,-6 C29.81,-6 31.79,-5.84 31.79,-5.84c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="150"
+ android:valueFrom="M31.79 -5.84 C31.79,-5.84 31.71,5.05 31.71,5.05 C31.71,5.05 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 29.81,-6 29.81,-6 C29.81,-6 31.79,-5.84 31.79,-5.84c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.37,5.78 32.37,5.78 C32.37,5.78 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.36,-6 30.36,-6 C30.36,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="45"
+ android:valueTo="-45"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -27.84,6 -27.84,6 C-27.84,6 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 -30.39,-6 -30.39,-6 C-30.39,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -27.29,6.01 -27.29,6.01 C-27.29,6.01 -31.91,6.01 -31.91,6.01 C-31.91,6.01 -25.64,-5.37 -25.64,-5.37 C-25.64,-5.37 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="17"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -27.29,6.01 -27.29,6.01 C-27.29,6.01 -31.91,6.01 -31.91,6.01 C-31.91,6.01 -25.64,-5.37 -25.64,-5.37 C-25.64,-5.37 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -27.29,6.01 -27.29,6.01 C-27.29,6.01 -31.91,6.01 -31.91,6.01 C-31.91,6.01 -25.64,-5.37 -25.64,-5.37 C-25.64,-5.37 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="33"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -27.29,6.01 -27.29,6.01 C-27.29,6.01 -31.91,6.01 -31.91,6.01 C-31.91,6.01 -25.64,-5.37 -25.64,-5.37 C-25.64,-5.37 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -21.36,6.01 -21.36,6.01 C-21.36,6.01 -25.51,2.6 -25.51,2.6 C-25.51,2.6 -25.64,-5.37 -25.64,-5.37 C-25.64,-5.37 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="50"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -21.36,6.01 -21.36,6.01 C-21.36,6.01 -25.51,2.6 -25.51,2.6 C-25.51,2.6 -25.64,-5.37 -25.64,-5.37 C-25.64,-5.37 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -24.02,6.12 -24.02,6.12 C-24.02,6.12 -26.5,2.93 -26.5,2.93 C-26.5,2.93 -26.6,-5.46 -26.6,-5.46 C-26.6,-5.46 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="67"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -24.02,6.12 -24.02,6.12 C-24.02,6.12 -26.5,2.93 -26.5,2.93 C-26.5,2.93 -26.6,-5.46 -26.6,-5.46 C-26.6,-5.46 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -26.4,6.16 -26.4,6.16 C-26.4,6.16 -27.48,3.42 -27.48,3.42 C-27.48,3.42 -27.56,-5.55 -27.56,-5.55 C-27.56,-5.55 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="83"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -26.4,6.16 -26.4,6.16 C-26.4,6.16 -27.48,3.42 -27.48,3.42 C-27.48,3.42 -27.56,-5.55 -27.56,-5.55 C-27.56,-5.55 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -28.01,6.2 -28.01,6.2 C-28.01,6.2 -28.47,3.91 -28.47,3.91 C-28.47,3.91 -28.52,-5.64 -28.52,-5.64 C-28.52,-5.64 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="100"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -28.01,6.2 -28.01,6.2 C-28.01,6.2 -28.47,3.91 -28.47,3.91 C-28.47,3.91 -28.52,-5.64 -28.52,-5.64 C-28.52,-5.64 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -29.36,6.06 -29.36,6.06 C-29.36,6.06 -29.45,4.4 -29.45,4.4 C-29.45,4.4 -29.48,-5.73 -29.48,-5.73 C-29.48,-5.73 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="117"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -29.36,6.06 -29.36,6.06 C-29.36,6.06 -29.45,4.4 -29.45,4.4 C-29.45,4.4 -29.48,-5.73 -29.48,-5.73 C-29.48,-5.73 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -30.54,6 -30.54,6 C-30.54,6 -30.44,4.89 -30.44,4.89 C-30.44,4.89 -30.44,-5.82 -30.44,-5.82 C-30.44,-5.82 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="133"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -30.54,6 -30.54,6 C-30.54,6 -30.44,4.89 -30.44,4.89 C-30.44,4.89 -30.44,-5.82 -30.44,-5.82 C-30.44,-5.82 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -25.85,5.67 -25.85,5.67 C-25.85,5.67 -31.42,5.38 -31.42,5.38 C-31.42,5.38 -31.4,-5.91 -31.4,-5.91 C-31.4,-5.91 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="150"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -25.85,5.67 -25.85,5.67 C-25.85,5.67 -31.42,5.38 -31.42,5.38 C-31.42,5.38 -31.4,-5.91 -31.4,-5.91 C-31.4,-5.91 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -21.36,6.01 -21.36,6.01 C-21.36,6.01 -32.41,5.87 -32.41,5.87 C-32.41,5.87 -32.36,-5.99 -32.36,-5.99 C-32.36,-5.99 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="183"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/more_issues_expand_anim.xml b/PermissionController/res/drawable-v33/more_issues_expand_anim.xml
new file mode 100644
index 000000000..048b74a30
--- /dev/null
+++ b/PermissionController/res/drawable-v33/more_issues_expand_anim.xml
@@ -0,0 +1,267 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="240dp"
+ android:height="240dp"
+ android:viewportWidth="240"
+ android:viewportHeight="240">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="135.511"
+ android:translateY="123.157">
+ <group
+ android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:rotation="45"
+ android:translateX="-35"
+ android:translateY="-3.157">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?android:attr/textColorPrimary"
+ android:fillType="nonZero"
+ android:pathData=" M32.5 -6 C32.5,-6 32.37,5.78 32.37,5.78 C32.37,5.78 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.36,-6 30.36,-6 C30.36,-6 32.5,-6 32.5,-6c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"
+ android:rotation="-45"
+ android:translateX="2.5"
+ android:translateY="-3.157">
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?android:attr/textColorPrimary"
+ android:fillType="nonZero"
+ android:pathData=" M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -21.36,6.01 -21.36,6.01 C-21.36,6.01 -32.41,5.87 -32.41,5.87 C-32.41,5.87 -32.36,-5.99 -32.36,-5.99 C-32.36,-5.99 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c " />
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="45"
+ android:valueTo="-45"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.37,5.78 32.37,5.78 C32.37,5.78 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.36,-6 30.36,-6 C30.36,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M31.86 -5.98 C31.86,-5.98 25.7,5.72 25.7,5.72 C25.7,5.72 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.36,-6 30.36,-6 C30.36,-6 31.86,-5.98 31.86,-5.98c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="pathData"
+ android:startOffset="17"
+ android:valueFrom="M31.86 -5.98 C31.86,-5.98 25.7,5.72 25.7,5.72 C25.7,5.72 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.36,-6 30.36,-6 C30.36,-6 31.86,-5.98 31.86,-5.98c "
+ android:valueTo="M27.06 -1.54 C27.06,-1.54 27.21,5.79 27.21,5.79 C27.21,5.79 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 21.3,-5.98 21.3,-5.98 C21.3,-5.98 27.06,-1.54 27.06,-1.54c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="50"
+ android:valueFrom="M27.06 -1.54 C27.06,-1.54 27.21,5.79 27.21,5.79 C27.21,5.79 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 21.3,-5.98 21.3,-5.98 C21.3,-5.98 27.06,-1.54 27.06,-1.54c "
+ android:valueTo="M26.17 -1.74 C26.17,-1.74 27.97,5.82 27.97,5.82 C27.97,5.82 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 24.54,-5.12 24.54,-5.12 C24.54,-5.12 26.17,-1.74 26.17,-1.74c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="67"
+ android:valueFrom="M26.17 -1.74 C26.17,-1.74 27.97,5.82 27.97,5.82 C27.97,5.82 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 24.54,-5.12 24.54,-5.12 C24.54,-5.12 26.17,-1.74 26.17,-1.74c "
+ android:valueTo="M27.22 -2.45 C27.22,-2.45 28.72,5.85 28.72,5.85 C28.72,5.85 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 26.96,-5.01 26.96,-5.01 C26.96,-5.01 27.22,-2.45 27.22,-2.45c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="83"
+ android:valueFrom="M27.22 -2.45 C27.22,-2.45 28.72,5.85 28.72,5.85 C28.72,5.85 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 26.96,-5.01 26.96,-5.01 C26.96,-5.01 27.22,-2.45 27.22,-2.45c "
+ android:valueTo="M28.28 -3.16 C28.28,-3.16 29.48,5.88 29.48,5.88 C29.48,5.88 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 28.94,-4.93 28.94,-4.93 C28.94,-4.93 28.28,-3.16 28.28,-3.16c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="100"
+ android:valueFrom="M28.28 -3.16 C28.28,-3.16 29.48,5.88 29.48,5.88 C29.48,5.88 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 28.94,-4.93 28.94,-4.93 C28.94,-4.93 28.28,-3.16 28.28,-3.16c "
+ android:valueTo="M29.33 -3.87 C29.33,-3.87 30.23,5.91 30.23,5.91 C30.23,5.91 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.46,-4.91 30.46,-4.91 C30.46,-4.91 29.33,-3.87 29.33,-3.87c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="pathData"
+ android:startOffset="117"
+ android:valueFrom="M29.33 -3.87 C29.33,-3.87 30.23,5.91 30.23,5.91 C30.23,5.91 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.46,-4.91 30.46,-4.91 C30.46,-4.91 29.33,-3.87 29.33,-3.87c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.36,-6 30.36,-6 C30.36,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-45"
+ android:valueTo="45"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -21.36,6.01 -21.36,6.01 C-21.36,6.01 -32.41,5.87 -32.41,5.87 C-32.41,5.87 -32.36,-5.99 -32.36,-5.99 C-32.36,-5.99 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -22.01,6.01 -22.01,6.01 C-22.01,6.01 -25.12,6.11 -25.12,6.11 C-25.12,6.11 -31.67,-5.94 -31.67,-5.94 C-31.67,-5.94 -25.96,-6 -25.96,-6 C-25.96,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="17"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -22.01,6.01 -22.01,6.01 C-22.01,6.01 -25.12,6.11 -25.12,6.11 C-25.12,6.11 -31.67,-5.94 -31.67,-5.94 C-31.67,-5.94 -25.96,-6 -25.96,-6 C-25.96,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -22.66,6.01 -22.66,6.01 C-22.66,6.01 -26,5.97 -26,5.97 C-26,5.97 -31.77,-5.95 -31.77,-5.95 C-31.77,-5.95 -26.46,-6 -26.46,-6 C-26.46,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="33"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -22.66,6.01 -22.66,6.01 C-22.66,6.01 -26,5.97 -26,5.97 C-26,5.97 -31.77,-5.95 -31.77,-5.95 C-31.77,-5.95 -26.46,-6 -26.46,-6 C-26.46,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -23.31,6.01 -23.31,6.01 C-23.31,6.01 -26.76,6.08 -26.76,6.08 C-26.76,6.08 -21.55,-5.9 -21.55,-5.9 C-21.55,-5.9 -21.18,-5.93 -21.18,-5.93 C-21.18,-5.93 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="50"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -23.31,6.01 -23.31,6.01 C-23.31,6.01 -26.76,6.08 -26.76,6.08 C-26.76,6.08 -21.55,-5.9 -21.55,-5.9 C-21.55,-5.9 -21.18,-5.93 -21.18,-5.93 C-21.18,-5.93 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -23.96,6.01 -23.96,6.01 C-23.96,6.01 -27.58,6.07 -27.58,6.07 C-27.58,6.07 -23.19,-5.85 -23.19,-5.85 C-23.19,-5.85 -23.19,-5.86 -23.19,-5.86 C-23.19,-5.86 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="67"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -23.96,6.01 -23.96,6.01 C-23.96,6.01 -27.58,6.07 -27.58,6.07 C-27.58,6.07 -23.19,-5.85 -23.19,-5.85 C-23.19,-5.85 -23.19,-5.86 -23.19,-5.86 C-23.19,-5.86 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -24.6,6.01 -24.6,6.01 C-24.6,6.01 -28.4,6.06 -28.4,6.06 C-28.4,6.06 -25.62,-5.84 -25.62,-5.84 C-25.62,-5.84 -25.63,-5.85 -25.63,-5.85 C-25.63,-5.85 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="83"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -24.6,6.01 -24.6,6.01 C-24.6,6.01 -28.4,6.06 -28.4,6.06 C-28.4,6.06 -25.62,-5.84 -25.62,-5.84 C-25.62,-5.84 -25.63,-5.85 -25.63,-5.85 C-25.63,-5.85 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -25.25,6 -25.25,6 C-25.25,6 -29.22,6.05 -29.22,6.05 C-29.22,6.05 -27.73,-5.89 -27.73,-5.89 C-27.73,-5.89 -27.72,-5.9 -27.72,-5.9 C-27.72,-5.9 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="100"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -25.25,6 -25.25,6 C-25.25,6 -29.22,6.05 -29.22,6.05 C-29.22,6.05 -27.73,-5.89 -27.73,-5.89 C-27.73,-5.89 -27.72,-5.9 -27.72,-5.9 C-27.72,-5.9 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -25.9,6 -25.9,6 C-25.9,6 -30.04,6.04 -30.04,6.04 C-30.04,6.04 -29.34,-5.92 -29.34,-5.92 C-29.34,-5.92 -29.34,-5.91 -29.34,-5.91 C-29.34,-5.91 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="pathData"
+ android:startOffset="117"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -25.9,6 -25.9,6 C-25.9,6 -30.04,6.04 -30.04,6.04 C-30.04,6.04 -29.34,-5.92 -29.34,-5.92 C-29.34,-5.92 -29.34,-5.91 -29.34,-5.91 C-29.34,-5.91 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -27.84,6 -27.84,6 C-27.84,6 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 -30.39,-6 -30.39,-6 C-30.39,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="183"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v31/safety_center_card_background.xml b/PermissionController/res/drawable-v33/safety_center_card_background.xml
index 2af4e43c4..e04b32f4f 100644
--- a/PermissionController/res/drawable-v31/safety_center_card_background.xml
+++ b/PermissionController/res/drawable-v33/safety_center_card_background.xml
@@ -16,6 +16,6 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="@color/safety_center_card_background" />
- <corners android:radius="28dp"/>
+ <solid android:color="?attr/colorSurface" />
+ <corners android:radius="@dimen/sc_card_corner_radius_large"/>
</shape> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_center_card_widget_background.xml b/PermissionController/res/drawable-v33/safety_center_card_widget_background.xml
new file mode 100644
index 000000000..f7ff2f2cb
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_center_card_widget_background.xml
@@ -0,0 +1,21 @@
+<?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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="?attr/colorSurfaceVariant" />
+ <corners android:radius="@dimen/sc_card_widget_corner_radius"/>
+</shape> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_center_group_collapse_anim.xml b/PermissionController/res/drawable-v33/safety_center_group_collapse_anim.xml
new file mode 100644
index 000000000..2c2a33e56
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_center_group_collapse_anim.xml
@@ -0,0 +1,324 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="240dp"
+ android:height="240dp"
+ android:viewportWidth="240"
+ android:viewportHeight="240">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:scaleX="8.34"
+ android:scaleY="8.34"
+ android:translateX="120"
+ android:translateY="120">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorSurfaceVariant"
+ android:fillType="nonZero"
+ android:pathData=" M12 0 C12,0 12,0 12,0 C12,6.62 6.62,12 0,12 C0,12 0,12 0,12 C-6.62,12 -12,6.62 -12,0 C-12,0 -12,0 -12,0 C-12,-6.62 -6.62,-12 0,-12 C0,-12 0,-12 0,-12 C6.62,-12 12,-6.62 12,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="135.511"
+ android:translateY="123.157">
+ <group
+ android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:rotation="-45"
+ android:translateX="-35"
+ android:translateY="-3.157">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?android:attr/textColorPrimary"
+ android:fillType="nonZero"
+ android:pathData=" M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.36,-6 30.36,-6 C30.36,-6 32.5,-6 32.5,-6c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"
+ android:rotation="45"
+ android:translateX="2.5"
+ android:translateY="-3.157">
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?android:attr/textColorPrimary"
+ android:fillType="nonZero"
+ android:pathData=" M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -27.84,6 -27.84,6 C-27.84,6 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 -30.39,-6 -30.39,-6 C-30.39,-6 32.5,-6 32.5,-6c " />
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-45"
+ android:valueTo="45"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.36,-6 30.36,-6 C30.36,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M26.11 -4.58 C26.11,-4.58 31.89,5.93 31.89,5.93 C31.89,5.93 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 25.42,-6 25.42,-6 C25.42,-6 26.11,-4.58 26.11,-4.58c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="17"
+ android:valueFrom="M26.11 -4.58 C26.11,-4.58 31.89,5.93 31.89,5.93 C31.89,5.93 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 25.42,-6 25.42,-6 C25.42,-6 26.11,-4.58 26.11,-4.58c "
+ android:valueTo="M26.82 -4.74 C26.82,-4.74 31.96,5.93 31.96,5.93 C31.96,5.93 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 25.97,-6 25.97,-6 C25.97,-6 26.82,-4.74 26.82,-4.74c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="33"
+ android:valueFrom="M26.82 -4.74 C26.82,-4.74 31.96,5.93 31.96,5.93 C31.96,5.93 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 25.97,-6 25.97,-6 C25.97,-6 26.82,-4.74 26.82,-4.74c "
+ android:valueTo="M27.53 -4.9 C27.53,-4.9 21.59,5.98 21.59,5.98 C21.59,5.98 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 26.52,-6 26.52,-6 C26.52,-6 27.53,-4.9 27.53,-4.9c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="pathData"
+ android:startOffset="50"
+ android:valueFrom="M27.53 -4.9 C27.53,-4.9 21.59,5.98 21.59,5.98 C21.59,5.98 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 26.52,-6 26.52,-6 C26.52,-6 27.53,-4.9 27.53,-4.9c "
+ android:valueTo="M28.95 -5.21 C28.95,-5.21 26.96,5.75 26.96,5.75 C26.96,5.75 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 27.62,-6 27.62,-6 C27.62,-6 28.95,-5.21 28.95,-5.21c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="83"
+ android:valueFrom="M28.95 -5.21 C28.95,-5.21 26.96,5.75 26.96,5.75 C26.96,5.75 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 27.62,-6 27.62,-6 C27.62,-6 28.95,-5.21 28.95,-5.21c "
+ android:valueTo="M29.66 -5.37 C29.66,-5.37 29.2,5.22 29.2,5.22 C29.2,5.22 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 28.16,-6 28.16,-6 C28.16,-6 29.66,-5.37 29.66,-5.37c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="100"
+ android:valueFrom="M29.66 -5.37 C29.66,-5.37 29.2,5.22 29.2,5.22 C29.2,5.22 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 28.16,-6 28.16,-6 C28.16,-6 29.66,-5.37 29.66,-5.37c "
+ android:valueTo="M30.37 -5.53 C30.37,-5.53 30.63,4.87 30.63,4.87 C30.63,4.87 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 28.71,-6 28.71,-6 C28.71,-6 30.37,-5.53 30.37,-5.53c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="117"
+ android:valueFrom="M30.37 -5.53 C30.37,-5.53 30.63,4.87 30.63,4.87 C30.63,4.87 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 28.71,-6 28.71,-6 C28.71,-6 30.37,-5.53 30.37,-5.53c "
+ android:valueTo="M31.08 -5.68 C31.08,-5.68 31.7,4.9 31.7,4.9 C31.7,4.9 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 29.26,-6 29.26,-6 C29.26,-6 31.08,-5.68 31.08,-5.68c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="133"
+ android:valueFrom="M31.08 -5.68 C31.08,-5.68 31.7,4.9 31.7,4.9 C31.7,4.9 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 29.26,-6 29.26,-6 C29.26,-6 31.08,-5.68 31.08,-5.68c "
+ android:valueTo="M31.79 -5.84 C31.79,-5.84 31.71,5.05 31.71,5.05 C31.71,5.05 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 29.81,-6 29.81,-6 C29.81,-6 31.79,-5.84 31.79,-5.84c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="150"
+ android:valueFrom="M31.79 -5.84 C31.79,-5.84 31.71,5.05 31.71,5.05 C31.71,5.05 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 29.81,-6 29.81,-6 C29.81,-6 31.79,-5.84 31.79,-5.84c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.37,5.78 32.37,5.78 C32.37,5.78 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.36,-6 30.36,-6 C30.36,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="45"
+ android:valueTo="-45"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -27.84,6 -27.84,6 C-27.84,6 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 -30.39,-6 -30.39,-6 C-30.39,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -27.29,6.01 -27.29,6.01 C-27.29,6.01 -31.91,6.01 -31.91,6.01 C-31.91,6.01 -25.64,-5.37 -25.64,-5.37 C-25.64,-5.37 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="17"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -27.29,6.01 -27.29,6.01 C-27.29,6.01 -31.91,6.01 -31.91,6.01 C-31.91,6.01 -25.64,-5.37 -25.64,-5.37 C-25.64,-5.37 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -27.29,6.01 -27.29,6.01 C-27.29,6.01 -31.91,6.01 -31.91,6.01 C-31.91,6.01 -25.64,-5.37 -25.64,-5.37 C-25.64,-5.37 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="33"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -27.29,6.01 -27.29,6.01 C-27.29,6.01 -31.91,6.01 -31.91,6.01 C-31.91,6.01 -25.64,-5.37 -25.64,-5.37 C-25.64,-5.37 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -21.36,6.01 -21.36,6.01 C-21.36,6.01 -25.51,2.6 -25.51,2.6 C-25.51,2.6 -25.64,-5.37 -25.64,-5.37 C-25.64,-5.37 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="50"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -21.36,6.01 -21.36,6.01 C-21.36,6.01 -25.51,2.6 -25.51,2.6 C-25.51,2.6 -25.64,-5.37 -25.64,-5.37 C-25.64,-5.37 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -24.02,6.12 -24.02,6.12 C-24.02,6.12 -26.5,2.93 -26.5,2.93 C-26.5,2.93 -26.6,-5.46 -26.6,-5.46 C-26.6,-5.46 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="67"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -24.02,6.12 -24.02,6.12 C-24.02,6.12 -26.5,2.93 -26.5,2.93 C-26.5,2.93 -26.6,-5.46 -26.6,-5.46 C-26.6,-5.46 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -26.4,6.16 -26.4,6.16 C-26.4,6.16 -27.48,3.42 -27.48,3.42 C-27.48,3.42 -27.56,-5.55 -27.56,-5.55 C-27.56,-5.55 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="83"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -26.4,6.16 -26.4,6.16 C-26.4,6.16 -27.48,3.42 -27.48,3.42 C-27.48,3.42 -27.56,-5.55 -27.56,-5.55 C-27.56,-5.55 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -28.01,6.2 -28.01,6.2 C-28.01,6.2 -28.47,3.91 -28.47,3.91 C-28.47,3.91 -28.52,-5.64 -28.52,-5.64 C-28.52,-5.64 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="100"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -28.01,6.2 -28.01,6.2 C-28.01,6.2 -28.47,3.91 -28.47,3.91 C-28.47,3.91 -28.52,-5.64 -28.52,-5.64 C-28.52,-5.64 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -29.36,6.06 -29.36,6.06 C-29.36,6.06 -29.45,4.4 -29.45,4.4 C-29.45,4.4 -29.48,-5.73 -29.48,-5.73 C-29.48,-5.73 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="117"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -29.36,6.06 -29.36,6.06 C-29.36,6.06 -29.45,4.4 -29.45,4.4 C-29.45,4.4 -29.48,-5.73 -29.48,-5.73 C-29.48,-5.73 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -30.54,6 -30.54,6 C-30.54,6 -30.44,4.89 -30.44,4.89 C-30.44,4.89 -30.44,-5.82 -30.44,-5.82 C-30.44,-5.82 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="133"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -30.54,6 -30.54,6 C-30.54,6 -30.44,4.89 -30.44,4.89 C-30.44,4.89 -30.44,-5.82 -30.44,-5.82 C-30.44,-5.82 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -25.85,5.67 -25.85,5.67 C-25.85,5.67 -31.42,5.38 -31.42,5.38 C-31.42,5.38 -31.4,-5.91 -31.4,-5.91 C-31.4,-5.91 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="150"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -25.85,5.67 -25.85,5.67 C-25.85,5.67 -31.42,5.38 -31.42,5.38 C-31.42,5.38 -31.4,-5.91 -31.4,-5.91 C-31.4,-5.91 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -21.36,6.01 -21.36,6.01 C-21.36,6.01 -32.41,5.87 -32.41,5.87 C-32.41,5.87 -32.36,-5.99 -32.36,-5.99 C-32.36,-5.99 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="183"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_center_group_expand_anim.xml b/PermissionController/res/drawable-v33/safety_center_group_expand_anim.xml
new file mode 100644
index 000000000..46102721b
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_center_group_expand_anim.xml
@@ -0,0 +1,280 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="240dp"
+ android:height="240dp"
+ android:viewportWidth="240"
+ android:viewportHeight="240">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:scaleX="8.34"
+ android:scaleY="8.34"
+ android:translateX="120"
+ android:translateY="120">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorSurfaceVariant"
+ android:fillType="nonZero"
+ android:pathData=" M12 0 C12,0 12,0 12,0 C12,6.62 6.62,12 0,12 C0,12 0,12 0,12 C-6.62,12 -12,6.62 -12,0 C-12,0 -12,0 -12,0 C-12,-6.62 -6.62,-12 0,-12 C0,-12 0,-12 0,-12 C6.62,-12 12,-6.62 12,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="135.511"
+ android:translateY="123.157">
+ <group
+ android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:rotation="45"
+ android:translateX="-35"
+ android:translateY="-3.157">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?android:attr/textColorPrimary"
+ android:fillType="nonZero"
+ android:pathData=" M32.5 -6 C32.5,-6 32.37,5.78 32.37,5.78 C32.37,5.78 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.36,-6 30.36,-6 C30.36,-6 32.5,-6 32.5,-6c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"
+ android:rotation="-45"
+ android:translateX="2.5"
+ android:translateY="-3.157">
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?android:attr/textColorPrimary"
+ android:fillType="nonZero"
+ android:pathData=" M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -21.36,6.01 -21.36,6.01 C-21.36,6.01 -32.41,5.87 -32.41,5.87 C-32.41,5.87 -32.36,-5.99 -32.36,-5.99 C-32.36,-5.99 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c " />
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="45"
+ android:valueTo="-45"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.37,5.78 32.37,5.78 C32.37,5.78 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.36,-6 30.36,-6 C30.36,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M31.86 -5.98 C31.86,-5.98 25.7,5.72 25.7,5.72 C25.7,5.72 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.36,-6 30.36,-6 C30.36,-6 31.86,-5.98 31.86,-5.98c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="pathData"
+ android:startOffset="17"
+ android:valueFrom="M31.86 -5.98 C31.86,-5.98 25.7,5.72 25.7,5.72 C25.7,5.72 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.36,-6 30.36,-6 C30.36,-6 31.86,-5.98 31.86,-5.98c "
+ android:valueTo="M27.06 -1.54 C27.06,-1.54 27.21,5.79 27.21,5.79 C27.21,5.79 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 21.3,-5.98 21.3,-5.98 C21.3,-5.98 27.06,-1.54 27.06,-1.54c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="50"
+ android:valueFrom="M27.06 -1.54 C27.06,-1.54 27.21,5.79 27.21,5.79 C27.21,5.79 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 21.3,-5.98 21.3,-5.98 C21.3,-5.98 27.06,-1.54 27.06,-1.54c "
+ android:valueTo="M26.17 -1.74 C26.17,-1.74 27.97,5.82 27.97,5.82 C27.97,5.82 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 24.54,-5.12 24.54,-5.12 C24.54,-5.12 26.17,-1.74 26.17,-1.74c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="67"
+ android:valueFrom="M26.17 -1.74 C26.17,-1.74 27.97,5.82 27.97,5.82 C27.97,5.82 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 24.54,-5.12 24.54,-5.12 C24.54,-5.12 26.17,-1.74 26.17,-1.74c "
+ android:valueTo="M27.22 -2.45 C27.22,-2.45 28.72,5.85 28.72,5.85 C28.72,5.85 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 26.96,-5.01 26.96,-5.01 C26.96,-5.01 27.22,-2.45 27.22,-2.45c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="83"
+ android:valueFrom="M27.22 -2.45 C27.22,-2.45 28.72,5.85 28.72,5.85 C28.72,5.85 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 26.96,-5.01 26.96,-5.01 C26.96,-5.01 27.22,-2.45 27.22,-2.45c "
+ android:valueTo="M28.28 -3.16 C28.28,-3.16 29.48,5.88 29.48,5.88 C29.48,5.88 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 28.94,-4.93 28.94,-4.93 C28.94,-4.93 28.28,-3.16 28.28,-3.16c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="100"
+ android:valueFrom="M28.28 -3.16 C28.28,-3.16 29.48,5.88 29.48,5.88 C29.48,5.88 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 28.94,-4.93 28.94,-4.93 C28.94,-4.93 28.28,-3.16 28.28,-3.16c "
+ android:valueTo="M29.33 -3.87 C29.33,-3.87 30.23,5.91 30.23,5.91 C30.23,5.91 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.46,-4.91 30.46,-4.91 C30.46,-4.91 29.33,-3.87 29.33,-3.87c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="pathData"
+ android:startOffset="117"
+ android:valueFrom="M29.33 -3.87 C29.33,-3.87 30.23,5.91 30.23,5.91 C30.23,5.91 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.46,-4.91 30.46,-4.91 C30.46,-4.91 29.33,-3.87 29.33,-3.87c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 30.36,-6 30.36,-6 C30.36,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-45"
+ android:valueTo="45"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -21.36,6.01 -21.36,6.01 C-21.36,6.01 -32.41,5.87 -32.41,5.87 C-32.41,5.87 -32.36,-5.99 -32.36,-5.99 C-32.36,-5.99 -25.47,-6 -25.47,-6 C-25.47,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -22.01,6.01 -22.01,6.01 C-22.01,6.01 -25.12,6.11 -25.12,6.11 C-25.12,6.11 -31.67,-5.94 -31.67,-5.94 C-31.67,-5.94 -25.96,-6 -25.96,-6 C-25.96,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="17"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -22.01,6.01 -22.01,6.01 C-22.01,6.01 -25.12,6.11 -25.12,6.11 C-25.12,6.11 -31.67,-5.94 -31.67,-5.94 C-31.67,-5.94 -25.96,-6 -25.96,-6 C-25.96,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -22.66,6.01 -22.66,6.01 C-22.66,6.01 -26,5.97 -26,5.97 C-26,5.97 -31.77,-5.95 -31.77,-5.95 C-31.77,-5.95 -26.46,-6 -26.46,-6 C-26.46,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="33"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -22.66,6.01 -22.66,6.01 C-22.66,6.01 -26,5.97 -26,5.97 C-26,5.97 -31.77,-5.95 -31.77,-5.95 C-31.77,-5.95 -26.46,-6 -26.46,-6 C-26.46,-6 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -23.31,6.01 -23.31,6.01 C-23.31,6.01 -26.76,6.08 -26.76,6.08 C-26.76,6.08 -21.55,-5.9 -21.55,-5.9 C-21.55,-5.9 -21.18,-5.93 -21.18,-5.93 C-21.18,-5.93 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="50"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -23.31,6.01 -23.31,6.01 C-23.31,6.01 -26.76,6.08 -26.76,6.08 C-26.76,6.08 -21.55,-5.9 -21.55,-5.9 C-21.55,-5.9 -21.18,-5.93 -21.18,-5.93 C-21.18,-5.93 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -23.96,6.01 -23.96,6.01 C-23.96,6.01 -27.58,6.07 -27.58,6.07 C-27.58,6.07 -23.19,-5.85 -23.19,-5.85 C-23.19,-5.85 -23.19,-5.86 -23.19,-5.86 C-23.19,-5.86 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="67"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -23.96,6.01 -23.96,6.01 C-23.96,6.01 -27.58,6.07 -27.58,6.07 C-27.58,6.07 -23.19,-5.85 -23.19,-5.85 C-23.19,-5.85 -23.19,-5.86 -23.19,-5.86 C-23.19,-5.86 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -24.6,6.01 -24.6,6.01 C-24.6,6.01 -28.4,6.06 -28.4,6.06 C-28.4,6.06 -25.62,-5.84 -25.62,-5.84 C-25.62,-5.84 -25.63,-5.85 -25.63,-5.85 C-25.63,-5.85 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="83"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -24.6,6.01 -24.6,6.01 C-24.6,6.01 -28.4,6.06 -28.4,6.06 C-28.4,6.06 -25.62,-5.84 -25.62,-5.84 C-25.62,-5.84 -25.63,-5.85 -25.63,-5.85 C-25.63,-5.85 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -25.25,6 -25.25,6 C-25.25,6 -29.22,6.05 -29.22,6.05 C-29.22,6.05 -27.73,-5.89 -27.73,-5.89 C-27.73,-5.89 -27.72,-5.9 -27.72,-5.9 C-27.72,-5.9 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="pathData"
+ android:startOffset="100"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -25.25,6 -25.25,6 C-25.25,6 -29.22,6.05 -29.22,6.05 C-29.22,6.05 -27.73,-5.89 -27.73,-5.89 C-27.73,-5.89 -27.72,-5.9 -27.72,-5.9 C-27.72,-5.9 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -25.9,6 -25.9,6 C-25.9,6 -30.04,6.04 -30.04,6.04 C-30.04,6.04 -29.34,-5.92 -29.34,-5.92 C-29.34,-5.92 -29.34,-5.91 -29.34,-5.91 C-29.34,-5.91 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="pathData"
+ android:startOffset="117"
+ android:valueFrom="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -25.9,6 -25.9,6 C-25.9,6 -30.04,6.04 -30.04,6.04 C-30.04,6.04 -29.34,-5.92 -29.34,-5.92 C-29.34,-5.92 -29.34,-5.91 -29.34,-5.91 C-29.34,-5.91 32.5,-6 32.5,-6c "
+ android:valueTo="M32.5 -6 C32.5,-6 32.5,6 32.5,6 C32.5,6 -27.84,6 -27.84,6 C-27.84,6 -32.5,6 -32.5,6 C-32.5,6 -32.5,-6 -32.5,-6 C-32.5,-6 -30.39,-6 -30.39,-6 C-30.39,-6 32.5,-6 32.5,-6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="183"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_center_issue_resolved_avd.xml b/PermissionController/res/drawable-v33/safety_center_issue_resolved_avd.xml
new file mode 100644
index 000000000..7d27c1ad2
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_center_issue_resolved_avd.xml
@@ -0,0 +1,157 @@
+<!--
+ ~ 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.
+ -->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="112dp"
+ android:height="112dp"
+ android:viewportHeight="112"
+ android:viewportWidth="112">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="56.5"
+ android:translateY="56.625">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="?android:attr/textColorPrimary"
+ android:fillType="nonZero"
+ android:pathData=" M-14.75 -0.59 C-14.75,-0.59 -15.32,-1.16 -15.32,-1.16 C-15.32,-1.16 -14.67,-0.73 -14.67,-0.73 C-14.67,-0.73 -14.39,-0.44 -14.39,-0.44 C-14.39,-0.44 -17.32,2.5 -17.32,2.5 C-17.32,2.5 -17.59,2.23 -17.59,2.23 C-17.59,2.23 -14.75,-0.59 -14.75,-0.59c "
+ android:trimPathEnd="1"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:rotation="-90"
+ android:translateX="56"
+ android:translateY="56">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:pathData=" M53.5 0 C53.5,-29.53 29.53,-53.5 0,-53.5 C0,-53.5 0,-53.5 0,-53.5 C-29.53,-53.5 -53.5,-29.53 -53.5,0 C-53.5,0 -53.5,0 -53.5,0 C-53.5,29.53 -29.53,53.5 0,53.5 C0,53.5 0,53.5 0,53.5 C29.53,53.5 53.5,29.53 53.5,0 C53.5,0 53.5,0 53.5,0c "
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/textColorTertiary"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="5"
+ android:trimPathEnd="0"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="400"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="400"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="400"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M-14.75 -0.59 C-14.75,-0.59 -15.32,-1.16 -15.32,-1.16 C-15.32,-1.16 -14.67,-0.73 -14.67,-0.73 C-14.67,-0.73 -14.39,-0.44 -14.39,-0.44 C-14.39,-0.44 -17.32,2.5 -17.32,2.5 C-17.32,2.5 -17.59,2.23 -17.59,2.23 C-17.59,2.23 -14.75,-0.59 -14.75,-0.59c "
+ android:valueTo="M-14.75 -0.59 C-14.75,-0.59 -15.32,-1.16 -15.32,-1.16 C-15.32,-1.16 -14.67,-0.73 -14.67,-0.73 C-14.67,-0.73 -14.39,-0.44 -14.39,-0.44 C-14.39,-0.44 -17.32,2.5 -17.32,2.5 C-17.32,2.5 -17.59,2.23 -17.59,2.23 C-17.59,2.23 -14.75,-0.59 -14.75,-0.59c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="pathData"
+ android:startOffset="400"
+ android:valueFrom="M-14.75 -0.59 C-14.75,-0.59 -15.32,-1.16 -15.32,-1.16 C-15.32,-1.16 -14.67,-0.73 -14.67,-0.73 C-14.67,-0.73 -14.39,-0.44 -14.39,-0.44 C-14.39,-0.44 -17.32,2.5 -17.32,2.5 C-17.32,2.5 -17.59,2.23 -17.59,2.23 C-17.59,2.23 -14.75,-0.59 -14.75,-0.59c "
+ android:valueTo="M-14.75 -0.59 C-14.75,-0.59 -6.41,7.75 -6.41,7.75 C-6.41,7.75 -6.3,7.65 -6.3,7.65 C-6.3,7.65 -3.48,10.47 -3.48,10.47 C-3.48,10.47 -6.41,13.41 -6.41,13.41 C-6.41,13.41 -17.59,2.23 -17.59,2.23 C-17.59,2.23 -14.75,-0.59 -14.75,-0.59c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="pathData"
+ android:startOffset="483"
+ android:valueFrom="M-14.75 -0.59 C-14.75,-0.59 -6.41,7.75 -6.41,7.75 C-6.41,7.75 -6.3,7.65 -6.3,7.65 C-6.3,7.65 -3.48,10.47 -3.48,10.47 C-3.48,10.47 -6.41,13.41 -6.41,13.41 C-6.41,13.41 -17.59,2.23 -17.59,2.23 C-17.59,2.23 -14.75,-0.59 -14.75,-0.59c "
+ android:valueTo="M-14.75 -0.59 C-14.75,-0.59 -6.41,7.75 -6.41,7.75 C-6.41,7.75 14.77,-13.41 14.77,-13.41 C14.77,-13.41 17.59,-10.59 17.59,-10.59 C17.59,-10.59 -6.41,13.41 -6.41,13.41 C-6.41,13.41 -17.59,2.23 -17.59,2.23 C-17.59,2.23 -14.75,-0.59 -14.75,-0.59c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="500"
+ android:propertyName="trimPathEnd"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="667"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_center_more_issues_card_background.xml b/PermissionController/res/drawable-v33/safety_center_more_issues_card_background.xml
new file mode 100644
index 000000000..6c423a6d1
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_center_more_issues_card_background.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.
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+
+ <item>
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/sc_card_corner_radius_large" />
+ <solid android:color="?attr/colorSurface" />
+ </shape>
+ </item>
+
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/sc_card_corner_radius_large" />
+ <solid android:color="#FFFF" />
+ </shape>
+ </item>
+</ripple>
diff --git a/PermissionController/res/drawable-v33/safety_center_sensor_toggle_disabled.xml b/PermissionController/res/drawable-v33/safety_center_sensor_toggle_disabled.xml
new file mode 100644
index 000000000..364fbd9bb
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_center_sensor_toggle_disabled.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ 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.
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+ <item android:id="@android:id/background">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/safety_center_toggle_disabled"/>
+ <corners android:radius="24dp"/>
+ </shape>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_center_sensor_toggle_enabled.xml b/PermissionController/res/drawable-v33/safety_center_sensor_toggle_enabled.xml
new file mode 100644
index 000000000..dd6957e82
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_center_sensor_toggle_enabled.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ 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.
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+ <item android:id="@android:id/background">
+ <shape android:shape="rectangle">
+ <solid android:color="?android:attr/colorAccent"/>
+ <corners android:radius="24dp"/>
+ </shape>
+ </item>
+</ripple>
+
diff --git a/PermissionController/res/drawable-v33/safety_entity_top_flat_bottom_flat_background.xml b/PermissionController/res/drawable-v33/safety_entity_top_flat_bottom_flat_background.xml
new file mode 100644
index 000000000..18e99bd73
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_entity_top_flat_bottom_flat_background.xml
@@ -0,0 +1,22 @@
+<?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.
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+ <item>
+ <color android:color="?attr/colorSurface" />
+ </item>
+</ripple> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_entity_top_flat_bottom_large_background.xml b/PermissionController/res/drawable-v33/safety_entity_top_flat_bottom_large_background.xml
new file mode 100644
index 000000000..ef78867b8
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_entity_top_flat_bottom_large_background.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="?attr/colorSurface" />
+ <corners
+ android:bottomLeftRadius="@dimen/sc_card_corner_radius_large"
+ android:bottomRightRadius="@dimen/sc_card_corner_radius_large" />
+ </shape>
+ </item>
+
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <solid android:color="#FFFF" />
+ <corners
+ android:bottomLeftRadius="@dimen/sc_card_corner_radius_large"
+ android:bottomRightRadius="@dimen/sc_card_corner_radius_large" />
+ </shape>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_entity_top_flat_bottom_small_background.xml b/PermissionController/res/drawable-v33/safety_entity_top_flat_bottom_small_background.xml
new file mode 100644
index 000000000..dd455b0f6
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_entity_top_flat_bottom_small_background.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="?attr/colorSurface" />
+ <corners
+ android:bottomLeftRadius="@dimen/sc_card_corner_radius_xsmall"
+ android:bottomRightRadius="@dimen/sc_card_corner_radius_xsmall" />
+ </shape>
+ </item>
+
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <solid android:color="#FFFF" />
+ <corners
+ android:bottomLeftRadius="@dimen/sc_card_corner_radius_xsmall"
+ android:bottomRightRadius="@dimen/sc_card_corner_radius_xsmall" />
+ </shape>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_entity_top_large_bottom_flat_background.xml b/PermissionController/res/drawable-v33/safety_entity_top_large_bottom_flat_background.xml
new file mode 100644
index 000000000..2326ce4bd
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_entity_top_large_bottom_flat_background.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="?attr/colorSurface" />
+ <corners
+ android:topLeftRadius="@dimen/sc_card_corner_radius_large"
+ android:topRightRadius="@dimen/sc_card_corner_radius_large" />
+ </shape>
+ </item>
+
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <solid android:color="#FFFF" />
+ <corners
+ android:topLeftRadius="@dimen/sc_card_corner_radius_large"
+ android:topRightRadius="@dimen/sc_card_corner_radius_large" />
+ </shape>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_entity_top_large_bottom_large_background.xml b/PermissionController/res/drawable-v33/safety_entity_top_large_bottom_large_background.xml
new file mode 100644
index 000000000..a5a60e85b
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_entity_top_large_bottom_large_background.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.
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="?attr/colorSurface" />
+ <corners android:radius="@dimen/sc_card_corner_radius_large" />
+ </shape>
+ </item>
+
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <solid android:color="#FFFF" />
+ <corners android:radius="@dimen/sc_card_corner_radius_large" />
+ </shape>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_entity_top_large_bottom_small_background.xml b/PermissionController/res/drawable-v33/safety_entity_top_large_bottom_small_background.xml
new file mode 100644
index 000000000..2cbe94e8f
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_entity_top_large_bottom_small_background.xml
@@ -0,0 +1,41 @@
+<?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.
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+
+ <item>
+ <shape android:shape="rectangle">
+ <corners
+ android:bottomLeftRadius="@dimen/sc_card_corner_radius_xsmall"
+ android:bottomRightRadius="@dimen/sc_card_corner_radius_xsmall"
+ android:topLeftRadius="@dimen/sc_card_corner_radius_large"
+ android:topRightRadius="@dimen/sc_card_corner_radius_large" />
+ <solid android:color="?attr/colorSurface" />
+ </shape>
+ </item>
+
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <corners
+ android:bottomLeftRadius="@dimen/sc_card_corner_radius_xsmall"
+ android:bottomRightRadius="@dimen/sc_card_corner_radius_xsmall"
+ android:topLeftRadius="@dimen/sc_card_corner_radius_large"
+ android:topRightRadius="@dimen/sc_card_corner_radius_large" />
+ <solid android:color="#FFFF" />
+ </shape>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_entity_top_small_bottom_flat_background.xml b/PermissionController/res/drawable-v33/safety_entity_top_small_bottom_flat_background.xml
new file mode 100644
index 000000000..eced55ee8
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_entity_top_small_bottom_flat_background.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="?attr/colorSurface" />
+ <corners
+ android:topLeftRadius="@dimen/sc_card_corner_radius_xsmall"
+ android:topRightRadius="@dimen/sc_card_corner_radius_xsmall" />
+ </shape>
+ </item>
+
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <solid android:color="#FFFF" />
+ <corners
+ android:topLeftRadius="@dimen/sc_card_corner_radius_xsmall"
+ android:topRightRadius="@dimen/sc_card_corner_radius_xsmall" />
+ </shape>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_entity_top_small_bottom_large_background.xml b/PermissionController/res/drawable-v33/safety_entity_top_small_bottom_large_background.xml
new file mode 100644
index 000000000..5e26cd41a
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_entity_top_small_bottom_large_background.xml
@@ -0,0 +1,41 @@
+<?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.
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+
+ <item>
+ <shape android:shape="rectangle">
+ <corners
+ android:bottomLeftRadius="@dimen/sc_card_corner_radius_large"
+ android:bottomRightRadius="@dimen/sc_card_corner_radius_large"
+ android:topLeftRadius="@dimen/sc_card_corner_radius_xsmall"
+ android:topRightRadius="@dimen/sc_card_corner_radius_xsmall" />
+ <solid android:color="?attr/colorSurface" />
+ </shape>
+ </item>
+
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <corners
+ android:bottomLeftRadius="@dimen/sc_card_corner_radius_large"
+ android:bottomRightRadius="@dimen/sc_card_corner_radius_large"
+ android:topLeftRadius="@dimen/sc_card_corner_radius_xsmall"
+ android:topRightRadius="@dimen/sc_card_corner_radius_xsmall" />
+ <solid android:color="#FFFF" />
+ </shape>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_entity_top_small_bottom_small_background.xml b/PermissionController/res/drawable-v33/safety_entity_top_small_bottom_small_background.xml
new file mode 100644
index 000000000..6c8df5022
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_entity_top_small_bottom_small_background.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.
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="?attr/colorSurface" />
+ <corners android:radius="@dimen/sc_card_corner_radius_xsmall" />
+ </shape>
+ </item>
+
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <solid android:color="#FFFF" />
+ <corners android:radius="@dimen/sc_card_corner_radius_xsmall" />
+ </shape>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_entry_icon_action_background.xml b/PermissionController/res/drawable-v33/safety_entry_icon_action_background.xml
new file mode 100644
index 000000000..dc6a3fa28
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_entry_icon_action_background.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.
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <solid android:color="@android:color/white" />
+ <corners android:radius="?android:attr/buttonCornerRadius" />
+ </shape>
+ </item>
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="@android:color/transparent" />
+ </shape>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_group_entry_background.xml b/PermissionController/res/drawable-v33/safety_group_entry_background.xml
new file mode 100644
index 000000000..66d98fe64
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_group_entry_background.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.
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <solid android:color="#FFFF" />
+ </shape>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_status_info.xml b/PermissionController/res/drawable-v33/safety_status_info.xml
new file mode 100644
index 000000000..e52ed3d60
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_status_info.xml
@@ -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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:viewportWidth="224"
+ android:viewportHeight="224"
+ android:width="56dp"
+ android:height="56dp">
+ <path
+ android:pathData="M0 112C0 50.1441 50.1441 0 112 0C173.856 0 224 50.1441 224 112C224 173.856 173.856 224 112 224C50.1441 224 0 173.856 0 112Z"
+ android:fillColor="?attr/colorScStatusBackgroundInfo" />
+ <path
+ android:pathData="M112 42L56 62.5333V105.467C56 123.2 61.6 139.067 71.8666 154C82.1333 168.933 96.1333 178.267 112 182C127.867 178.267 141.867 168.933 152.133 154C162.4 139.067 168 123.2 168 105.467V63.4667L112 42Z"
+ android:fillColor="?attr/colorScStatusInfo" />
+ <path
+ android:pathData="M104.532 135.256L80.2656 110.056L89.599 100.722L104.532 114.722L134.399 85.7891L143.732 95.1224L104.532 135.256Z"
+ android:fillColor="?attr/colorScShieldAccent"/>
+
+</vector>
diff --git a/PermissionController/res/drawable-v33/safety_status_info_to_info_anim.xml b/PermissionController/res/drawable-v33/safety_status_info_to_info_anim.xml
new file mode 100644
index 000000000..31b5982ba
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_status_info_to_info_anim.xml
@@ -0,0 +1,173 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_3_G">
+ <path android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_2_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_1_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusInfo" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 42 C112,42 56,62.53 56,62.53 C56,62.53 56,105.47 56,105.47 C56,123.2 61.6,139.07 71.87,154 C82.13,168.93 96.13,178.27 112,182 C127.87,178.27 141.87,168.93 152.13,154 C162.4,139.07 168,123.2 168,105.47 C168,105.47 168,63.47 168,63.47 C168,63.47 112,42 112,42c "/>
+ </group>
+ <group android:name="_R_G_L_0_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="?attr/colorScShieldAccent"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "/>
+ <path android:name="_R_G_L_0_G_D_1_P_0" android:fillColor="?attr/colorScShieldAccent"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "/>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_3_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="783"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_status_recommend_to_info_anim.xml b/PermissionController/res/drawable-v33/safety_status_recommend_to_info_anim.xml
new file mode 100644
index 000000000..6e63c5097
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_status_recommend_to_info_anim.xml
@@ -0,0 +1,698 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_5_G">
+ <path android:name="_R_G_L_5_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundRecommend"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_4_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_4_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_3_G" android:translateX="112.5" android:translateY="112"
+ android:scaleX="4" android:scaleY="4">
+ <path android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusRecommend" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M-14 -12.37 C-14,-12.37 0,-17.5 0,-17.5 C0,-17.5 14,-12.37 14,-12.37 C14,-12.37 14,-1.63 14,-1.63 C14,2.8 12.6,6.77 10.03,10.5 C7.47,14.23 3.97,16.57 0,17.5 C-3.97,16.57 -7.47,14.23 -10.03,10.5 C-12.6,6.77 -14,2.8 -14,-1.63 C-14,-1.63 -14,-12.37 -14,-12.37c "/>
+ </group>
+ <group android:name="_R_G_L_2_G_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="0">
+ <group android:name="_R_G_L_2_G" android:translateX="-112"
+ android:translateY="-112" android:pivotX="112" android:pivotY="112"
+ android:rotation="-49.449" android:scaleX="0.25" android:scaleY="0.25">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="0"
+ android:fillType="nonZero"
+ android:pathData=" M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 105.33,115.27 105.33,115.27 C105.33,115.27 114.67,124.6 114.67,124.6 C114.67,124.6 104.53,135.26 104.53,135.26c "/>
+ <path android:name="_R_G_L_2_G_D_1_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="0"
+ android:fillType="nonZero"
+ android:pathData=" M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 105.33,115.27 105.33,115.27 C105.33,115.27 114.67,124.6 114.67,124.6 C114.67,124.6 104.53,135.26 104.53,135.26c "/>
+ </group>
+ </group>
+ <group android:name="_R_G_L_1_G_N_2_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="4">
+ <group android:name="_R_G_L_1_G_N_2_T_1" android:translateX="-0.001"
+ android:translateY="-3.999" android:scaleX="0.25" android:scaleY="0.25"
+ android:rotation="0">
+ <group android:name="_R_G_L_1_G_N_2_T_0" android:translateX="-111.997"
+ android:translateY="-96.002">
+ <group android:name="_R_G_L_1_G_T_1" android:translateX="112"
+ android:translateY="112" android:scaleX="1" android:scaleY="1">
+ <group android:name="_R_G_L_1_G" android:translateX="-112"
+ android:translateY="-112">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 142.67 C117.15,142.67 121.33,138.49 121.33,133.33 C121.33,128.18 117.15,124 112,124 C106.84,124 102.66,128.18 102.66,133.33 C102.66,138.49 106.84,142.67 112,142.67c "/>
+ </group>
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="_R_G_L_0_G_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="4">
+ <group android:name="_R_G_L_0_G_T_1" android:translateX="-0.001"
+ android:translateY="-3.999" android:scaleX="0.25" android:scaleY="0.25"
+ android:rotation="0">
+ <group android:name="_R_G_L_0_G" android:translateX="-111.997"
+ android:translateY="-96.002">
+ <group android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:translateX="111.997" android:translateY="96.002"
+ android:pivotX="0.055" android:pivotY="-18.901"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M9.33 -18.67 C9.33,-18.67 -9.33,-18.67 -9.33,-18.67 C-9.33,-18.67 -9.33,18.67 -9.33,18.67 C-9.33,18.67 9.33,18.67 9.33,18.67 C9.33,18.67 9.33,-18.67 9.33,-18.67c "/>
+ </group>
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_5_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_4_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillColor" android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="?attr/colorScStatusRecommend"
+ android:valueTo="?attr/colorScStatusRecommend"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillColor" android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="?attr/colorScStatusRecommend"
+ android:valueTo="?attr/colorScStatusInfo"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillColor" android:duration="450"
+ android:startOffset="317"
+ android:valueFrom="?attr/colorScStatusInfo"
+ android:valueTo="?attr/colorScStatusInfo"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="283"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="17"
+ android:startOffset="283" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="300"
+ android:startOffset="0"
+ android:valueFrom="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 105.33,115.27 105.33,115.27 C105.33,115.27 114.67,124.6 114.67,124.6 C114.67,124.6 104.53,135.26 104.53,135.26c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 105.33,115.27 105.33,115.27 C105.33,115.27 114.67,124.6 114.67,124.6 C114.67,124.6 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="350"
+ android:startOffset="300"
+ android:valueFrom="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 105.33,115.27 105.33,115.27 C105.33,115.27 114.67,124.6 114.67,124.6 C114.67,124.6 104.53,135.26 104.53,135.26c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="283"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="17"
+ android:startOffset="283" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="300"
+ android:startOffset="0"
+ android:valueFrom="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 105.33,115.27 105.33,115.27 C105.33,115.27 114.67,124.6 114.67,124.6 C114.67,124.6 104.53,135.26 104.53,135.26c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 105.33,115.27 105.33,115.27 C105.33,115.27 114.67,124.6 114.67,124.6 C114.67,124.6 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="350"
+ android:startOffset="300"
+ android:valueFrom="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 105.33,115.27 105.33,115.27 C105.33,115.27 114.67,124.6 114.67,124.6 C114.67,124.6 104.53,135.26 104.53,135.26c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="rotation" android:duration="283"
+ android:startOffset="0" android:valueFrom="-49.449"
+ android:valueTo="-49.449" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="rotation" android:duration="350"
+ android:startOffset="283" android:valueFrom="-49.449"
+ android:valueTo="0" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="rotation" android:duration="133"
+ android:startOffset="633" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleY" android:duration="0"
+ android:startOffset="300" android:valueFrom="0" android:valueTo="4"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="283"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="17"
+ android:startOffset="283" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateXY" android:duration="167"
+ android:startOffset="0" android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 112,112C 112,108.25 112,93.25 112,89.5">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="133"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.801,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="133"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.801,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="117"
+ android:startOffset="133" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.801,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="117"
+ android:startOffset="133" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.801,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_2_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateXY" android:duration="283"
+ android:startOffset="0" android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M -0.001,-3.999C -0.36,-2.801 -1.798,1.9900000000000002 -2.157,3.188">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_2_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="rotation" android:duration="617"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="321"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_2_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="283"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="17"
+ android:startOffset="283" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="200"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="200"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="100"
+ android:startOffset="200" android:valueFrom="1"
+ android:valueTo="0.77338" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="100"
+ android:startOffset="200" android:valueFrom="1"
+ android:valueTo="0.9275700000000001" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateXY" android:duration="283"
+ android:startOffset="0" android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M -0.001,-3.999C -0.36,-2.801 -1.798,1.9900000000000002 -2.157,3.188">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="rotation" android:duration="617"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="321"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleY" android:duration="0"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="4"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleY" android:duration="0"
+ android:startOffset="317" android:valueFrom="4" android:valueTo="0"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="783"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_status_recommendation.xml b/PermissionController/res/drawable-v33/safety_status_recommendation.xml
new file mode 100644
index 000000000..69b3b8902
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_status_recommendation.xml
@@ -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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:viewportWidth="224"
+ android:viewportHeight="224"
+ android:width="56dp"
+ android:height="56dp">
+ <path
+ android:pathData="M0 112C0 50.1441 50.1441 0 112 0C173.856 0 224 50.1441 224 112C224 173.856 173.856 224 112 224C50.1441 224 0 173.856 0 112Z"
+ android:fillColor="?attr/colorScStatusBackgroundRecommend" />
+ <path
+ android:pathData="M112 42L56 62.5333V105.467C56 123.2 61.6 139.067 71.8666 154C82.1333 168.933 96.1333 178.267 112 182C127.867 178.267 141.867 168.933 152.133 154C162.4 139.067 168 123.2 168 105.467V63.4667L112 42Z"
+ android:fillColor="?attr/colorScStatusRecommend" />
+ <path
+ android:pathData="M121.331 77.3359H102.664V114.669H121.331V77.3359Z"
+ android:fillColor="?attr/colorScShieldAccent"/>
+ <path
+ android:pathData="M111.997 142.667C117.152 142.667 121.331 138.488 121.331 133.333C121.331 128.179 117.152 124 111.997 124C106.843 124 102.664 128.179 102.664 133.333C102.664 138.488 106.843 142.667 111.997 142.667Z"
+ android:fillColor="?attr/colorScShieldAccent"/>
+</vector>
diff --git a/PermissionController/res/drawable-v33/safety_status_small_info_to_info_anim.xml b/PermissionController/res/drawable-v33/safety_status_small_info_to_info_anim.xml
new file mode 100644
index 000000000..8f8a0c564
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_status_small_info_to_info_anim.xml
@@ -0,0 +1,151 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="20dp"
+ android:width="20dp"
+ android:viewportHeight="20"
+ android:viewportWidth="20">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="2"
+ android:translateY="2"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScIconInfo"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C3.58,0 0,3.58 0,8 C0,12.42 3.58,16 8,16 C12.42,16 16,12.42 16,8 C16,3.58 12.42,0 8,0c M6.41 12 C6.41,12 3.24,8.79 3.24,8.79 C3.24,8.79 4.35,7.69 4.35,7.69 C4.35,7.69 6.41,9.74 6.41,9.74 C6.41,9.74 11.65,4.5 11.65,4.5 C11.65,4.5 12.76,5.62 12.76,5.62 C12.76,5.62 6.41,12 6.41,12c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="2"
+ android:translateY="2"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="1"
+ android:scaleY="1">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScIconInfo"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C3.58,0 0,3.58 0,8 C0,12.42 3.58,16 8,16 C12.42,16 16,12.42 16,8 C16,3.58 12.42,0 8,0c M6.41 12 C6.41,12 3.24,8.79 3.24,8.79 C3.24,8.79 4.35,7.69 4.35,7.69 C4.35,7.69 6.41,9.74 6.41,9.74 C6.41,9.74 11.65,4.5 11.65,4.5 C11.65,4.5 12.76,5.62 12.76,5.62 C12.76,5.62 6.41,12 6.41,12c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="317"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_status_small_info_to_recommendation_anim.xml b/PermissionController/res/drawable-v33/safety_status_small_info_to_recommendation_anim.xml
new file mode 100644
index 000000000..37bd68c44
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_status_small_info_to_recommendation_anim.xml
@@ -0,0 +1,151 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="20dp"
+ android:width="20dp"
+ android:viewportHeight="20"
+ android:viewportWidth="20">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="2"
+ android:translateY="2"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScIconRecommend"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M7.2 8.75 C7.2,8.75 7.2,3.99 7.2,3.99 C7.2,3.99 8.8,3.99 8.8,3.99 C8.8,3.99 8.8,8.75 8.8,8.75 C8.8,8.75 7.2,8.75 7.2,8.75c M7.2 12 C7.2,12 7.2,10.4 7.2,10.4 C7.2,10.4 8.8,10.4 8.8,10.4 C8.8,10.4 8.8,12 8.8,12 C8.8,12 7.2,12 7.2,12c M8 0 C3.58,0 0,3.58 0,8 C0,12.42 3.58,16 8,16 C12.42,16 16,12.42 16,8 C16,3.58 12.42,0 8,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="2"
+ android:translateY="2"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="1"
+ android:scaleY="1">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScIconInfo"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C3.58,0 0,3.58 0,8 C0,12.42 3.58,16 8,16 C12.42,16 16,12.42 16,8 C16,3.58 12.42,0 8,0c M6.41 12 C6.41,12 3.24,8.79 3.24,8.79 C3.24,8.79 4.35,7.69 4.35,7.69 C4.35,7.69 6.41,9.74 6.41,9.74 C6.41,9.74 11.65,4.5 11.65,4.5 C11.65,4.5 12.76,5.62 12.76,5.62 C12.76,5.62 6.41,12 6.41,12c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="317"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_status_small_info_to_warn_anim.xml b/PermissionController/res/drawable-v33/safety_status_small_info_to_warn_anim.xml
new file mode 100644
index 000000000..fc374e370
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_status_small_info_to_warn_anim.xml
@@ -0,0 +1,151 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="20dp"
+ android:width="20dp"
+ android:viewportHeight="20"
+ android:viewportWidth="20">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="2"
+ android:translateY="2"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScIconWarn"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M7.2 8.75 C7.2,8.75 7.2,3.99 7.2,3.99 C7.2,3.99 8.8,3.99 8.8,3.99 C8.8,3.99 8.8,8.75 8.8,8.75 C8.8,8.75 7.2,8.75 7.2,8.75c M7.2 12 C7.2,12 7.2,10.4 7.2,10.4 C7.2,10.4 8.8,10.4 8.8,10.4 C8.8,10.4 8.8,12 8.8,12 C8.8,12 7.2,12 7.2,12c M8 0 C3.58,0 0,3.58 0,8 C0,12.42 3.58,16 8,16 C12.42,16 16,12.42 16,8 C16,3.58 12.42,0 8,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="2"
+ android:translateY="2"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="1"
+ android:scaleY="1">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScIconInfo"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C3.58,0 0,3.58 0,8 C0,12.42 3.58,16 8,16 C12.42,16 16,12.42 16,8 C16,3.58 12.42,0 8,0c M6.41 12 C6.41,12 3.24,8.79 3.24,8.79 C3.24,8.79 4.35,7.69 4.35,7.69 C4.35,7.69 6.41,9.74 6.41,9.74 C6.41,9.74 11.65,4.5 11.65,4.5 C11.65,4.5 12.76,5.62 12.76,5.62 C12.76,5.62 6.41,12 6.41,12c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="317"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_status_small_recommendation_to_info_anim.xml b/PermissionController/res/drawable-v33/safety_status_small_recommendation_to_info_anim.xml
new file mode 100644
index 000000000..881656e28
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_status_small_recommendation_to_info_anim.xml
@@ -0,0 +1,151 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="20dp"
+ android:width="20dp"
+ android:viewportHeight="20"
+ android:viewportWidth="20">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="2"
+ android:translateY="2"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScIconInfo"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C3.58,0 0,3.58 0,8 C0,12.42 3.58,16 8,16 C12.42,16 16,12.42 16,8 C16,3.58 12.42,0 8,0c M6.41 12 C6.41,12 3.24,8.79 3.24,8.79 C3.24,8.79 4.35,7.69 4.35,7.69 C4.35,7.69 6.41,9.74 6.41,9.74 C6.41,9.74 11.65,4.5 11.65,4.5 C11.65,4.5 12.76,5.62 12.76,5.62 C12.76,5.62 6.41,12 6.41,12c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="2"
+ android:translateY="2"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="1"
+ android:scaleY="1">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScIconRecommend"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M7.2 8.75 C7.2,8.75 7.2,3.99 7.2,3.99 C7.2,3.99 8.8,3.99 8.8,3.99 C8.8,3.99 8.8,8.75 8.8,8.75 C8.8,8.75 7.2,8.75 7.2,8.75c M7.2 12 C7.2,12 7.2,10.4 7.2,10.4 C7.2,10.4 8.8,10.4 8.8,10.4 C8.8,10.4 8.8,12 8.8,12 C8.8,12 7.2,12 7.2,12c M8 0 C3.58,0 0,3.58 0,8 C0,12.42 3.58,16 8,16 C12.42,16 16,12.42 16,8 C16,3.58 12.42,0 8,0c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="317"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_status_small_recommendation_to_recommendation_anim.xml b/PermissionController/res/drawable-v33/safety_status_small_recommendation_to_recommendation_anim.xml
new file mode 100644
index 000000000..e7eb77884
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_status_small_recommendation_to_recommendation_anim.xml
@@ -0,0 +1,151 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="20dp"
+ android:width="20dp"
+ android:viewportHeight="20"
+ android:viewportWidth="20">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="2"
+ android:translateY="2"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScIconRecommend"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M7.2 8.75 C7.2,8.75 7.2,3.99 7.2,3.99 C7.2,3.99 8.8,3.99 8.8,3.99 C8.8,3.99 8.8,8.75 8.8,8.75 C8.8,8.75 7.2,8.75 7.2,8.75c M7.2 12 C7.2,12 7.2,10.4 7.2,10.4 C7.2,10.4 8.8,10.4 8.8,10.4 C8.8,10.4 8.8,12 8.8,12 C8.8,12 7.2,12 7.2,12c M8 0 C3.58,0 0,3.58 0,8 C0,12.42 3.58,16 8,16 C12.42,16 16,12.42 16,8 C16,3.58 12.42,0 8,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="2"
+ android:translateY="2"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="1"
+ android:scaleY="1">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScIconRecommend"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M7.2 8.75 C7.2,8.75 7.2,3.99 7.2,3.99 C7.2,3.99 8.8,3.99 8.8,3.99 C8.8,3.99 8.8,8.75 8.8,8.75 C8.8,8.75 7.2,8.75 7.2,8.75c M7.2 12 C7.2,12 7.2,10.4 7.2,10.4 C7.2,10.4 8.8,10.4 8.8,10.4 C8.8,10.4 8.8,12 8.8,12 C8.8,12 7.2,12 7.2,12c M8 0 C3.58,0 0,3.58 0,8 C0,12.42 3.58,16 8,16 C12.42,16 16,12.42 16,8 C16,3.58 12.42,0 8,0c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="317"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_status_small_recommendation_to_warn_anim.xml b/PermissionController/res/drawable-v33/safety_status_small_recommendation_to_warn_anim.xml
new file mode 100644
index 000000000..3016c4b82
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_status_small_recommendation_to_warn_anim.xml
@@ -0,0 +1,151 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="20dp"
+ android:width="20dp"
+ android:viewportHeight="20"
+ android:viewportWidth="20">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="2"
+ android:translateY="2"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScIconWarn"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M7.2 8.75 C7.2,8.75 7.2,3.99 7.2,3.99 C7.2,3.99 8.8,3.99 8.8,3.99 C8.8,3.99 8.8,8.75 8.8,8.75 C8.8,8.75 7.2,8.75 7.2,8.75c M7.2 12 C7.2,12 7.2,10.4 7.2,10.4 C7.2,10.4 8.8,10.4 8.8,10.4 C8.8,10.4 8.8,12 8.8,12 C8.8,12 7.2,12 7.2,12c M8 0 C3.58,0 0,3.58 0,8 C0,12.42 3.58,16 8,16 C12.42,16 16,12.42 16,8 C16,3.58 12.42,0 8,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="2"
+ android:translateY="2"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="1"
+ android:scaleY="1">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScIconRecommend"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M7.2 8.75 C7.2,8.75 7.2,3.99 7.2,3.99 C7.2,3.99 8.8,3.99 8.8,3.99 C8.8,3.99 8.8,8.75 8.8,8.75 C8.8,8.75 7.2,8.75 7.2,8.75c M7.2 12 C7.2,12 7.2,10.4 7.2,10.4 C7.2,10.4 8.8,10.4 8.8,10.4 C8.8,10.4 8.8,12 8.8,12 C8.8,12 7.2,12 7.2,12c M8 0 C3.58,0 0,3.58 0,8 C0,12.42 3.58,16 8,16 C12.42,16 16,12.42 16,8 C16,3.58 12.42,0 8,0c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="317"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_status_small_warn_to_info_anim.xml b/PermissionController/res/drawable-v33/safety_status_small_warn_to_info_anim.xml
new file mode 100644
index 000000000..2921a281d
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_status_small_warn_to_info_anim.xml
@@ -0,0 +1,151 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="20dp"
+ android:width="20dp"
+ android:viewportHeight="20"
+ android:viewportWidth="20">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="2"
+ android:translateY="2"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScIconInfo"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C3.58,0 0,3.58 0,8 C0,12.42 3.58,16 8,16 C12.42,16 16,12.42 16,8 C16,3.58 12.42,0 8,0c M6.41 12 C6.41,12 3.24,8.79 3.24,8.79 C3.24,8.79 4.35,7.69 4.35,7.69 C4.35,7.69 6.41,9.74 6.41,9.74 C6.41,9.74 11.65,4.5 11.65,4.5 C11.65,4.5 12.76,5.62 12.76,5.62 C12.76,5.62 6.41,12 6.41,12c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="2"
+ android:translateY="2"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="1"
+ android:scaleY="1">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScIconWarn"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M7.2 8.75 C7.2,8.75 7.2,3.99 7.2,3.99 C7.2,3.99 8.8,3.99 8.8,3.99 C8.8,3.99 8.8,8.75 8.8,8.75 C8.8,8.75 7.2,8.75 7.2,8.75c M7.2 12 C7.2,12 7.2,10.4 7.2,10.4 C7.2,10.4 8.8,10.4 8.8,10.4 C8.8,10.4 8.8,12 8.8,12 C8.8,12 7.2,12 7.2,12c M8 0 C3.58,0 0,3.58 0,8 C0,12.42 3.58,16 8,16 C12.42,16 16,12.42 16,8 C16,3.58 12.42,0 8,0c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="317"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_status_small_warn_to_recommendation_anim.xml b/PermissionController/res/drawable-v33/safety_status_small_warn_to_recommendation_anim.xml
new file mode 100644
index 000000000..7efb6fc46
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_status_small_warn_to_recommendation_anim.xml
@@ -0,0 +1,151 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="20dp"
+ android:width="20dp"
+ android:viewportHeight="20"
+ android:viewportWidth="20">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="2"
+ android:translateY="2"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScIconRecommend"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M7.2 8.75 C7.2,8.75 7.2,3.99 7.2,3.99 C7.2,3.99 8.8,3.99 8.8,3.99 C8.8,3.99 8.8,8.75 8.8,8.75 C8.8,8.75 7.2,8.75 7.2,8.75c M7.2 12 C7.2,12 7.2,10.4 7.2,10.4 C7.2,10.4 8.8,10.4 8.8,10.4 C8.8,10.4 8.8,12 8.8,12 C8.8,12 7.2,12 7.2,12c M8 0 C3.58,0 0,3.58 0,8 C0,12.42 3.58,16 8,16 C12.42,16 16,12.42 16,8 C16,3.58 12.42,0 8,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="2"
+ android:translateY="2"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="1"
+ android:scaleY="1">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScIconWarn"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M7.2 8.75 C7.2,8.75 7.2,3.99 7.2,3.99 C7.2,3.99 8.8,3.99 8.8,3.99 C8.8,3.99 8.8,8.75 8.8,8.75 C8.8,8.75 7.2,8.75 7.2,8.75c M7.2 12 C7.2,12 7.2,10.4 7.2,10.4 C7.2,10.4 8.8,10.4 8.8,10.4 C8.8,10.4 8.8,12 8.8,12 C8.8,12 7.2,12 7.2,12c M8 0 C3.58,0 0,3.58 0,8 C0,12.42 3.58,16 8,16 C12.42,16 16,12.42 16,8 C16,3.58 12.42,0 8,0c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="317"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_status_small_warn_to_warn_anim.xml b/PermissionController/res/drawable-v33/safety_status_small_warn_to_warn_anim.xml
new file mode 100644
index 000000000..ce98c4af7
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_status_small_warn_to_warn_anim.xml
@@ -0,0 +1,151 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="20dp"
+ android:width="20dp"
+ android:viewportHeight="20"
+ android:viewportWidth="20">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="2"
+ android:translateY="2"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScIconWarn"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M7.2 8.75 C7.2,8.75 7.2,3.99 7.2,3.99 C7.2,3.99 8.8,3.99 8.8,3.99 C8.8,3.99 8.8,8.75 8.8,8.75 C8.8,8.75 7.2,8.75 7.2,8.75c M7.2 12 C7.2,12 7.2,10.4 7.2,10.4 C7.2,10.4 8.8,10.4 8.8,10.4 C8.8,10.4 8.8,12 8.8,12 C8.8,12 7.2,12 7.2,12c M8 0 C3.58,0 0,3.58 0,8 C0,12.42 3.58,16 8,16 C12.42,16 16,12.42 16,8 C16,3.58 12.42,0 8,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="2"
+ android:translateY="2"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="1"
+ android:scaleY="1">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScIconWarn"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M7.2 8.75 C7.2,8.75 7.2,3.99 7.2,3.99 C7.2,3.99 8.8,3.99 8.8,3.99 C8.8,3.99 8.8,8.75 8.8,8.75 C8.8,8.75 7.2,8.75 7.2,8.75c M7.2 12 C7.2,12 7.2,10.4 7.2,10.4 C7.2,10.4 8.8,10.4 8.8,10.4 C8.8,10.4 8.8,12 8.8,12 C8.8,12 7.2,12 7.2,12c M8 0 C3.58,0 0,3.58 0,8 C0,12.42 3.58,16 8,16 C12.42,16 16,12.42 16,8 C16,3.58 12.42,0 8,0c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="317"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_status_warn.xml b/PermissionController/res/drawable-v33/safety_status_warn.xml
new file mode 100644
index 000000000..3e50a7b18
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_status_warn.xml
@@ -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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:viewportWidth="224"
+ android:viewportHeight="224"
+ android:width="56dp"
+ android:height="56dp">
+ <path
+ android:pathData="M0 112C0 50.1441 50.1441 0 112 0C173.856 0 224 50.1441 224 112C224 173.856 173.856 224 112 224C50.1441 224 0 173.856 0 112Z"
+ android:fillColor="?attr/colorScStatusBackgroundWarn" />
+ <path
+ android:pathData="M112 42L56 62.5333V105.467C56 123.2 61.6 139.067 71.8666 154C82.1333 168.933 96.1333 178.267 112 182C127.867 178.267 141.867 168.933 152.133 154C162.4 139.067 168 123.2 168 105.467V63.4667L112 42Z"
+ android:fillColor="?attr/colorScStatusWarn" />
+ <path
+ android:pathData="M121.331 77.3359H102.664V114.669H121.331V77.3359Z"
+ android:fillColor="?attr/colorScShieldAccent"/>
+ <path
+ android:pathData="M111.997 142.667C117.152 142.667 121.331 138.488 121.331 133.333C121.331 128.179 117.152 124 111.997 124C106.843 124 102.664 128.179 102.664 133.333C102.664 138.488 106.843 142.667 111.997 142.667Z"
+ android:fillColor="?attr/colorScShieldAccent"/>
+</vector>
diff --git a/PermissionController/res/drawable-v33/safety_status_warn_to_info_anim.xml b/PermissionController/res/drawable-v33/safety_status_warn_to_info_anim.xml
new file mode 100644
index 000000000..36333360b
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_status_warn_to_info_anim.xml
@@ -0,0 +1,697 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_5_G">
+ <path android:name="_R_G_L_5_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundWarn"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_4_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_4_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_3_G" android:translateX="112.5" android:translateY="112"
+ android:scaleX="4" android:scaleY="4">
+ <path android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusWarn" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M-14 -12.37 C-14,-12.37 0,-17.5 0,-17.5 C0,-17.5 14,-12.37 14,-12.37 C14,-12.37 14,-1.63 14,-1.63 C14,2.8 12.6,6.77 10.03,10.5 C7.47,14.23 3.97,16.57 0,17.5 C-3.97,16.57 -7.47,14.23 -10.03,10.5 C-12.6,6.77 -14,2.8 -14,-1.63 C-14,-1.63 -14,-12.37 -14,-12.37c "/>
+ </group>
+ <group android:name="_R_G_L_2_G_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="0">
+ <group android:name="_R_G_L_2_G" android:translateX="-112"
+ android:translateY="-112" android:pivotX="112" android:pivotY="112"
+ android:rotation="-49.449" android:scaleX="0.25" android:scaleY="0.25">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="0"
+ android:fillType="nonZero"
+ android:pathData=" M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 105.33,115.27 105.33,115.27 C105.33,115.27 114.67,124.6 114.67,124.6 C114.67,124.6 104.53,135.26 104.53,135.26c "/>
+ <path android:name="_R_G_L_2_G_D_1_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="0"
+ android:fillType="nonZero"
+ android:pathData=" M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 105.33,115.27 105.33,115.27 C105.33,115.27 114.67,124.6 114.67,124.6 C114.67,124.6 104.53,135.26 104.53,135.26c "/>
+ </group>
+ </group>
+ <group android:name="_R_G_L_1_G_N_2_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="4">
+ <group android:name="_R_G_L_1_G_N_2_T_1" android:translateX="-0.001"
+ android:translateY="-3.999" android:scaleX="0.25" android:scaleY="0.25"
+ android:rotation="0">
+ <group android:name="_R_G_L_1_G_N_2_T_0" android:translateX="-111.997"
+ android:translateY="-96.002">
+ <group android:name="_R_G_L_1_G_T_1" android:translateX="112"
+ android:translateY="112" android:scaleX="1" android:scaleY="1">
+ <group android:name="_R_G_L_1_G" android:translateX="-112"
+ android:translateY="-112">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 142.67 C117.15,142.67 121.33,138.49 121.33,133.33 C121.33,128.18 117.15,124 112,124 C106.84,124 102.66,128.18 102.66,133.33 C102.66,138.49 106.84,142.67 112,142.67c "/>
+ </group>
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="_R_G_L_0_G_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="4">
+ <group android:name="_R_G_L_0_G_T_1" android:translateX="-0.001"
+ android:translateY="-3.999" android:scaleX="0.25" android:scaleY="0.25"
+ android:rotation="0">
+ <group android:name="_R_G_L_0_G" android:translateX="-111.997"
+ android:translateY="-96.002">
+ <group android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:translateX="111.997" android:translateY="96.002"
+ android:pivotX="0.055" android:pivotY="-18.901"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M9.33 -18.67 C9.33,-18.67 -9.33,-18.67 -9.33,-18.67 C-9.33,-18.67 -9.33,18.67 -9.33,18.67 C-9.33,18.67 9.33,18.67 9.33,18.67 C9.33,18.67 9.33,-18.67 9.33,-18.67c "/>
+ </group>
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_5_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_4_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillColor" android:duration="150"
+ android:startOffset="0" android:valueFrom="?attr/colorScStatusWarn"
+ android:valueTo="?attr/colorScStatusWarn"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillColor" android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="?attr/colorScStatusWarn"
+ android:valueTo="?attr/colorScStatusInfo"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillColor" android:duration="450"
+ android:startOffset="317"
+ android:valueFrom="?attr/colorScStatusInfo"
+ android:valueTo="?attr/colorScStatusInfo"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="283"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="17"
+ android:startOffset="283" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="300"
+ android:startOffset="0"
+ android:valueFrom="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 105.33,115.27 105.33,115.27 C105.33,115.27 114.67,124.6 114.67,124.6 C114.67,124.6 104.53,135.26 104.53,135.26c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 105.33,115.27 105.33,115.27 C105.33,115.27 114.67,124.6 114.67,124.6 C114.67,124.6 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="350"
+ android:startOffset="300"
+ android:valueFrom="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 105.33,115.27 105.33,115.27 C105.33,115.27 114.67,124.6 114.67,124.6 C114.67,124.6 104.53,135.26 104.53,135.26c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="283"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="17"
+ android:startOffset="283" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="300"
+ android:startOffset="0"
+ android:valueFrom="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 105.33,115.27 105.33,115.27 C105.33,115.27 114.67,124.6 114.67,124.6 C114.67,124.6 104.53,135.26 104.53,135.26c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 105.33,115.27 105.33,115.27 C105.33,115.27 114.67,124.6 114.67,124.6 C114.67,124.6 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="350"
+ android:startOffset="300"
+ android:valueFrom="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 105.33,115.27 105.33,115.27 C105.33,115.27 114.67,124.6 114.67,124.6 C114.67,124.6 104.53,135.26 104.53,135.26c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="rotation" android:duration="283"
+ android:startOffset="0" android:valueFrom="-49.449"
+ android:valueTo="-49.449" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="rotation" android:duration="350"
+ android:startOffset="283" android:valueFrom="-49.449"
+ android:valueTo="0" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="rotation" android:duration="133"
+ android:startOffset="633" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleY" android:duration="0"
+ android:startOffset="300" android:valueFrom="0" android:valueTo="4"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="283"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="17"
+ android:startOffset="283" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateXY" android:duration="167"
+ android:startOffset="0" android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 112,112C 112,108.25 112,93.25 112,89.5">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="133"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.801,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="133"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.801,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="117"
+ android:startOffset="133" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.801,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="117"
+ android:startOffset="133" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.801,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_2_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateXY" android:duration="283"
+ android:startOffset="0" android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M -0.001,-3.999C -0.36,-2.801 -1.798,1.9900000000000002 -2.157,3.188">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_2_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="rotation" android:duration="617"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="321"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_2_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="283"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="17"
+ android:startOffset="283" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="200"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="200"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="100"
+ android:startOffset="200" android:valueFrom="1"
+ android:valueTo="0.77338" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="100"
+ android:startOffset="200" android:valueFrom="1"
+ android:valueTo="0.9275700000000001" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateXY" android:duration="283"
+ android:startOffset="0" android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M -0.001,-3.999C -0.36,-2.801 -1.798,1.9900000000000002 -2.157,3.188">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="rotation" android:duration="617"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="321"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleY" android:duration="0"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="4"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleY" android:duration="0"
+ android:startOffset="317" android:valueFrom="4" android:valueTo="0"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="783"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/safety_status_warn_to_recommend_anim.xml b/PermissionController/res/drawable-v33/safety_status_warn_to_recommend_anim.xml
new file mode 100644
index 000000000..f67521552
--- /dev/null
+++ b/PermissionController/res/drawable-v33/safety_status_warn_to_recommend_anim.xml
@@ -0,0 +1,255 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_4_G">
+ <path android:name="_R_G_L_4_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundWarn"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_3_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundRecommend"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_2_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusWarn" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 42 C112,42 56,62.53 56,62.53 C56,62.53 56,105.47 56,105.47 C56,123.2 61.6,139.07 71.87,154 C82.13,168.93 96.13,178.27 112,182 C127.87,178.27 141.87,168.93 152.13,154 C162.4,139.07 168,123.2 168,105.47 C168,105.47 168,63.47 168,63.47 C168,63.47 112,42 112,42c "/>
+ </group>
+ <group android:name="_R_G_L_1_G_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="4">
+ <group android:name="_R_G_L_1_G" android:translateX="-112"
+ android:translateY="-112" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0.25" android:scaleY="0.25">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 142.67 C117.15,142.67 121.33,138.49 121.33,133.33 C121.33,128.18 117.15,124 112,124 C106.84,124 102.66,128.18 102.66,133.33 C102.66,138.49 106.84,142.67 112,142.67c "/>
+ </group>
+ </group>
+ <group android:name="_R_G_L_0_G_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="4">
+ <group android:name="_R_G_L_0_G" android:translateX="-111.999"
+ android:translateY="-86.34700000000001" android:pivotX="111.999"
+ android:pivotY="77.796" android:scaleX="0.25" android:scaleY="0.25">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M121.33 77.33 C121.33,77.33 102.66,77.33 102.66,77.33 C102.66,77.33 102.66,114.67 102.66,114.67 C102.66,114.67 121.33,114.67 121.33,114.67 C121.33,114.67 121.33,77.33 121.33,77.33c "/>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_3_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillColor" android:duration="183"
+ android:startOffset="0" android:valueFrom="?attr/colorScStatusWarn"
+ android:valueTo="?attr/colorScStatusWarn"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillColor" android:duration="333"
+ android:startOffset="183"
+ android:valueFrom="?attr/colorScStatusWarn"
+ android:valueTo="?attr/colorScStatusRecommend"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="783"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/status_info_to_scanning_anim.xml b/PermissionController/res/drawable-v33/status_info_to_scanning_anim.xml
new file mode 100644
index 000000000..2c22f6ae9
--- /dev/null
+++ b/PermissionController/res/drawable-v33/status_info_to_scanning_anim.xml
@@ -0,0 +1,192 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_2_G">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_1_G">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusInfo" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 42 C112,42 56,62.53 56,62.53 C56,62.53 56,105.47 56,105.47 C56,123.2 61.6,139.07 71.87,154 C82.13,168.93 96.13,178.27 112,182 C127.87,178.27 141.87,168.93 152.13,154 C162.4,139.07 168,123.2 168,105.47 C168,105.47 168,63.47 168,63.47 C168,63.47 112,42 112,42c "/>
+ </group>
+ <group android:name="_R_G_L_0_G">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "/>
+ <path android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "/>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="333"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="17"
+ android:startOffset="333" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="250"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="83"
+ android:startOffset="250" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="17"
+ android:startOffset="333" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="83"
+ android:startOffset="0"
+ android:valueFrom="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 94.77,124.55 94.77,124.55 C94.77,124.55 104.1,115.22 104.1,115.22 C104.1,115.22 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="250"
+ android:startOffset="83"
+ android:valueFrom="M104.53 135.26 C104.53,135.26 94.77,124.55 94.77,124.55 C94.77,124.55 104.1,115.22 104.1,115.22 C104.1,115.22 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "
+ android:valueTo="M143.78 95.07 C143.78,95.07 134.58,85.93 134.58,85.93 C134.58,85.93 134.54,85.72 134.54,85.72 C134.54,85.72 134.53,85.72 134.53,85.72 C134.53,85.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 143.78,95.07 143.78,95.07c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="17"
+ android:startOffset="333"
+ android:valueFrom="M143.78 95.07 C143.78,95.07 134.58,85.93 134.58,85.93 C134.58,85.93 134.54,85.72 134.54,85.72 C134.54,85.72 134.53,85.72 134.53,85.72 C134.53,85.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 143.78,95.07 143.78,95.07c "
+ android:valueTo="M143.78 95.07 C143.78,95.07 134.58,85.93 134.58,85.93 C134.58,85.93 134.54,85.72 134.54,85.72 C134.54,85.72 134.53,85.72 134.53,85.72 C134.53,85.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 143.78,95.07 143.78,95.07c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="250"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="83"
+ android:startOffset="250" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="17"
+ android:startOffset="333" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="83"
+ android:startOffset="0"
+ android:valueFrom="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 94.77,124.55 94.77,124.55 C94.77,124.55 104.1,115.22 104.1,115.22 C104.1,115.22 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="250"
+ android:startOffset="83"
+ android:valueFrom="M104.53 135.26 C104.53,135.26 94.77,124.55 94.77,124.55 C94.77,124.55 104.1,115.22 104.1,115.22 C104.1,115.22 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "
+ android:valueTo="M143.78 95.07 C143.78,95.07 134.58,85.93 134.58,85.93 C134.58,85.93 134.54,85.72 134.54,85.72 C134.54,85.72 134.53,85.72 134.53,85.72 C134.53,85.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 143.78,95.07 143.78,95.07c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="17"
+ android:startOffset="333"
+ android:valueFrom="M143.78 95.07 C143.78,95.07 134.58,85.93 134.58,85.93 C134.58,85.93 134.54,85.72 134.54,85.72 C134.54,85.72 134.53,85.72 134.53,85.72 C134.53,85.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 143.78,95.07 143.78,95.07c "
+ android:valueTo="M143.78 95.07 C143.78,95.07 134.58,85.93 134.58,85.93 C134.58,85.93 134.54,85.72 134.54,85.72 C134.54,85.72 134.53,85.72 134.53,85.72 C134.53,85.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 143.78,95.07 143.78,95.07c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="350"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/status_recommend_to_scanning_anim.xml b/PermissionController/res/drawable-v33/status_recommend_to_scanning_anim.xml
new file mode 100644
index 000000000..873fe92c0
--- /dev/null
+++ b/PermissionController/res/drawable-v33/status_recommend_to_scanning_anim.xml
@@ -0,0 +1,124 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_3_G">
+ <path android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundRecommend"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_2_G">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusRecommend" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 42 C112,42 56,62.53 56,62.53 C56,62.53 56,105.47 56,105.47 C56,123.2 61.6,139.07 71.87,154 C82.13,168.93 96.13,178.27 112,182 C127.87,178.27 141.87,168.93 152.13,154 C162.4,139.07 168,123.2 168,105.47 C168,105.47 168,62.53 168,62.53 C168,62.53 112,42 112,42c "/>
+ </group>
+ <group android:name="_R_G_L_1_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="?attr/colorScShieldAccent"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 142.67 C117.15,142.67 121.33,138.49 121.33,133.33 C121.33,128.18 117.15,124 112,124 C106.84,124 102.66,128.18 102.66,133.33 C102.66,138.49 106.84,142.67 112,142.67c "/>
+ </group>
+ <group android:name="_R_G_L_0_G">
+ <group android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0" android:translateX="111.997"
+ android:translateY="96.002" android:pivotX="0.055"
+ android:pivotY="-18.901" android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M9.33 -18.67 C9.33,-18.67 -9.33,-18.67 -9.33,-18.67 C-9.33,-18.67 -9.33,18.67 -9.33,18.67 C-9.33,18.67 9.33,18.67 9.33,18.67 C9.33,18.67 9.33,-18.67 9.33,-18.67c "/>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_3_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="333"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="17"
+ android:startOffset="333" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.801,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.801,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="100"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.8,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="100"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.8,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="233"
+ android:startOffset="100" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.8,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="233"
+ android:startOffset="100" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.8,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="350"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/status_scanning_anim_info.xml b/PermissionController/res/drawable-v33/status_scanning_anim_info.xml
new file mode 100644
index 000000000..84564ed77
--- /dev/null
+++ b/PermissionController/res/drawable-v33/status_scanning_anim_info.xml
@@ -0,0 +1,79 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_2_G" android:translateX="-168" android:translateY="-168"
+ android:pivotX="280" android:pivotY="280" android:scaleX="0.4"
+ android:scaleY="0.4">
+ <path android:name="_R_G_L_2_G_S" android:fillColor="@android:color/transparent"
+ android:pathData="M0,0 L560,0 L560,560 L0,560z"/>
+ </group>
+ <group android:name="_R_G_L_1_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0.1" android:scaleY="0.1">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_0_G">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusInfo" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 42 C112,42 56,62.53 56,62.53 C56,62.53 56,105.47 56,105.47 C56,123.2 61.6,139.07 71.87,154 C82.13,168.93 96.13,178.27 112,182 C127.87,178.27 141.87,168.93 152.13,154 C162.4,139.07 168,123.2 168,105.47 C168,105.47 168,63.47 168,63.47 C168,63.47 112,42 112,42c "/>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="583"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.667,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="417"
+ android:startOffset="583" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.667,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="1000"
+ android:startOffset="0" android:valueFrom="0.1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="1000"
+ android:startOffset="0" android:valueFrom="0.1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="1017"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/status_scanning_anim_recommend.xml b/PermissionController/res/drawable-v33/status_scanning_anim_recommend.xml
new file mode 100644
index 000000000..89fb3ca81
--- /dev/null
+++ b/PermissionController/res/drawable-v33/status_scanning_anim_recommend.xml
@@ -0,0 +1,79 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_2_G" android:translateX="-168" android:translateY="-168"
+ android:pivotX="280" android:pivotY="280" android:scaleX="0.4"
+ android:scaleY="0.4">
+ <path android:name="_R_G_L_2_G_S" android:fillColor="@android:color/transparent"
+ android:pathData="M0,0 L560,0 L560,560 L0,560z"/>
+ </group>
+ <group android:name="_R_G_L_1_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0.1" android:scaleY="0.1">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundRecommend"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_0_G">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusRecommend" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 42 C112,42 56,62.53 56,62.53 C56,62.53 56,105.47 56,105.47 C56,123.2 61.6,139.07 71.87,154 C82.13,168.93 96.13,178.27 112,182 C127.87,178.27 141.87,168.93 152.13,154 C162.4,139.07 168,123.2 168,105.47 C168,105.47 168,62.53 168,62.53 C168,62.53 112,42 112,42c "/>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="583"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.667,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="417"
+ android:startOffset="583" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.667,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="1000"
+ android:startOffset="0" android:valueFrom="0.1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="1000"
+ android:startOffset="0" android:valueFrom="0.1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="1017"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/status_scanning_anim_warn.xml b/PermissionController/res/drawable-v33/status_scanning_anim_warn.xml
new file mode 100644
index 000000000..48c8ea730
--- /dev/null
+++ b/PermissionController/res/drawable-v33/status_scanning_anim_warn.xml
@@ -0,0 +1,79 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_2_G" android:translateX="-168" android:translateY="-168"
+ android:pivotX="280" android:pivotY="280" android:scaleX="0.4"
+ android:scaleY="0.4">
+ <path android:name="_R_G_L_2_G_S" android:fillColor="@android:color/transparent"
+ android:pathData="M0,0 L560,0 L560,560 L0,560z"/>
+ </group>
+ <group android:name="_R_G_L_1_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0.1" android:scaleY="0.1">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundWarn"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_0_G">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusWarn" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 42 C112,42 56,62.53 56,62.53 C56,62.53 56,105.47 56,105.47 C56,123.2 61.6,139.07 71.87,154 C82.13,168.93 96.13,178.27 112,182 C127.87,178.27 141.87,168.93 152.13,154 C162.4,139.07 168,123.2 168,105.47 C168,105.47 168,62.53 168,62.53 C168,62.53 112,42 112,42c "/>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="583"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.667,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="417"
+ android:startOffset="583" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.667,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="1000"
+ android:startOffset="0" android:valueFrom="0.1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="1000"
+ android:startOffset="0" android:valueFrom="0.1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="1017"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/status_scanning_end_anim_info_to_info.xml b/PermissionController/res/drawable-v33/status_scanning_end_anim_info_to_info.xml
new file mode 100644
index 000000000..5032e7203
--- /dev/null
+++ b/PermissionController/res/drawable-v33/status_scanning_end_anim_info_to_info.xml
@@ -0,0 +1,205 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_2_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_1_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusInfo" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 42 C112,42 56,62.53 56,62.53 C56,62.53 56,105.47 56,105.47 C56,123.2 61.6,139.07 71.87,154 C82.13,168.93 96.13,178.27 112,182 C127.87,178.27 141.87,168.93 152.13,154 C162.4,139.07 168,123.2 168,105.47 C168,105.47 168,63.47 168,63.47 C168,63.47 112,42 112,42c "/>
+ </group>
+ <group android:name="_R_G_L_0_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="?attr/colorScShieldAccent"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M80.31 109.98 C80.31,109.98 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 89.5,100.63 89.5,100.63 C89.5,100.63 89.86,100.7 89.86,100.7 C89.86,100.7 89.58,100.52 89.58,100.52 C89.58,100.52 80.31,109.98 80.31,109.98c "/>
+ <path android:name="_R_G_L_0_G_D_1_P_0" android:fillColor="?attr/colorScShieldAccent"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M80.31 109.98 C80.31,109.98 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 89.5,100.63 89.5,100.63 C89.5,100.63 89.86,100.7 89.86,100.7 C89.86,100.7 89.58,100.52 89.58,100.52 C89.58,100.52 80.31,109.98 80.31,109.98c "/>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="50"
+ android:startOffset="0"
+ android:valueFrom="M80.31 109.98 C80.31,109.98 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 89.5,100.63 89.5,100.63 C89.5,100.63 89.86,100.7 89.86,100.7 C89.86,100.7 89.58,100.52 89.58,100.52 C89.58,100.52 80.31,109.98 80.31,109.98c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 104.73,114.96 104.73,114.96 C104.73,114.96 114.06,124.29 114.06,124.29 C114.06,124.29 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="167"
+ android:startOffset="50"
+ android:valueFrom="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 104.73,114.96 104.73,114.96 C104.73,114.96 114.06,124.29 114.06,124.29 C114.06,124.29 104.53,135.26 104.53,135.26c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="50"
+ android:startOffset="0"
+ android:valueFrom="M80.31 109.98 C80.31,109.98 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 89.5,100.63 89.5,100.63 C89.5,100.63 89.86,100.7 89.86,100.7 C89.86,100.7 89.58,100.52 89.58,100.52 C89.58,100.52 80.31,109.98 80.31,109.98c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 104.73,114.96 104.73,114.96 C104.73,114.96 114.06,124.29 114.06,124.29 C114.06,124.29 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="167"
+ android:startOffset="50"
+ android:valueFrom="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 104.73,114.96 104.73,114.96 C104.73,114.96 114.06,124.29 114.06,124.29 C114.06,124.29 104.53,135.26 104.53,135.26c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="783"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/status_scanning_end_anim_info_to_recommend.xml b/PermissionController/res/drawable-v33/status_scanning_end_anim_info_to_recommend.xml
new file mode 100644
index 000000000..6d60a7532
--- /dev/null
+++ b/PermissionController/res/drawable-v33/status_scanning_end_anim_info_to_recommend.xml
@@ -0,0 +1,308 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_3_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundRecommend"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_2_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusInfo" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 42 C112,42 56,62.53 56,62.53 C56,62.53 56,105.47 56,105.47 C56,123.2 61.6,139.07 71.87,154 C82.13,168.93 96.13,178.27 112,182 C127.87,178.27 141.87,168.93 152.13,154 C162.4,139.07 168,123.2 168,105.47 C168,105.47 168,63.47 168,63.47 C168,63.47 112,42 112,42c "/>
+ </group>
+ <group android:name="_R_G_L_1_G_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="4">
+ <group android:name="_R_G_L_1_G" android:translateX="-112"
+ android:translateY="-112" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 142.67 C117.15,142.67 121.33,138.49 121.33,133.33 C121.33,128.18 117.15,124 112,124 C106.84,124 102.66,128.18 102.66,133.33 C102.66,138.49 106.84,142.67 112,142.67c "/>
+ </group>
+ </group>
+ <group android:name="_R_G_L_0_G_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="4">
+ <group android:name="_R_G_L_0_G" android:translateX="-111.999"
+ android:translateY="-86.34700000000001" android:pivotX="111.999"
+ android:pivotY="77.796" android:scaleX="0.25" android:scaleY="0.25">
+ <group android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:translateX="111.997" android:translateY="96.002"
+ android:pivotX="0.055" android:pivotY="-18.901" android:scaleX="1"
+ android:scaleY="0">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M9.33 -18.67 C9.33,-18.67 -9.33,-18.67 -9.33,-18.67 C-9.33,-18.67 -9.33,18.67 -9.33,18.67 C-9.33,18.67 9.33,18.67 9.33,18.67 C9.33,18.67 9.33,-18.67 9.33,-18.67c "/>
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_3_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillColor" android:duration="150"
+ android:startOffset="0" android:valueFrom="?attr/colorScStatusInfo"
+ android:valueTo="?attr/colorScStatusInfo"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillColor" android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="?attr/colorScStatusInfo"
+ android:valueTo="?attr/colorScStatusRecommend"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="100"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="100"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="100" android:valueFrom="0"
+ android:valueTo="0.25" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="100" android:valueFrom="0"
+ android:valueTo="0.25" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="233"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="233"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="783"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/status_scanning_end_anim_info_to_warn.xml b/PermissionController/res/drawable-v33/status_scanning_end_anim_info_to_warn.xml
new file mode 100644
index 000000000..9ce7d18cc
--- /dev/null
+++ b/PermissionController/res/drawable-v33/status_scanning_end_anim_info_to_warn.xml
@@ -0,0 +1,308 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_3_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundWarn"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_2_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusInfo" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 42 C112,42 56,62.53 56,62.53 C56,62.53 56,105.47 56,105.47 C56,123.2 61.6,139.07 71.87,154 C82.13,168.93 96.13,178.27 112,182 C127.87,178.27 141.87,168.93 152.13,154 C162.4,139.07 168,123.2 168,105.47 C168,105.47 168,63.47 168,63.47 C168,63.47 112,42 112,42c "/>
+ </group>
+ <group android:name="_R_G_L_1_G_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="4">
+ <group android:name="_R_G_L_1_G" android:translateX="-112"
+ android:translateY="-112" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 142.67 C117.15,142.67 121.33,138.49 121.33,133.33 C121.33,128.18 117.15,124 112,124 C106.84,124 102.66,128.18 102.66,133.33 C102.66,138.49 106.84,142.67 112,142.67c "/>
+ </group>
+ </group>
+ <group android:name="_R_G_L_0_G_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="4">
+ <group android:name="_R_G_L_0_G" android:translateX="-111.999"
+ android:translateY="-86.34700000000001" android:pivotX="111.999"
+ android:pivotY="77.796" android:scaleX="0.25" android:scaleY="0.25">
+ <group android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:translateX="111.997" android:translateY="96.002"
+ android:pivotX="0.055" android:pivotY="-18.901" android:scaleX="1"
+ android:scaleY="0">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M9.33 -18.67 C9.33,-18.67 -9.33,-18.67 -9.33,-18.67 C-9.33,-18.67 -9.33,18.67 -9.33,18.67 C-9.33,18.67 9.33,18.67 9.33,18.67 C9.33,18.67 9.33,-18.67 9.33,-18.67c "/>
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_3_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillColor" android:duration="150"
+ android:startOffset="0" android:valueFrom="?attr/colorScStatusInfo"
+ android:valueTo="?attr/colorScStatusInfo"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillColor" android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="?attr/colorScStatusInfo"
+ android:valueTo="?attr/colorScStatusWarn"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="100"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="100"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="100" android:valueFrom="0"
+ android:valueTo="0.25" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="100" android:valueFrom="0"
+ android:valueTo="0.25" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="233"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="233"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="783"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/status_scanning_end_anim_recommend_to_info.xml b/PermissionController/res/drawable-v33/status_scanning_end_anim_recommend_to_info.xml
new file mode 100644
index 000000000..f69fb1680
--- /dev/null
+++ b/PermissionController/res/drawable-v33/status_scanning_end_anim_recommend_to_info.xml
@@ -0,0 +1,231 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_2_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_1_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusRecommend" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 42 C112,42 56,62.53 56,62.53 C56,62.53 56,105.47 56,105.47 C56,123.2 61.6,139.07 71.87,154 C82.13,168.93 96.13,178.27 112,182 C127.87,178.27 141.87,168.93 152.13,154 C162.4,139.07 168,123.2 168,105.47 C168,105.47 168,63.47 168,63.47 C168,63.47 112,42 112,42c "/>
+ </group>
+ <group android:name="_R_G_L_0_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="?attr/colorScShieldAccent"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M80.31 109.98 C80.31,109.98 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 89.5,100.63 89.5,100.63 C89.5,100.63 89.86,100.7 89.86,100.7 C89.86,100.7 89.58,100.52 89.58,100.52 C89.58,100.52 80.31,109.98 80.31,109.98c "/>
+ <path android:name="_R_G_L_0_G_D_1_P_0" android:fillColor="?attr/colorScShieldAccent"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M80.31 109.98 C80.31,109.98 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 89.5,100.63 89.5,100.63 C89.5,100.63 89.86,100.7 89.86,100.7 C89.86,100.7 89.58,100.52 89.58,100.52 C89.58,100.52 80.31,109.98 80.31,109.98c "/>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillColor" android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="?attr/colorScStatusRecommend"
+ android:valueTo="?attr/colorScStatusRecommend"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillColor" android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="?attr/colorScStatusRecommend"
+ android:valueTo="?attr/colorScStatusInfo"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="50"
+ android:startOffset="0"
+ android:valueFrom="M80.31 109.98 C80.31,109.98 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 89.5,100.63 89.5,100.63 C89.5,100.63 89.86,100.7 89.86,100.7 C89.86,100.7 89.58,100.52 89.58,100.52 C89.58,100.52 80.31,109.98 80.31,109.98c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 104.73,114.96 104.73,114.96 C104.73,114.96 114.06,124.29 114.06,124.29 C114.06,124.29 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="167"
+ android:startOffset="50"
+ android:valueFrom="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 104.73,114.96 104.73,114.96 C104.73,114.96 114.06,124.29 114.06,124.29 C114.06,124.29 104.53,135.26 104.53,135.26c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="50"
+ android:startOffset="0"
+ android:valueFrom="M80.31 109.98 C80.31,109.98 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 89.5,100.63 89.5,100.63 C89.5,100.63 89.86,100.7 89.86,100.7 C89.86,100.7 89.58,100.52 89.58,100.52 C89.58,100.52 80.31,109.98 80.31,109.98c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 104.73,114.96 104.73,114.96 C104.73,114.96 114.06,124.29 114.06,124.29 C114.06,124.29 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="167"
+ android:startOffset="50"
+ android:valueFrom="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 104.73,114.96 104.73,114.96 C104.73,114.96 114.06,124.29 114.06,124.29 C114.06,124.29 104.53,135.26 104.53,135.26c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="783"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/status_scanning_end_anim_recommend_to_recommend.xml b/PermissionController/res/drawable-v33/status_scanning_end_anim_recommend_to_recommend.xml
new file mode 100644
index 000000000..8f8c9fb46
--- /dev/null
+++ b/PermissionController/res/drawable-v33/status_scanning_end_anim_recommend_to_recommend.xml
@@ -0,0 +1,283 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_3_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundRecommend"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_2_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusRecommend" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 42 C112,42 56,62.53 56,62.53 C56,62.53 56,105.47 56,105.47 C56,123.2 61.6,139.07 71.87,154 C82.13,168.93 96.13,178.27 112,182 C127.87,178.27 141.87,168.93 152.13,154 C162.4,139.07 168,123.2 168,105.47 C168,105.47 168,63.47 168,63.47 C168,63.47 112,42 112,42c "/>
+ </group>
+ <group android:name="_R_G_L_1_G_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="4">
+ <group android:name="_R_G_L_1_G" android:translateX="-112"
+ android:translateY="-112" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 142.67 C117.15,142.67 121.33,138.49 121.33,133.33 C121.33,128.18 117.15,124 112,124 C106.84,124 102.66,128.18 102.66,133.33 C102.66,138.49 106.84,142.67 112,142.67c "/>
+ </group>
+ </group>
+ <group android:name="_R_G_L_0_G_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="4">
+ <group android:name="_R_G_L_0_G" android:translateX="-111.999"
+ android:translateY="-86.34700000000001" android:pivotX="111.999"
+ android:pivotY="77.796" android:scaleX="0.25" android:scaleY="0.25">
+ <group android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:translateX="111.997" android:translateY="96.002"
+ android:pivotX="0.055" android:pivotY="-18.901" android:scaleX="1"
+ android:scaleY="0">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M9.33 -18.67 C9.33,-18.67 -9.33,-18.67 -9.33,-18.67 C-9.33,-18.67 -9.33,18.67 -9.33,18.67 C-9.33,18.67 9.33,18.67 9.33,18.67 C9.33,18.67 9.33,-18.67 9.33,-18.67c "/>
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_3_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="100"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="100"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="100" android:valueFrom="0"
+ android:valueTo="0.25" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="100" android:valueFrom="0"
+ android:valueTo="0.25" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="233"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="233"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="783"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/status_scanning_end_anim_recommend_to_warn.xml b/PermissionController/res/drawable-v33/status_scanning_end_anim_recommend_to_warn.xml
new file mode 100644
index 000000000..cbe900d10
--- /dev/null
+++ b/PermissionController/res/drawable-v33/status_scanning_end_anim_recommend_to_warn.xml
@@ -0,0 +1,309 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_3_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundWarn"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_2_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusRecommend" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 42 C112,42 56,62.53 56,62.53 C56,62.53 56,105.47 56,105.47 C56,123.2 61.6,139.07 71.87,154 C82.13,168.93 96.13,178.27 112,182 C127.87,178.27 141.87,168.93 152.13,154 C162.4,139.07 168,123.2 168,105.47 C168,105.47 168,63.47 168,63.47 C168,63.47 112,42 112,42c "/>
+ </group>
+ <group android:name="_R_G_L_1_G_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="4">
+ <group android:name="_R_G_L_1_G" android:translateX="-112"
+ android:translateY="-112" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 142.67 C117.15,142.67 121.33,138.49 121.33,133.33 C121.33,128.18 117.15,124 112,124 C106.84,124 102.66,128.18 102.66,133.33 C102.66,138.49 106.84,142.67 112,142.67c "/>
+ </group>
+ </group>
+ <group android:name="_R_G_L_0_G_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="4">
+ <group android:name="_R_G_L_0_G" android:translateX="-111.999"
+ android:translateY="-86.34700000000001" android:pivotX="111.999"
+ android:pivotY="77.796" android:scaleX="0.25" android:scaleY="0.25">
+ <group android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:translateX="111.997" android:translateY="96.002"
+ android:pivotX="0.055" android:pivotY="-18.901" android:scaleX="1"
+ android:scaleY="0">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M9.33 -18.67 C9.33,-18.67 -9.33,-18.67 -9.33,-18.67 C-9.33,-18.67 -9.33,18.67 -9.33,18.67 C-9.33,18.67 9.33,18.67 9.33,18.67 C9.33,18.67 9.33,-18.67 9.33,-18.67c "/>
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_3_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillColor" android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="?attr/colorScStatusRecommend"
+ android:valueTo="?attr/colorScStatusRecommend"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillColor" android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="?attr/colorScStatusRecommend"
+ android:valueTo="?attr/colorScStatusWarn"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="100"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="100"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="100" android:valueFrom="0"
+ android:valueTo="0.25" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="100" android:valueFrom="0"
+ android:valueTo="0.25" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="233"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="233"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="783"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/status_scanning_end_anim_warn_to_info.xml b/PermissionController/res/drawable-v33/status_scanning_end_anim_warn_to_info.xml
new file mode 100644
index 000000000..723675887
--- /dev/null
+++ b/PermissionController/res/drawable-v33/status_scanning_end_anim_warn_to_info.xml
@@ -0,0 +1,230 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_2_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_1_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusWarn" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 42 C112,42 56,62.53 56,62.53 C56,62.53 56,105.47 56,105.47 C56,123.2 61.6,139.07 71.87,154 C82.13,168.93 96.13,178.27 112,182 C127.87,178.27 141.87,168.93 152.13,154 C162.4,139.07 168,123.2 168,105.47 C168,105.47 168,63.47 168,63.47 C168,63.47 112,42 112,42c "/>
+ </group>
+ <group android:name="_R_G_L_0_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="?attr/colorScShieldAccent"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M80.31 109.98 C80.31,109.98 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 89.5,100.63 89.5,100.63 C89.5,100.63 89.86,100.7 89.86,100.7 C89.86,100.7 89.58,100.52 89.58,100.52 C89.58,100.52 80.31,109.98 80.31,109.98c "/>
+ <path android:name="_R_G_L_0_G_D_1_P_0" android:fillColor="?attr/colorScShieldAccent"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M80.31 109.98 C80.31,109.98 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 89.5,100.63 89.5,100.63 C89.5,100.63 89.86,100.7 89.86,100.7 C89.86,100.7 89.58,100.52 89.58,100.52 C89.58,100.52 80.31,109.98 80.31,109.98c "/>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillColor" android:duration="150"
+ android:startOffset="0" android:valueFrom="?attr/colorScStatusWarn"
+ android:valueTo="?attr/colorScStatusWarn"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillColor" android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="?attr/colorScStatusWarn"
+ android:valueTo="?attr/colorScStatusInfo"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="50"
+ android:startOffset="0"
+ android:valueFrom="M80.31 109.98 C80.31,109.98 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 89.5,100.63 89.5,100.63 C89.5,100.63 89.86,100.7 89.86,100.7 C89.86,100.7 89.58,100.52 89.58,100.52 C89.58,100.52 80.31,109.98 80.31,109.98c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 104.73,114.96 104.73,114.96 C104.73,114.96 114.06,124.29 114.06,124.29 C114.06,124.29 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="167"
+ android:startOffset="50"
+ android:valueFrom="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 104.73,114.96 104.73,114.96 C104.73,114.96 114.06,124.29 114.06,124.29 C114.06,124.29 104.53,135.26 104.53,135.26c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="50"
+ android:startOffset="0"
+ android:valueFrom="M80.31 109.98 C80.31,109.98 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 89.5,100.63 89.5,100.63 C89.5,100.63 89.86,100.7 89.86,100.7 C89.86,100.7 89.58,100.52 89.58,100.52 C89.58,100.52 80.31,109.98 80.31,109.98c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 104.73,114.96 104.73,114.96 C104.73,114.96 114.06,124.29 114.06,124.29 C114.06,124.29 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="167"
+ android:startOffset="50"
+ android:valueFrom="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 104.73,114.96 104.73,114.96 C104.73,114.96 114.06,124.29 114.06,124.29 C114.06,124.29 104.53,135.26 104.53,135.26c "
+ android:valueTo="M104.53 135.26 C104.53,135.26 80.27,110.06 80.27,110.06 C80.27,110.06 89.6,100.72 89.6,100.72 C89.6,100.72 104.53,114.72 104.53,114.72 C104.53,114.72 134.4,85.79 134.4,85.79 C134.4,85.79 143.73,95.12 143.73,95.12 C143.73,95.12 104.53,135.26 104.53,135.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="783"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/status_scanning_end_anim_warn_to_recommend.xml b/PermissionController/res/drawable-v33/status_scanning_end_anim_warn_to_recommend.xml
new file mode 100644
index 000000000..15300ce02
--- /dev/null
+++ b/PermissionController/res/drawable-v33/status_scanning_end_anim_warn_to_recommend.xml
@@ -0,0 +1,308 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_3_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundRecommend"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_2_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusWarn" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 42 C112,42 56,62.53 56,62.53 C56,62.53 56,105.47 56,105.47 C56,123.2 61.6,139.07 71.87,154 C82.13,168.93 96.13,178.27 112,182 C127.87,178.27 141.87,168.93 152.13,154 C162.4,139.07 168,123.2 168,105.47 C168,105.47 168,63.47 168,63.47 C168,63.47 112,42 112,42c "/>
+ </group>
+ <group android:name="_R_G_L_1_G_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="4">
+ <group android:name="_R_G_L_1_G" android:translateX="-112"
+ android:translateY="-112" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 142.67 C117.15,142.67 121.33,138.49 121.33,133.33 C121.33,128.18 117.15,124 112,124 C106.84,124 102.66,128.18 102.66,133.33 C102.66,138.49 106.84,142.67 112,142.67c "/>
+ </group>
+ </group>
+ <group android:name="_R_G_L_0_G_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="4">
+ <group android:name="_R_G_L_0_G" android:translateX="-111.999"
+ android:translateY="-86.34700000000001" android:pivotX="111.999"
+ android:pivotY="77.796" android:scaleX="0.25" android:scaleY="0.25">
+ <group android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:translateX="111.997" android:translateY="96.002"
+ android:pivotX="0.055" android:pivotY="-18.901" android:scaleX="1"
+ android:scaleY="0">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M9.33 -18.67 C9.33,-18.67 -9.33,-18.67 -9.33,-18.67 C-9.33,-18.67 -9.33,18.67 -9.33,18.67 C-9.33,18.67 9.33,18.67 9.33,18.67 C9.33,18.67 9.33,-18.67 9.33,-18.67c "/>
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_3_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillColor" android:duration="150"
+ android:startOffset="0" android:valueFrom="?attr/colorScStatusWarn"
+ android:valueTo="?attr/colorScStatusWarn"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillColor" android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="?attr/colorScStatusWarn"
+ android:valueTo="?attr/colorScStatusRecommend"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="100"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="100"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="100" android:valueFrom="0"
+ android:valueTo="0.25" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="100" android:valueFrom="0"
+ android:valueTo="0.25" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="233"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="233"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="783"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/status_scanning_end_anim_warn_to_warn.xml b/PermissionController/res/drawable-v33/status_scanning_end_anim_warn_to_warn.xml
new file mode 100644
index 000000000..86a053815
--- /dev/null
+++ b/PermissionController/res/drawable-v33/status_scanning_end_anim_warn_to_warn.xml
@@ -0,0 +1,283 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_3_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundWarn"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_2_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusWarn" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 42 C112,42 56,62.53 56,62.53 C56,62.53 56,105.47 56,105.47 C56,123.2 61.6,139.07 71.87,154 C82.13,168.93 96.13,178.27 112,182 C127.87,178.27 141.87,168.93 152.13,154 C162.4,139.07 168,123.2 168,105.47 C168,105.47 168,63.47 168,63.47 C168,63.47 112,42 112,42c "/>
+ </group>
+ <group android:name="_R_G_L_1_G_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="4">
+ <group android:name="_R_G_L_1_G" android:translateX="-112"
+ android:translateY="-112" android:pivotX="112" android:pivotY="112"
+ android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 142.67 C117.15,142.67 121.33,138.49 121.33,133.33 C121.33,128.18 117.15,124 112,124 C106.84,124 102.66,128.18 102.66,133.33 C102.66,138.49 106.84,142.67 112,142.67c "/>
+ </group>
+ </group>
+ <group android:name="_R_G_L_0_G_N_1_T_0" android:translateX="112"
+ android:translateY="112" android:scaleX="4" android:scaleY="4">
+ <group android:name="_R_G_L_0_G" android:translateX="-111.999"
+ android:translateY="-86.34700000000001" android:pivotX="111.999"
+ android:pivotY="77.796" android:scaleX="0.25" android:scaleY="0.25">
+ <group android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:translateX="111.997" android:translateY="96.002"
+ android:pivotX="0.055" android:pivotY="-18.901" android:scaleX="1"
+ android:scaleY="0">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M9.33 -18.67 C9.33,-18.67 -9.33,-18.67 -9.33,-18.67 C-9.33,-18.67 -9.33,18.67 -9.33,18.67 C-9.33,18.67 9.33,18.67 9.33,18.67 C9.33,18.67 9.33,-18.67 9.33,-18.67c "/>
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_3_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="517"
+ android:startOffset="250" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0.9"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.809,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="0.9"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.002,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="100"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="100"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="100" android:valueFrom="0"
+ android:valueTo="0.25" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="100" android:valueFrom="0"
+ android:valueTo="0.25" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.199,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="233"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="233"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_1_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="150"
+ android:startOffset="0" android:valueFrom="4" android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="450"
+ android:startOffset="150" android:valueFrom="3.6"
+ android:valueTo="4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="600" android:valueFrom="4" android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="783"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v33/status_warn_to_scanning_anim.xml b/PermissionController/res/drawable-v33/status_warn_to_scanning_anim.xml
new file mode 100644
index 000000000..c954c60c0
--- /dev/null
+++ b/PermissionController/res/drawable-v33/status_warn_to_scanning_anim.xml
@@ -0,0 +1,124 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="224dp" android:width="224dp" android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_3_G">
+ <path android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundWarn"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c "/>
+ </group>
+ <group android:name="_R_G_L_2_G">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusWarn" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 42 C112,42 56,62.53 56,62.53 C56,62.53 56,105.47 56,105.47 C56,123.2 61.6,139.07 71.87,154 C82.13,168.93 96.13,178.27 112,182 C127.87,178.27 141.87,168.93 152.13,154 C162.4,139.07 168,123.2 168,105.47 C168,105.47 168,62.53 168,62.53 C168,62.53 112,42 112,42c "/>
+ </group>
+ <group android:name="_R_G_L_1_G" android:pivotX="112" android:pivotY="112"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="?attr/colorScShieldAccent"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M112 142.67 C117.15,142.67 121.33,138.49 121.33,133.33 C121.33,128.18 117.15,124 112,124 C106.84,124 102.66,128.18 102.66,133.33 C102.66,138.49 106.84,142.67 112,142.67c "/>
+ </group>
+ <group android:name="_R_G_L_0_G">
+ <group android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0" android:translateX="111.997"
+ android:translateY="96.002" android:pivotX="0.055"
+ android:pivotY="-18.901" android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent" android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M9.33 -18.67 C9.33,-18.67 -9.33,-18.67 -9.33,-18.67 C-9.33,-18.67 -9.33,18.67 -9.33,18.67 C-9.33,18.67 9.33,18.67 9.33,18.67 C9.33,18.67 9.33,-18.67 9.33,-18.67c "/>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_3_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="333"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="17"
+ android:startOffset="333" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator
+ android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="250"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.801,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="250"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.801,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="100"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.8,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="100"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.8,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="233"
+ android:startOffset="100" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.8,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="233"
+ android:startOffset="100" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.8,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="350"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/ic_business.xml b/PermissionController/res/drawable-v34/ic_business.xml
new file mode 100644
index 000000000..23ee37d0e
--- /dev/null
+++ b/PermissionController/res/drawable-v34/ic_business.xml
@@ -0,0 +1,10 @@
+<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="M12,7L12,3L2,3v18h20L22,7L12,7zM6,19L4,19v-2h2v2zM6,15L4,15v-2h2v2zM6,11L4,11L4,9h2v2zM6,7L4,7L4,5h2v2zM10,19L8,19v-2h2v2zM10,15L8,15v-2h2v2zM10,11L8,11L8,9h2v2zM10,7L8,7L8,5h2v2zM20,19h-8v-2h2v-2h-2v-2h2v-2h-2L12,9h8v10zM18,11h-2v2h2v-2zM18,15h-2v2h2v-2z"/>
+</vector>
diff --git a/PermissionController/res/drawable-v34/ic_collections_bookmark.xml b/PermissionController/res/drawable-v34/ic_collections_bookmark.xml
new file mode 100644
index 000000000..29f9e569c
--- /dev/null
+++ b/PermissionController/res/drawable-v34/ic_collections_bookmark.xml
@@ -0,0 +1,10 @@
+<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="M4,6L2,6v14c0,1.1 0.9,2 2,2h14v-2L4,20L4,6zM20,2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM20,16L8,16L8,4h5v7l2.5,-1.88L18,11L18,4h2v12z"/>
+</vector>
diff --git a/PermissionController/res/drawable-v34/ic_gear.xml b/PermissionController/res/drawable-v34/ic_gear.xml
new file mode 100644
index 000000000..958284d4c
--- /dev/null
+++ b/PermissionController/res/drawable-v34/ic_gear.xml
@@ -0,0 +1,13 @@
+<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="M13.85,22.25h-3.7c-0.74,0 -1.36,-0.54 -1.45,-1.27l-0.27,-1.89c-0.27,-0.14 -0.53,-0.29 -0.79,-0.46l-1.8,0.72c-0.7,0.26 -1.47,-0.03 -1.81,-0.65L2.2,15.53c-0.35,-0.66 -0.2,-1.44 0.36,-1.88l1.53,-1.19c-0.01,-0.15 -0.02,-0.3 -0.02,-0.46 0,-0.15 0.01,-0.31 0.02,-0.46l-1.52,-1.19c-0.59,-0.45 -0.74,-1.26 -0.37,-1.88l1.85,-3.19c0.34,-0.62 1.11,-0.9 1.79,-0.63l1.81,0.73c0.26,-0.17 0.52,-0.32 0.78,-0.46l0.27,-1.91c0.09,-0.7 0.71,-1.25 1.44,-1.25h3.7c0.74,0 1.36,0.54 1.45,1.27l0.27,1.89c0.27,0.14 0.53,0.29 0.79,0.46l1.8,-0.72c0.71,-0.26 1.48,0.03 1.82,0.65l1.84,3.18c0.36,0.66 0.2,1.44 -0.36,1.88l-1.52,1.19c0.01,0.15 0.02,0.3 0.02,0.46s-0.01,0.31 -0.02,0.46l1.52,1.19c0.56,0.45 0.72,1.23 0.37,1.86l-1.86,3.22c-0.34,0.62 -1.11,0.9 -1.8,0.63l-1.8,-0.72c-0.26,0.17 -0.52,0.32 -0.78,0.46l-0.27,1.91c-0.1,0.68 -0.72,1.22 -1.46,1.22zM10.62,20.25h2.76l0.37,-2.55 0.53,-0.22c0.44,-0.18 0.88,-0.44 1.34,-0.78l0.45,-0.34 2.38,0.96 1.38,-2.4 -2.03,-1.58 0.07,-0.56c0.03,-0.26 0.06,-0.51 0.06,-0.78s-0.03,-0.53 -0.06,-0.78l-0.07,-0.56 2.03,-1.58 -1.39,-2.4 -2.39,0.96 -0.45,-0.35c-0.42,-0.32 -0.87,-0.58 -1.33,-0.77l-0.52,-0.22 -0.37,-2.55h-2.76l-0.37,2.55 -0.53,0.21c-0.44,0.19 -0.88,0.44 -1.34,0.79l-0.45,0.33 -2.38,-0.95 -1.39,2.39 2.03,1.58 -0.07,0.56c-0.03,0.26 -0.06,0.53 -0.06,0.79s0.02,0.53 0.06,0.78l0.07,0.56 -2.03,1.58 1.38,2.4 2.39,-0.96 0.45,0.35c0.43,0.33 0.86,0.58 1.33,0.77l0.53,0.22 0.38,2.55z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,12m-3.5,0a3.5,3.5 0,1 1,7 0a3.5,3.5 0,1 1,-7 0"/>
+</vector>
diff --git a/PermissionController/res/drawable-v34/ic_help.xml b/PermissionController/res/drawable-v34/ic_help.xml
new file mode 100644
index 000000000..5a8f419f6
--- /dev/null
+++ b/PermissionController/res/drawable-v34/ic_help.xml
@@ -0,0 +1,11 @@
+<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"
+ android:autoMirrored="true">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11,18h2v-2h-2v2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM12,6c-2.21,0 -4,1.79 -4,4h2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2c0,2 -3,1.75 -3,5h2c0,-2.25 3,-2.5 3,-5 0,-2.21 -1.79,-4 -4,-4z"/>
+</vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/ic_info_24dp.xml b/PermissionController/res/drawable-v34/ic_info_24dp.xml
new file mode 100644
index 000000000..35f7f5f61
--- /dev/null
+++ b/PermissionController/res/drawable-v34/ic_info_24dp.xml
@@ -0,0 +1,10 @@
+<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="M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
+</vector>
diff --git a/PermissionController/res/drawable-v34/ic_safety_center_brand_chip.xml b/PermissionController/res/drawable-v34/ic_safety_center_brand_chip.xml
new file mode 100644
index 000000000..82ee628ff
--- /dev/null
+++ b/PermissionController/res/drawable-v34/ic_safety_center_brand_chip.xml
@@ -0,0 +1,14 @@
+<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/textColorPrimary">
+ <group>
+ <clip-path
+ android:pathData="M4,2h16v20h-16z"/>
+ <path
+ android:pathData="M18.92,4.4L12.56,2.1C12.38,2.03 12.19,2 12,2C11.81,2 11.62,2.03 11.44,2.1L5.08,4.4C4.43,4.63 4,5.25 4,5.94V10.32C4.02,11.07 4.07,11.79 4.17,12.54C4.64,15.72 6.44,19.33 11.37,21.85C11.57,21.95 11.78,22 12,22C12.22,22 12.43,21.95 12.63,21.85C13.08,21.62 13.5,21.37 13.9,21.12C14.04,21.05 14.18,20.96 14.32,20.86C17.98,18.43 19.41,15.32 19.82,12.54C19.92,11.8 19.98,11.07 19.99,10.32V5.94C19.99,5.25 19.56,4.64 18.91,4.4H18.92ZM12.25,19.78C12.1,19.87 11.9,19.87 11.74,19.78C8.5,17.97 6.62,15.43 6.15,12.27C6.06,11.59 6.01,10.94 6,10.32V6.55C6,6.34 6.13,6.15 6.33,6.08L8.26,5.38C8.11,5.89 8.03,6.44 8.03,7.04C8.04,8.91 9.03,10.68 10.7,11.8C11.15,12.08 12.39,12.89 12.78,13.19C13.27,13.57 13.95,14.21 14.26,14.74C15.29,16.52 14.26,18.46 13.1,19.27C12.83,19.45 12.55,19.62 12.25,19.79V19.78ZM17.85,12.24C17.66,13.49 17.26,14.63 16.65,15.68C16.57,15.04 16.37,14.38 15.99,13.74C15.42,12.75 14.33,11.86 14.01,11.61C13.47,11.19 11.94,10.22 11.79,10.12C10.69,9.39 10.04,8.23 10.03,6.99C10.03,5.01 11.25,4.34 11.98,4.12C12.08,4.09 12.19,4.1 12.29,4.13L17.68,6.08C17.88,6.15 18.01,6.34 18.01,6.55V10.28C18,10.94 17.95,11.59 17.86,12.24H17.85Z"
+ android:fillColor="#000000"/>
+ </group>
+</vector>
diff --git a/PermissionController/res/drawable-v34/ic_safety_center_shield.xml b/PermissionController/res/drawable-v34/ic_safety_center_shield.xml
new file mode 100644
index 000000000..b7e7d7e5f
--- /dev/null
+++ b/PermissionController/res/drawable-v34/ic_safety_center_shield.xml
@@ -0,0 +1,14 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20"
+ android:tint="?android:attr/textColorPrimary">
+ <group>
+ <clip-path
+ android:pathData="M3.5,2h13v16h-13z"/>
+ <path
+ android:pathData="M15.619,3.92L10.451,2.08C10.305,2.024 10.151,2 9.996,2C9.842,2 9.687,2.024 9.541,2.08L4.374,3.92C3.845,4.104 3.496,4.6 3.496,5.152V8.656C3.512,9.256 3.553,9.832 3.634,10.432C4.016,12.976 5.479,15.864 9.484,17.88C9.647,17.96 9.817,18 9.996,18C10.175,18 10.345,17.96 10.508,17.88C10.874,17.696 11.215,17.496 11.54,17.296C11.654,17.24 11.767,17.168 11.881,17.088C14.855,15.144 16.017,12.656 16.35,10.432C16.431,9.84 16.48,9.256 16.488,8.656V5.152C16.488,4.6 16.139,4.112 15.611,3.92H15.619ZM10.199,16.224C10.077,16.296 9.915,16.296 9.785,16.224C7.152,14.776 5.625,12.744 5.243,10.216C5.17,9.672 5.129,9.152 5.121,8.656V5.64C5.121,5.472 5.227,5.32 5.389,5.264L6.957,4.704C6.835,5.112 6.77,5.552 6.77,6.032C6.779,7.528 7.583,8.944 8.94,9.84C9.305,10.064 10.313,10.712 10.63,10.952C11.028,11.256 11.58,11.768 11.832,12.192C12.669,13.616 11.832,15.168 10.89,15.816C10.67,15.96 10.443,16.096 10.199,16.232V16.224ZM14.749,10.192C14.595,11.192 14.27,12.104 13.774,12.944C13.709,12.432 13.547,11.904 13.238,11.392C12.775,10.6 11.889,9.888 11.629,9.688C11.191,9.352 9.947,8.576 9.825,8.496C8.932,7.912 8.404,6.984 8.395,5.992C8.395,4.408 9.387,3.872 9.98,3.696C10.061,3.672 10.151,3.68 10.232,3.704L14.611,5.264C14.774,5.32 14.879,5.472 14.879,5.64V8.624C14.871,9.152 14.83,9.672 14.757,10.192H14.749Z"
+ android:fillColor="#000000"/>
+ </group>
+</vector>
diff --git a/PermissionController/res/drawable-v34/ic_safety_info.xml b/PermissionController/res/drawable-v34/ic_safety_info.xml
new file mode 100644
index 000000000..59ffbcfe4
--- /dev/null
+++ b/PermissionController/res/drawable-v34/ic_safety_info.xml
@@ -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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <path
+ android:pathData="M2,10a8,8 0,1 0,16.001 0a8,8 0,1 0,-16.001 0z"
+ android:fillColor="?attr/colorScIconInfo"/>
+ <group>
+ <clip-path
+ android:pathData="M5.258,5.292h9.412v9.416h-9.412z"/>
+ <path
+ android:pathData="M5.98,10.139L8.543,12.657L13.948,7.346"
+ android:strokeWidth="1.92076"
+ android:fillColor="#00000000"
+ android:strokeColor="?attr/colorScShieldAccent"/>
+ </group>
+</vector>
diff --git a/PermissionController/res/drawable-v34/ic_safety_null_state.xml b/PermissionController/res/drawable-v34/ic_safety_null_state.xml
new file mode 100644
index 000000000..a9dd828aa
--- /dev/null
+++ b/PermissionController/res/drawable-v34/ic_safety_null_state.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ 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="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <path
+ android:pathData="M10,2a8,8 0,1 0,-0 16.001a8,8 0,1 0,-0 -16.001z"
+ android:fillColor="?attr/colorScIconNull"/>
+ <path
+ android:pathData="M14.232,9.002L5.772,9.002L5.772,11.005L14.232,11.005L14.232,9.002Z"
+ android:fillColor="?attr/colorScShieldAccent"/>
+</vector>
diff --git a/PermissionController/res/drawable-v34/ic_safety_recommendation.xml b/PermissionController/res/drawable-v34/ic_safety_recommendation.xml
new file mode 100644
index 000000000..dedec6a87
--- /dev/null
+++ b/PermissionController/res/drawable-v34/ic_safety_recommendation.xml
@@ -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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <path
+ android:pathData="M2,10a8,8 0,1 0,16.001 0a8,8 0,1 0,-16.001 0z"
+ android:fillColor="?attr/colorScIconRecommend"/>
+ <path
+ android:pathData="M9.963,5.764V10.47"
+ android:strokeWidth="2.00079"
+ android:fillColor="#00000000"
+ android:strokeColor="@color/sc_shield_accent_fixed_variant"/>
+ <path
+ android:pathData="M9.963,12.118V14.239"
+ android:strokeWidth="2.00079"
+ android:fillColor="#00000000"
+ android:strokeColor="@color/sc_shield_accent_fixed_variant"/>
+</vector>
diff --git a/PermissionController/res/drawable-v34/ic_safety_warn.xml b/PermissionController/res/drawable-v34/ic_safety_warn.xml
new file mode 100644
index 000000000..7acacbc5a
--- /dev/null
+++ b/PermissionController/res/drawable-v34/ic_safety_warn.xml
@@ -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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <path
+ android:pathData="M2,10a8,8 0,1 0,16.001 0a8,8 0,1 0,-16.001 0z"
+ android:fillColor="?attr/colorScIconWarn"/>
+ <path
+ android:pathData="M10,5.764V10.47"
+ android:strokeWidth="2.00079"
+ android:fillColor="#00000000"
+ android:strokeColor="?attr/colorScShieldAccent"/>
+ <path
+ android:pathData="M10,12.118V14.239"
+ android:strokeWidth="2.00079"
+ android:fillColor="#00000000"
+ android:strokeColor="?attr/colorScShieldAccent"/>
+</vector>
diff --git a/PermissionController/res/drawable/safety_center_button_background_dark.xml b/PermissionController/res/drawable-v34/safety_center_brand_chip_background.xml
index 90884857c..2d216edd8 100644
--- a/PermissionController/res/drawable/safety_center_button_background_dark.xml
+++ b/PermissionController/res/drawable-v34/safety_center_brand_chip_background.xml
@@ -1,5 +1,5 @@
<!--
- ~ Copyright (C) 2021 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,8 +14,7 @@
~ limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="#FF444444"/>
- <corners android:radius="20dp" />
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="?attr/colorSurface" />
+ <corners android:radius="@dimen/sc_brand_chip_corner_radius"/>
</shape> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/safety_status_info.xml b/PermissionController/res/drawable-v34/safety_status_info.xml
new file mode 100644
index 000000000..c12c19144
--- /dev/null
+++ b/PermissionController/res/drawable-v34/safety_status_info.xml
@@ -0,0 +1,20 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="56dp"
+ android:height="56dp"
+ android:viewportWidth="56"
+ android:viewportHeight="56">
+ <group>
+ <clip-path
+ android:pathData="M28,0L28,0A28,28 0,0 1,56 28L56,28A28,28 0,0 1,28 56L28,56A28,28 0,0 1,0 28L0,28A28,28 0,0 1,28 0z"/>
+ <path
+ android:pathData="M28,28m-28,0a28,28 0,1 1,56 0a28,28 0,1 1,-56 0"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"/>
+ <path
+ android:pathData="M14.5,25.14C14.525,26.402 14.623,27.66 14.792,28.91C15.592,34.319 18.623,40.446 26.932,44.74C27.262,44.91 27.628,44.999 28,44.999C28.372,44.999 28.738,44.91 29.068,44.74C37.377,40.446 40.408,34.319 41.208,28.91C41.377,27.66 41.475,26.401 41.5,25.14V17.67C41.5,17.099 41.324,16.541 40.997,16.073C40.669,15.605 40.205,15.249 39.669,15.055L28.946,11.166C28.335,10.944 27.665,10.944 27.054,11.166L16.331,15.055C15.795,15.249 15.331,15.605 15.003,16.073C14.676,16.541 14.5,17.099 14.5,17.67V25.14Z"
+ android:fillColor="?attr/colorScStatusInfo"/>
+ <path
+ android:pathData="M36.172,23.255L25.503,33.814L19.829,28.198L22.172,25.831L25.503,29.129L33.829,20.888L36.172,23.255Z"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillType="evenOdd"/>
+ </group>
+</vector>
diff --git a/PermissionController/res/drawable-v34/safety_status_info_to_info_anim.xml b/PermissionController/res/drawable-v34/safety_status_info_to_info_anim.xml
new file mode 100644
index 000000000..91d07a50d
--- /dev/null
+++ b/PermissionController/res/drawable-v34/safety_status_info_to_info_anim.xml
@@ -0,0 +1,245 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="224dp"
+ android:width="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_3_G">
+ <path
+ android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_2_G"
+ android:pivotX="112"
+ android:pivotY="112"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="84"
+ android:translateY="84"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusInfo"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="84"
+ android:translateY="84"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M36.17 23.26 C36.17,23.26 25.5,33.81 25.5,33.81 C25.5,33.81 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 25.5,29.13 25.5,29.13 C25.5,29.13 33.83,20.89 33.83,20.89 C33.83,20.89 36.17,23.26 36.17,23.26c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_3_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="fillAlpha"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="250"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="250"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="517"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="517"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="783"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/safety_status_recommend_to_info_anim.xml b/PermissionController/res/drawable-v34/safety_status_recommend_to_info_anim.xml
new file mode 100644
index 000000000..c618ff308
--- /dev/null
+++ b/PermissionController/res/drawable-v34/safety_status_recommend_to_info_anim.xml
@@ -0,0 +1,722 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_5_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_4_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="517"
+ android:propertyName="scaleX"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="517"
+ android:propertyName="scaleY"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="?attr/colorScStatusRecommend"
+ android:valueTo="?attr/colorScStatusRecommend"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillColor"
+ android:startOffset="150"
+ android:valueFrom="?attr/colorScStatusRecommend"
+ android:valueTo="?attr/colorScStatusInfo"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M22.2 25.82 C22.2,25.82 19.84,28.17 19.84,28.17 C19.84,28.17 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 22.15,25.8 22.15,25.8 C22.15,25.8 22.22,25.82 22.22,25.82 C22.22,25.82 22.2,25.82 22.2,25.82c "
+ android:valueTo="M22.2 25.82 C22.2,25.82 19.84,28.17 19.84,28.17 C19.84,28.17 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 22.15,25.8 22.15,25.8 C22.15,25.8 22.22,25.82 22.22,25.82 C22.22,25.82 22.2,25.82 22.2,25.82c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="pathData"
+ android:startOffset="150"
+ android:valueFrom="M22.2 25.82 C22.2,25.82 19.84,28.17 19.84,28.17 C19.84,28.17 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 22.15,25.8 22.15,25.8 C22.15,25.8 22.22,25.82 22.22,25.82 C22.22,25.82 22.2,25.82 22.2,25.82c "
+ android:valueTo="M27.89 31.53 C27.89,31.53 25.5,33.81 25.5,33.81 C25.5,33.81 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 25.5,29.13 25.5,29.13 C25.5,29.13 25.54,29.17 25.54,29.17 C25.54,29.17 27.89,31.53 27.89,31.53c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="pathData"
+ android:startOffset="200"
+ android:valueFrom="M27.89 31.53 C27.89,31.53 25.5,33.81 25.5,33.81 C25.5,33.81 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 25.5,29.13 25.5,29.13 C25.5,29.13 25.54,29.17 25.54,29.17 C25.54,29.17 27.89,31.53 27.89,31.53c "
+ android:valueTo="M36.17 23.26 C36.17,23.26 25.5,33.81 25.5,33.81 C25.5,33.81 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 25.5,29.13 25.5,29.13 C25.5,29.13 33.83,20.89 33.83,20.89 C33.83,20.89 36.17,23.26 36.17,23.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.29,0 0.739,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_N_4_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_N_4_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="0"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="4"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="150"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M25.92 28.4 C25.92,28.4 25.92,18.4 25.92,18.4 C25.92,18.4 30.09,18.4 30.09,18.4 C30.09,18.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueTo="M25.92 28.4 C25.92,28.4 25.89,28.4 25.89,28.4 C25.89,28.4 30.06,28.4 30.06,28.4 C30.06,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.18,0 0.043,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="117"
+ android:pathData="M 0,0C 0,1.298 0,6.49 0,7.788"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_4_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_4_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="0"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="4"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_4_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="0"
+ android:propertyName="scaleY"
+ android:startOffset="350"
+ android:valueFrom="4"
+ android:valueTo="0"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="133"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="133"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="133"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M25.92 36.4 C25.92,36.4 25.92,31.89 25.92,31.89 C25.92,31.89 30.09,31.89 30.09,31.89 C30.09,31.89 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c "
+ android:valueTo="M25.92 36.4 C25.92,36.4 25.94,36.39 25.94,36.39 C25.94,36.39 30.11,36.39 30.11,36.39 C30.11,36.39 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.989,0 0.789,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_4_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_4_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="0"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="4"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_4_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="0"
+ android:propertyName="scaleY"
+ android:startOffset="350"
+ android:valueFrom="4"
+ android:valueTo="0"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="767"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="224dp"
+ android:height="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_5_G">
+ <path
+ android:name="_R_G_L_5_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusBackgroundRecommend"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_4_G"
+ android:pivotX="112"
+ android:pivotY="112"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_4_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_3_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusRecommend"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ <group
+ android:name="_R_G_L_2_G_N_4_T_0"
+ android:scaleX="4"
+ android:scaleY="0"
+ android:translateX="112"
+ android:translateY="112">
+ <group
+ android:name="_R_G_L_2_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillType="nonZero"
+ android:pathData=" M22.2 25.82 C22.2,25.82 19.84,28.17 19.84,28.17 C19.84,28.17 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 22.15,25.8 22.15,25.8 C22.15,25.8 22.22,25.82 22.22,25.82 C22.22,25.82 22.2,25.82 22.2,25.82c " />
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_1_G_N_4_T_0"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="112"
+ android:translateY="112">
+ <group
+ android:name="_R_G_L_1_G_T_1"
+ android:translateX="0"
+ android:translateY="0">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="@color/sc_shield_accent_fixed_variant"
+ android:fillType="nonZero"
+ android:pathData=" M25.92 28.4 C25.92,28.4 25.92,18.4 25.92,18.4 C25.92,18.4 30.09,18.4 30.09,18.4 C30.09,18.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c " />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G_N_4_T_0"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="112"
+ android:translateY="112">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="@color/sc_shield_accent_fixed_variant"
+ android:fillType="nonZero"
+ android:pathData=" M25.92 36.4 C25.92,36.4 25.92,31.89 25.92,31.89 C25.92,31.89 30.09,31.89 30.09,31.89 C30.09,31.89 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c " />
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/safety_status_recommendation.xml b/PermissionController/res/drawable-v34/safety_status_recommendation.xml
new file mode 100644
index 000000000..4dcab9f9d
--- /dev/null
+++ b/PermissionController/res/drawable-v34/safety_status_recommendation.xml
@@ -0,0 +1,24 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="56dp"
+ android:height="56dp"
+ android:viewportWidth="56"
+ android:viewportHeight="56">
+ <group>
+ <clip-path
+ android:pathData="M28,0L28,0A28,28 0,0 1,56 28L56,28A28,28 0,0 1,28 56L28,56A28,28 0,0 1,0 28L0,28A28,28 0,0 1,28 0z"/>
+ <path
+ android:pathData="M28,28m-28,0a28,28 0,1 1,56 0a28,28 0,1 1,-56 0"
+ android:fillColor="?attr/colorScStatusBackgroundRecommend"/>
+ <path
+ android:pathData="M14.5,25.14C14.525,26.402 14.623,27.66 14.792,28.91C15.592,34.319 18.623,40.446 26.932,44.74C27.262,44.91 27.628,44.999 28,44.999C28.372,44.999 28.738,44.91 29.068,44.74C37.377,40.446 40.408,34.319 41.208,28.91C41.377,27.66 41.475,26.401 41.5,25.14V17.67C41.5,17.099 41.324,16.541 40.997,16.073C40.669,15.605 40.205,15.249 39.669,15.055L28.946,11.166C28.335,10.944 27.665,10.944 27.054,11.166L16.331,15.055C15.795,15.249 15.331,15.605 15.003,16.073C14.676,16.541 14.5,17.099 14.5,17.67V25.14Z"
+ android:fillColor="?attr/colorScStatusRecommend"/>
+ <path
+ android:pathData="M25.916,28.397V18.4H30.086V28.397H25.916Z"
+ android:fillColor="@color/sc_shield_accent_fixed_variant"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M25.916,36.4V31.894H30.086V36.4H25.916Z"
+ android:fillColor="@color/sc_shield_accent_fixed_variant"
+ android:fillType="evenOdd"/>
+ </group>
+</vector>
diff --git a/PermissionController/res/drawable-v34/safety_status_small_info_to_info_anim.xml b/PermissionController/res/drawable-v34/safety_status_small_info_to_info_anim.xml
new file mode 100644
index 000000000..264a3fc92
--- /dev/null
+++ b/PermissionController/res/drawable-v34/safety_status_small_info_to_info_anim.xml
@@ -0,0 +1,163 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="317"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportHeight="20"
+ android:viewportWidth="20">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="0"
+ android:scaleY="0"
+ android:translateX="2"
+ android:translateY="2">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScIconInfo"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C12.42,0 16,3.58 16,8 C16,12.42 12.42,16 8,16 C3.58,16 0,12.42 0,8 C0,3.58 3.58,0 8,0c " />
+ <path
+ android:name="_R_G_L_1_G_D_1_P_0"
+ android:pathData=" M3.98 8.14 C3.98,8.14 6.54,10.66 6.54,10.66 C6.54,10.66 11.95,5.35 11.95,5.35 "
+ android:strokeAlpha="1"
+ android:strokeColor="?attr/colorScShieldAccent"
+ android:strokeWidth="1.921" />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="2"
+ android:translateY="2">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScIconInfo"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C12.42,0 16,3.58 16,8 C16,12.42 12.42,16 8,16 C3.58,16 0,12.42 0,8 C0,3.58 3.58,0 8,0c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:pathData=" M3.98 8.14 C3.98,8.14 6.54,10.66 6.54,10.66 C6.54,10.66 11.95,5.35 11.95,5.35 "
+ android:strokeAlpha="1"
+ android:strokeColor="?attr/colorScShieldAccent"
+ android:strokeWidth="1.921" />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/PermissionController/res/drawable-v34/safety_status_small_info_to_recommendation_anim.xml b/PermissionController/res/drawable-v34/safety_status_small_info_to_recommendation_anim.xml
new file mode 100644
index 000000000..ec9ad1b2c
--- /dev/null
+++ b/PermissionController/res/drawable-v34/safety_status_small_info_to_recommendation_anim.xml
@@ -0,0 +1,163 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="317"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportHeight="20"
+ android:viewportWidth="20">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="0"
+ android:scaleY="0"
+ android:translateX="2"
+ android:translateY="2">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScIconRecommend"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C12.42,0 16,3.58 16,8 C16,12.42 12.42,16 8,16 C3.58,16 0,12.42 0,8 C0,3.58 3.58,0 8,0c " />
+ <path
+ android:name="_R_G_L_1_G_D_1_P_0"
+ android:pathData=" M7.96 10.12 C7.96,10.12 7.96,12.24 7.96,12.24 M7.96 3.76 C7.96,3.76 7.96,8.47 7.96,8.47 "
+ android:strokeAlpha="1"
+ android:strokeColor="@color/sc_shield_accent_fixed_variant"
+ android:strokeWidth="2.001" />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="2"
+ android:translateY="2">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScIconInfo"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C12.42,0 16,3.58 16,8 C16,12.42 12.42,16 8,16 C3.58,16 0,12.42 0,8 C0,3.58 3.58,0 8,0c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:pathData=" M3.98 8.14 C3.98,8.14 6.54,10.66 6.54,10.66 C6.54,10.66 11.95,5.35 11.95,5.35 "
+ android:strokeAlpha="1"
+ android:strokeColor="?attr/colorScShieldAccent"
+ android:strokeWidth="1.921" />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/PermissionController/res/drawable-v34/safety_status_small_info_to_warn_anim.xml b/PermissionController/res/drawable-v34/safety_status_small_info_to_warn_anim.xml
new file mode 100644
index 000000000..21a215b7b
--- /dev/null
+++ b/PermissionController/res/drawable-v34/safety_status_small_info_to_warn_anim.xml
@@ -0,0 +1,163 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="317"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportHeight="20"
+ android:viewportWidth="20">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="0"
+ android:scaleY="0"
+ android:translateX="2"
+ android:translateY="2">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScIconWarn"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C12.42,0 16,3.58 16,8 C16,12.42 12.42,16 8,16 C3.58,16 0,12.42 0,8 C0,3.58 3.58,0 8,0c " />
+ <path
+ android:name="_R_G_L_1_G_D_1_P_0"
+ android:pathData=" M8 10.12 C8,10.12 8,12.24 8,12.24 M8 3.76 C8,3.76 8,8.47 8,8.47 "
+ android:strokeAlpha="1"
+ android:strokeColor="?attr/colorScShieldAccent"
+ android:strokeWidth="2.001" />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="2"
+ android:translateY="2">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScIconInfo"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C12.42,0 16,3.58 16,8 C16,12.42 12.42,16 8,16 C3.58,16 0,12.42 0,8 C0,3.58 3.58,0 8,0c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:pathData=" M3.98 8.14 C3.98,8.14 6.54,10.66 6.54,10.66 C6.54,10.66 11.95,5.35 11.95,5.35 "
+ android:strokeAlpha="1"
+ android:strokeColor="?attr/colorScShieldAccent"
+ android:strokeWidth="1.921" />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/PermissionController/res/drawable-v34/safety_status_small_recommendation_to_info_anim.xml b/PermissionController/res/drawable-v34/safety_status_small_recommendation_to_info_anim.xml
new file mode 100644
index 000000000..696a66999
--- /dev/null
+++ b/PermissionController/res/drawable-v34/safety_status_small_recommendation_to_info_anim.xml
@@ -0,0 +1,163 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="317"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportHeight="20"
+ android:viewportWidth="20">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="0"
+ android:scaleY="0"
+ android:translateX="2"
+ android:translateY="2">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScIconInfo"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C12.42,0 16,3.58 16,8 C16,12.42 12.42,16 8,16 C3.58,16 0,12.42 0,8 C0,3.58 3.58,0 8,0c " />
+ <path
+ android:name="_R_G_L_1_G_D_1_P_0"
+ android:pathData=" M3.98 8.14 C3.98,8.14 6.54,10.66 6.54,10.66 C6.54,10.66 11.95,5.35 11.95,5.35 "
+ android:strokeAlpha="1"
+ android:strokeColor="?attr/colorScShieldAccent"
+ android:strokeWidth="1.921" />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="2"
+ android:translateY="2">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScIconRecommend"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C12.42,0 16,3.58 16,8 C16,12.42 12.42,16 8,16 C3.58,16 0,12.42 0,8 C0,3.58 3.58,0 8,0c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:pathData=" M7.96 10.12 C7.96,10.12 7.96,12.24 7.96,12.24 M7.96 3.76 C7.96,3.76 7.96,8.47 7.96,8.47 "
+ android:strokeAlpha="1"
+ android:strokeColor="@color/sc_shield_accent_fixed_variant"
+ android:strokeWidth="2.001" />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/PermissionController/res/drawable-v34/safety_status_small_recommendation_to_recommendation_anim.xml b/PermissionController/res/drawable-v34/safety_status_small_recommendation_to_recommendation_anim.xml
new file mode 100644
index 000000000..9e69006fb
--- /dev/null
+++ b/PermissionController/res/drawable-v34/safety_status_small_recommendation_to_recommendation_anim.xml
@@ -0,0 +1,163 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="317"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportHeight="20"
+ android:viewportWidth="20">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="0"
+ android:scaleY="0"
+ android:translateX="2"
+ android:translateY="2">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScIconRecommend"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C12.42,0 16,3.58 16,8 C16,12.42 12.42,16 8,16 C3.58,16 0,12.42 0,8 C0,3.58 3.58,0 8,0c " />
+ <path
+ android:name="_R_G_L_1_G_D_1_P_0"
+ android:pathData=" M7.96 10.12 C7.96,10.12 7.96,12.24 7.96,12.24 M7.96 3.76 C7.96,3.76 7.96,8.47 7.96,8.47 "
+ android:strokeAlpha="1"
+ android:strokeColor="@color/sc_shield_accent_fixed_variant"
+ android:strokeWidth="2.001" />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="2"
+ android:translateY="2">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScIconRecommend"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C12.42,0 16,3.58 16,8 C16,12.42 12.42,16 8,16 C3.58,16 0,12.42 0,8 C0,3.58 3.58,0 8,0c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:pathData=" M7.96 10.12 C7.96,10.12 7.96,12.24 7.96,12.24 M7.96 3.76 C7.96,3.76 7.96,8.47 7.96,8.47 "
+ android:strokeAlpha="1"
+ android:strokeColor="@color/sc_shield_accent_fixed_variant"
+ android:strokeWidth="2.001" />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/PermissionController/res/drawable-v34/safety_status_small_recommendation_to_warn_anim.xml b/PermissionController/res/drawable-v34/safety_status_small_recommendation_to_warn_anim.xml
new file mode 100644
index 000000000..4264bf81a
--- /dev/null
+++ b/PermissionController/res/drawable-v34/safety_status_small_recommendation_to_warn_anim.xml
@@ -0,0 +1,163 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="317"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportHeight="20"
+ android:viewportWidth="20">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="0"
+ android:scaleY="0"
+ android:translateX="2"
+ android:translateY="2">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScIconWarn"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C12.42,0 16,3.58 16,8 C16,12.42 12.42,16 8,16 C3.58,16 0,12.42 0,8 C0,3.58 3.58,0 8,0c " />
+ <path
+ android:name="_R_G_L_1_G_D_1_P_0"
+ android:pathData=" M8 10.12 C8,10.12 8,12.24 8,12.24 M8 3.76 C8,3.76 8,8.47 8,8.47 "
+ android:strokeAlpha="1"
+ android:strokeColor="?attr/colorScShieldAccent"
+ android:strokeWidth="2.001" />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="2"
+ android:translateY="2">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScIconRecommend"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C12.42,0 16,3.58 16,8 C16,12.42 12.42,16 8,16 C3.58,16 0,12.42 0,8 C0,3.58 3.58,0 8,0c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:pathData=" M7.96 10.12 C7.96,10.12 7.96,12.24 7.96,12.24 M7.96 3.76 C7.96,3.76 7.96,8.47 7.96,8.47 "
+ android:strokeAlpha="1"
+ android:strokeColor="@color/sc_shield_accent_fixed_variant"
+ android:strokeWidth="2.001" />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/PermissionController/res/drawable-v34/safety_status_small_warn_to_info_anim.xml b/PermissionController/res/drawable-v34/safety_status_small_warn_to_info_anim.xml
new file mode 100644
index 000000000..79779a6a2
--- /dev/null
+++ b/PermissionController/res/drawable-v34/safety_status_small_warn_to_info_anim.xml
@@ -0,0 +1,163 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="317"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportHeight="20"
+ android:viewportWidth="20">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="0"
+ android:scaleY="0"
+ android:translateX="2"
+ android:translateY="2">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScIconInfo"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C12.42,0 16,3.58 16,8 C16,12.42 12.42,16 8,16 C3.58,16 0,12.42 0,8 C0,3.58 3.58,0 8,0c " />
+ <path
+ android:name="_R_G_L_1_G_D_1_P_0"
+ android:pathData=" M3.98 8.14 C3.98,8.14 6.54,10.66 6.54,10.66 C6.54,10.66 11.95,5.35 11.95,5.35 "
+ android:strokeAlpha="1"
+ android:strokeColor="?attr/colorScShieldAccent"
+ android:strokeWidth="1.921" />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="2"
+ android:translateY="2">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScIconWarn"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C12.42,0 16,3.58 16,8 C16,12.42 12.42,16 8,16 C3.58,16 0,12.42 0,8 C0,3.58 3.58,0 8,0c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:pathData=" M8 10.12 C8,10.12 8,12.24 8,12.24 M8 3.76 C8,3.76 8,8.47 8,8.47 "
+ android:strokeAlpha="1"
+ android:strokeColor="?attr/colorScShieldAccent"
+ android:strokeWidth="2.001" />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/PermissionController/res/drawable-v34/safety_status_small_warn_to_recommendation_anim.xml b/PermissionController/res/drawable-v34/safety_status_small_warn_to_recommendation_anim.xml
new file mode 100644
index 000000000..c6ae91634
--- /dev/null
+++ b/PermissionController/res/drawable-v34/safety_status_small_warn_to_recommendation_anim.xml
@@ -0,0 +1,163 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="317"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportHeight="20"
+ android:viewportWidth="20">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="0"
+ android:scaleY="0"
+ android:translateX="2"
+ android:translateY="2">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScIconRecommend"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C12.42,0 16,3.58 16,8 C16,12.42 12.42,16 8,16 C3.58,16 0,12.42 0,8 C0,3.58 3.58,0 8,0c " />
+ <path
+ android:name="_R_G_L_1_G_D_1_P_0"
+ android:pathData=" M7.96 10.12 C7.96,10.12 7.96,12.24 7.96,12.24 M7.96 3.76 C7.96,3.76 7.96,8.47 7.96,8.47 "
+ android:strokeAlpha="1"
+ android:strokeColor="@color/sc_shield_accent_fixed_variant"
+ android:strokeWidth="2.001" />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="2"
+ android:translateY="2">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScIconWarn"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C12.42,0 16,3.58 16,8 C16,12.42 12.42,16 8,16 C3.58,16 0,12.42 0,8 C0,3.58 3.58,0 8,0c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:pathData=" M8 10.12 C8,10.12 8,12.24 8,12.24 M8 3.76 C8,3.76 8,8.47 8,8.47 "
+ android:strokeAlpha="1"
+ android:strokeColor="?attr/colorScShieldAccent"
+ android:strokeWidth="2.001" />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/PermissionController/res/drawable-v34/safety_status_small_warn_to_warn_anim.xml b/PermissionController/res/drawable-v34/safety_status_small_warn_to_warn_anim.xml
new file mode 100644
index 000000000..3e2a67a4e
--- /dev/null
+++ b/PermissionController/res/drawable-v34/safety_status_small_warn_to_warn_anim.xml
@@ -0,0 +1,163 @@
+<!--
+ ~ 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="317"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportHeight="20"
+ android:viewportWidth="20">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="0"
+ android:scaleY="0"
+ android:translateX="2"
+ android:translateY="2">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScIconWarn"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C12.42,0 16,3.58 16,8 C16,12.42 12.42,16 8,16 C3.58,16 0,12.42 0,8 C0,3.58 3.58,0 8,0c " />
+ <path
+ android:name="_R_G_L_1_G_D_1_P_0"
+ android:pathData=" M8 10.12 C8,10.12 8,12.24 8,12.24 M8 3.76 C8,3.76 8,8.47 8,8.47 "
+ android:strokeAlpha="1"
+ android:strokeColor="?attr/colorScShieldAccent"
+ android:strokeWidth="2.001" />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="8"
+ android:pivotY="8"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="2"
+ android:translateY="2">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScIconWarn"
+ android:fillType="nonZero"
+ android:pathData=" M8 0 C12.42,0 16,3.58 16,8 C16,12.42 12.42,16 8,16 C3.58,16 0,12.42 0,8 C0,3.58 3.58,0 8,0c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:pathData=" M8 10.12 C8,10.12 8,12.24 8,12.24 M8 3.76 C8,3.76 8,8.47 8,8.47 "
+ android:strokeAlpha="1"
+ android:strokeColor="?attr/colorScShieldAccent"
+ android:strokeWidth="2.001" />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/PermissionController/res/drawable-v34/safety_status_warn.xml b/PermissionController/res/drawable-v34/safety_status_warn.xml
new file mode 100644
index 000000000..6b3304992
--- /dev/null
+++ b/PermissionController/res/drawable-v34/safety_status_warn.xml
@@ -0,0 +1,24 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="56dp"
+ android:height="56dp"
+ android:viewportWidth="56"
+ android:viewportHeight="56">
+ <group>
+ <clip-path
+ android:pathData="M28,0L28,0A28,28 0,0 1,56 28L56,28A28,28 0,0 1,28 56L28,56A28,28 0,0 1,0 28L0,28A28,28 0,0 1,28 0z"/>
+ <path
+ android:pathData="M28,28m-28,0a28,28 0,1 1,56 0a28,28 0,1 1,-56 0"
+ android:fillColor="?attr/colorScStatusBackgroundWarn"/>
+ <path
+ android:pathData="M14.5,25.14C14.525,26.402 14.623,27.66 14.792,28.91C15.592,34.319 18.623,40.446 26.932,44.74C27.262,44.91 27.628,44.999 28,44.999C28.372,44.999 28.738,44.91 29.068,44.74C37.377,40.446 40.408,34.319 41.208,28.91C41.377,27.66 41.475,26.401 41.5,25.14V17.67C41.5,17.099 41.324,16.541 40.997,16.073C40.669,15.605 40.205,15.249 39.669,15.055L28.946,11.166C28.335,10.944 27.665,10.944 27.054,11.166L16.331,15.055C15.795,15.249 15.331,15.605 15.003,16.073C14.676,16.541 14.5,17.099 14.5,17.67V25.14Z"
+ android:fillColor="?attr/colorScStatusWarn"/>
+ <path
+ android:pathData="M25.916,28.397V18.4H30.086V28.397H25.916Z"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M25.916,36.4V31.894H30.086V36.4H25.916Z"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillType="evenOdd"/>
+ </group>
+</vector>
diff --git a/PermissionController/res/drawable-v34/safety_status_warn_to_info_anim.xml b/PermissionController/res/drawable-v34/safety_status_warn_to_info_anim.xml
new file mode 100644
index 000000000..eba9107fe
--- /dev/null
+++ b/PermissionController/res/drawable-v34/safety_status_warn_to_info_anim.xml
@@ -0,0 +1,722 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_5_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_4_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="517"
+ android:propertyName="scaleX"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="517"
+ android:propertyName="scaleY"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="?attr/colorScStatusWarn"
+ android:valueTo="?attr/colorScStatusWarn"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillColor"
+ android:startOffset="150"
+ android:valueFrom="?attr/colorScStatusWarn"
+ android:valueTo="?attr/colorScStatusInfo"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M22.2 25.82 C22.2,25.82 19.84,28.17 19.84,28.17 C19.84,28.17 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 22.15,25.8 22.15,25.8 C22.15,25.8 22.22,25.82 22.22,25.82 C22.22,25.82 22.2,25.82 22.2,25.82c "
+ android:valueTo="M22.2 25.82 C22.2,25.82 19.84,28.17 19.84,28.17 C19.84,28.17 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 22.15,25.8 22.15,25.8 C22.15,25.8 22.22,25.82 22.22,25.82 C22.22,25.82 22.2,25.82 22.2,25.82c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="pathData"
+ android:startOffset="150"
+ android:valueFrom="M22.2 25.82 C22.2,25.82 19.84,28.17 19.84,28.17 C19.84,28.17 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 22.15,25.8 22.15,25.8 C22.15,25.8 22.22,25.82 22.22,25.82 C22.22,25.82 22.2,25.82 22.2,25.82c "
+ android:valueTo="M27.89 31.53 C27.89,31.53 25.5,33.81 25.5,33.81 C25.5,33.81 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 25.5,29.13 25.5,29.13 C25.5,29.13 25.54,29.17 25.54,29.17 C25.54,29.17 27.89,31.53 27.89,31.53c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="pathData"
+ android:startOffset="200"
+ android:valueFrom="M27.89 31.53 C27.89,31.53 25.5,33.81 25.5,33.81 C25.5,33.81 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 25.5,29.13 25.5,29.13 C25.5,29.13 25.54,29.17 25.54,29.17 C25.54,29.17 27.89,31.53 27.89,31.53c "
+ android:valueTo="M36.17 23.26 C36.17,23.26 25.5,33.81 25.5,33.81 C25.5,33.81 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 25.5,29.13 25.5,29.13 C25.5,29.13 33.83,20.89 33.83,20.89 C33.83,20.89 36.17,23.26 36.17,23.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.29,0 0.739,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_N_4_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_N_4_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="0"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="0"
+ android:valueTo="4"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="150"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M25.92 28.4 C25.92,28.4 25.92,18.4 25.92,18.4 C25.92,18.4 30.09,18.4 30.09,18.4 C30.09,18.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueTo="M25.92 28.4 C25.92,28.4 25.89,28.4 25.89,28.4 C25.89,28.4 30.06,28.4 30.06,28.4 C30.06,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.18,0 0.043,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="117"
+ android:pathData="M 0,0C 0,1.298 0,6.49 0,7.788"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_4_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_4_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="0"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="4"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_4_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="0"
+ android:propertyName="scaleY"
+ android:startOffset="183"
+ android:valueFrom="4"
+ android:valueTo="0"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="133"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="133"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="133"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M25.92 36.4 C25.92,36.4 25.92,31.89 25.92,31.89 C25.92,31.89 30.09,31.89 30.09,31.89 C30.09,31.89 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c "
+ android:valueTo="M25.92 36.4 C25.92,36.4 25.94,36.39 25.94,36.39 C25.94,36.39 30.11,36.39 30.11,36.39 C30.11,36.39 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.989,0 0.789,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_4_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_4_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="0"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="4"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_4_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="0"
+ android:propertyName="scaleY"
+ android:startOffset="183"
+ android:valueFrom="4"
+ android:valueTo="0"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="783"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="224dp"
+ android:height="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_5_G">
+ <path
+ android:name="_R_G_L_5_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusBackgroundWarn"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_4_G"
+ android:pivotX="112"
+ android:pivotY="112"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_4_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_3_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusWarn"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ <group
+ android:name="_R_G_L_2_G_N_4_T_0"
+ android:scaleX="4"
+ android:scaleY="0"
+ android:translateX="112"
+ android:translateY="112">
+ <group
+ android:name="_R_G_L_2_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillType="nonZero"
+ android:pathData=" M22.2 25.82 C22.2,25.82 19.84,28.17 19.84,28.17 C19.84,28.17 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 22.15,25.8 22.15,25.8 C22.15,25.8 22.22,25.82 22.22,25.82 C22.22,25.82 22.2,25.82 22.2,25.82c " />
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_1_G_N_4_T_0"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="112"
+ android:translateY="112">
+ <group
+ android:name="_R_G_L_1_G_T_1"
+ android:translateX="0"
+ android:translateY="0">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillType="nonZero"
+ android:pathData=" M25.92 28.4 C25.92,28.4 25.92,18.4 25.92,18.4 C25.92,18.4 30.09,18.4 30.09,18.4 C30.09,18.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c " />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G_N_4_T_0"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="112"
+ android:translateY="112">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillType="nonZero"
+ android:pathData=" M25.92 36.4 C25.92,36.4 25.92,31.89 25.92,31.89 C25.92,31.89 30.09,31.89 30.09,31.89 C30.09,31.89 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c " />
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/safety_status_warn_to_recommend_anim.xml b/PermissionController/res/drawable-v34/safety_status_warn_to_recommend_anim.xml
new file mode 100644
index 000000000..8b97e4871
--- /dev/null
+++ b/PermissionController/res/drawable-v34/safety_status_warn_to_recommend_anim.xml
@@ -0,0 +1,346 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="224dp"
+ android:width="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_3_G">
+ <path
+ android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundWarn"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_2_G"
+ android:pivotX="112"
+ android:pivotY="112"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundRecommend"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="84"
+ android:translateY="84"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusWarn"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="84"
+ android:translateY="84"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M25.92 28.4 C25.92,28.4 25.92,18.4 25.92,18.4 C25.92,18.4 30.09,18.4 30.09,18.4 C30.09,18.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M25.92 36.4 C25.92,36.4 25.92,31.89 25.92,31.89 C25.92,31.89 30.09,31.89 30.09,31.89 C30.09,31.89 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_3_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="fillAlpha"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="250"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="250"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="517"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="517"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="fillColor"
+ android:duration="183"
+ android:startOffset="0"
+ android:valueFrom="?attr/colorScStatusWarn"
+ android:valueTo="?attr/colorScStatusWarn"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="fillColor"
+ android:duration="333"
+ android:startOffset="183"
+ android:valueFrom="?attr/colorScStatusWarn"
+ android:valueTo="?attr/colorScStatusRecommend"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="fillColor"
+ android:duration="250"
+ android:startOffset="517"
+ android:valueFrom="?attr/colorScStatusRecommend"
+ android:valueTo="?attr/colorScStatusRecommend"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="fillColor"
+ android:duration="183"
+ android:startOffset="0"
+ android:valueFrom="?attr/colorScShieldAccent"
+ android:valueTo="?attr/colorScShieldAccent"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="fillColor"
+ android:duration="333"
+ android:startOffset="183"
+ android:valueFrom="?attr/colorScShieldAccent"
+ android:valueTo="@color/sc_shield_accent_fixed_variant"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="fillColor"
+ android:duration="183"
+ android:startOffset="0"
+ android:valueFrom="?attr/colorScShieldAccent"
+ android:valueTo="?attr/colorScShieldAccent"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="fillColor"
+ android:duration="333"
+ android:startOffset="183"
+ android:valueFrom="?attr/colorScShieldAccent"
+ android:valueTo="@color/sc_shield_accent_fixed_variant"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="783"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/status_info_to_scanning_anim.xml b/PermissionController/res/drawable-v34/status_info_to_scanning_anim.xml
new file mode 100644
index 000000000..7a1737b62
--- /dev/null
+++ b/PermissionController/res/drawable-v34/status_info_to_scanning_anim.xml
@@ -0,0 +1,149 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="333"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="317"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="317"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M36.17 23.26 C36.17,23.26 25.5,33.81 25.5,33.81 C25.5,33.81 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 25.5,29.13 25.5,29.13 C25.5,29.13 33.83,20.89 33.83,20.89 C33.83,20.89 36.17,23.26 36.17,23.26c "
+ android:valueTo="M36.17 23.26 C36.17,23.26 25.5,33.81 25.5,33.81 C25.5,33.81 23.14,31.52 23.14,31.52 C23.14,31.52 25.48,29.15 25.48,29.15 C25.48,29.15 25.5,29.13 25.5,29.13 C25.5,29.13 33.83,20.89 33.83,20.89 C33.83,20.89 36.17,23.26 36.17,23.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.928,0.337 0.985,0.984 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="283"
+ android:propertyName="pathData"
+ android:startOffset="50"
+ android:valueFrom="M36.17 23.26 C36.17,23.26 25.5,33.81 25.5,33.81 C25.5,33.81 23.14,31.52 23.14,31.52 C23.14,31.52 25.48,29.15 25.48,29.15 C25.48,29.15 25.5,29.13 25.5,29.13 C25.5,29.13 33.83,20.89 33.83,20.89 C33.83,20.89 36.17,23.26 36.17,23.26c "
+ android:valueTo="M36.17 23.26 C36.17,23.26 36.1,23.19 36.1,23.19 C36.1,23.19 33.74,20.89 33.74,20.89 C33.74,20.89 33.83,20.82 33.83,20.82 C33.83,20.82 33.82,20.84 33.82,20.84 C33.82,20.84 33.83,20.89 33.83,20.89 C33.83,20.89 36.17,23.26 36.17,23.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.007,0.007 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="350"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="224dp"
+ android:height="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_2_G">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusInfo"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillType="nonZero"
+ android:pathData=" M36.17 23.26 C36.17,23.26 25.5,33.81 25.5,33.81 C25.5,33.81 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 25.5,29.13 25.5,29.13 C25.5,29.13 33.83,20.89 33.83,20.89 C33.83,20.89 36.17,23.26 36.17,23.26c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/status_recommend_to_scanning_anim.xml b/PermissionController/res/drawable-v34/status_recommend_to_scanning_anim.xml
new file mode 100644
index 000000000..1b71689a9
--- /dev/null
+++ b/PermissionController/res/drawable-v34/status_recommend_to_scanning_anim.xml
@@ -0,0 +1,225 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_3_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="333"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="150"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M25.92 28.4 C25.92,28.4 25.92,18.4 25.92,18.4 C25.92,18.4 30.09,18.4 30.09,18.4 C30.09,18.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueTo="M25.92 28.4 C25.92,28.4 25.89,28.4 25.89,28.4 C25.89,28.4 30.06,28.4 30.06,28.4 C30.06,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.18,0 0.043,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="117"
+ android:pathData="M 112,112C 112,117.19200000000001 112,137.958 112,143.15"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="133"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="133"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="133"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M25.92 36.4 C25.92,36.4 25.92,31.89 25.92,31.89 C25.92,31.89 30.09,31.89 30.09,31.89 C30.09,31.89 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c "
+ android:valueTo="M25.92 36.4 C25.92,36.4 25.94,36.39 25.94,36.39 C25.94,36.39 30.11,36.39 30.11,36.39 C30.11,36.39 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.989,0 0.789,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="350"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="224dp"
+ android:height="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_3_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusBackgroundRecommend"
+ android:fillType="nonZero"
+ android:pathData=" M28 0 C28,0 28,0 28,0 C43.46,0 56,12.54 56,28 C56,28 56,28 56,28 C56,43.46 43.46,56 28,56 C28,56 28,56 28,56 C12.54,56 0,43.46 0,28 C0,28 0,28 0,28 C0,12.54 12.54,0 28,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_2_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusRecommend"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G_T_1"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="112"
+ android:translateY="112">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="@color/sc_shield_accent_fixed_variant"
+ android:fillType="nonZero"
+ android:pathData=" M25.92 28.4 C25.92,28.4 25.92,18.4 25.92,18.4 C25.92,18.4 30.09,18.4 30.09,18.4 C30.09,18.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c " />
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="@color/sc_shield_accent_fixed_variant"
+ android:fillType="nonZero"
+ android:pathData=" M25.92 36.4 C25.92,36.4 25.92,31.89 25.92,31.89 C25.92,31.89 30.09,31.89 30.09,31.89 C30.09,31.89 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/status_scanning_anim_info.xml b/PermissionController/res/drawable-v34/status_scanning_anim_info.xml
new file mode 100644
index 000000000..e0e952755
--- /dev/null
+++ b/PermissionController/res/drawable-v34/status_scanning_anim_info.xml
@@ -0,0 +1,111 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="583"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.667,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="fillAlpha"
+ android:startOffset="583"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.667,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="1000"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0.1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1000"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0.1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="1000"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="224dp"
+ android:height="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="112"
+ android:pivotY="112"
+ android:scaleX="0.1"
+ android:scaleY="0.1">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusInfo"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/status_scanning_anim_recommend.xml b/PermissionController/res/drawable-v34/status_scanning_anim_recommend.xml
new file mode 100644
index 000000000..50ec7edf2
--- /dev/null
+++ b/PermissionController/res/drawable-v34/status_scanning_anim_recommend.xml
@@ -0,0 +1,111 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="583"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.667,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="fillAlpha"
+ android:startOffset="583"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.667,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="1000"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0.1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1000"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0.1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="1000"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="224dp"
+ android:height="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="112"
+ android:pivotY="112"
+ android:scaleX="0.1"
+ android:scaleY="0.1">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusBackgroundRecommend"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusRecommend"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/status_scanning_anim_warn.xml b/PermissionController/res/drawable-v34/status_scanning_anim_warn.xml
new file mode 100644
index 000000000..d6c319ef0
--- /dev/null
+++ b/PermissionController/res/drawable-v34/status_scanning_anim_warn.xml
@@ -0,0 +1,111 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="583"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.667,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="fillAlpha"
+ android:startOffset="583"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.667,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="1000"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0.1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1000"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0.1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="1000"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="224dp"
+ android:height="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="112"
+ android:pivotY="112"
+ android:scaleX="0.1"
+ android:scaleY="0.1">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusBackgroundWarn"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusWarn"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/status_scanning_end_anim_info_to_info.xml b/PermissionController/res/drawable-v34/status_scanning_end_anim_info_to_info.xml
new file mode 100644
index 000000000..9336ddfa8
--- /dev/null
+++ b/PermissionController/res/drawable-v34/status_scanning_end_anim_info_to_info.xml
@@ -0,0 +1,265 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="517"
+ android:propertyName="scaleX"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="517"
+ android:propertyName="scaleY"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M22.2 25.82 C22.2,25.82 19.84,28.17 19.84,28.17 C19.84,28.17 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 22.15,25.8 22.15,25.8 C22.15,25.8 22.22,25.82 22.22,25.82 C22.22,25.82 22.2,25.82 22.2,25.82c "
+ android:valueTo="M27.89 31.53 C27.89,31.53 25.5,33.81 25.5,33.81 C25.5,33.81 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 25.5,29.13 25.5,29.13 C25.5,29.13 25.54,29.17 25.54,29.17 C25.54,29.17 27.89,31.53 27.89,31.53c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="pathData"
+ android:startOffset="50"
+ android:valueFrom="M27.89 31.53 C27.89,31.53 25.5,33.81 25.5,33.81 C25.5,33.81 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 25.5,29.13 25.5,29.13 C25.5,29.13 25.54,29.17 25.54,29.17 C25.54,29.17 27.89,31.53 27.89,31.53c "
+ android:valueTo="M36.17 23.26 C36.17,23.26 25.5,33.81 25.5,33.81 C25.5,33.81 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 25.5,29.13 25.5,29.13 C25.5,29.13 33.83,20.89 33.83,20.89 C33.83,20.89 36.17,23.26 36.17,23.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.29,0 0.739,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="767"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="224dp"
+ android:height="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_2_G"
+ android:pivotX="112"
+ android:pivotY="112"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusInfo"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillType="nonZero"
+ android:pathData=" M22.2 25.82 C22.2,25.82 19.84,28.17 19.84,28.17 C19.84,28.17 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 22.15,25.8 22.15,25.8 C22.15,25.8 22.22,25.82 22.22,25.82 C22.22,25.82 22.2,25.82 22.2,25.82c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/status_scanning_end_anim_info_to_recommend.xml b/PermissionController/res/drawable-v34/status_scanning_end_anim_info_to_recommend.xml
new file mode 100644
index 000000000..3a55c83ec
--- /dev/null
+++ b/PermissionController/res/drawable-v34/status_scanning_end_anim_info_to_recommend.xml
@@ -0,0 +1,469 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_3_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="517"
+ android:propertyName="scaleX"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="517"
+ android:propertyName="scaleY"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="?attr/colorScStatusInfo"
+ android:valueTo="?attr/colorScStatusInfo"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillColor"
+ android:startOffset="150"
+ android:valueFrom="?attr/colorScStatusInfo"
+ android:valueTo="?attr/colorScStatusRecommend"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="283"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M28.04 33.99 C28.04,33.99 28,33.98 28,33.98 C28,33.98 28.01,33.97 28.01,33.97 C28.01,33.97 28.02,33.98 28.02,33.98 C28.02,33.98 28.04,33.99 28.04,33.99c "
+ android:valueTo="M25.92 36.4 C25.92,36.4 25.92,31.89 25.92,31.89 C25.92,31.89 30.09,31.89 30.09,31.89 C30.09,31.89 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_3_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="167"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueTo="M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="pathData"
+ android:startOffset="167"
+ android:valueFrom="M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueTo="M25.92 28.4 C25.92,28.4 25.92,18.4 25.92,18.4 C25.92,18.4 30.09,18.4 30.09,18.4 C30.09,18.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="100"
+ android:pathData="M 0,0C 0,1.553 0,9.32 0,9.32"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="317"
+ android:pathData="M 0,9.32C 0,9.32 0,1.553 0,0"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="100">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_3_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="783"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="224dp"
+ android:height="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_3_G"
+ android:pivotX="112"
+ android:pivotY="112"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusBackgroundRecommend"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_2_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusInfo"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G_N_3_T_0"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="112"
+ android:translateY="112">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="@color/sc_shield_accent_fixed_variant"
+ android:fillType="nonZero"
+ android:pathData=" M28.04 33.99 C28.04,33.99 28,33.98 28,33.98 C28,33.98 28.01,33.97 28.01,33.97 C28.01,33.97 28.02,33.98 28.02,33.98 C28.02,33.98 28.04,33.99 28.04,33.99c " />
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G_N_3_T_0"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="112"
+ android:translateY="112">
+ <group
+ android:name="_R_G_L_0_G_T_1"
+ android:translateX="0"
+ android:translateY="0">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="@color/sc_shield_accent_fixed_variant"
+ android:fillType="nonZero"
+ android:pathData=" M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c " />
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/status_scanning_end_anim_info_to_warn.xml b/PermissionController/res/drawable-v34/status_scanning_end_anim_info_to_warn.xml
new file mode 100644
index 000000000..8c42eed50
--- /dev/null
+++ b/PermissionController/res/drawable-v34/status_scanning_end_anim_info_to_warn.xml
@@ -0,0 +1,469 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_3_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="517"
+ android:propertyName="scaleX"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="517"
+ android:propertyName="scaleY"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="?attr/colorScStatusInfo"
+ android:valueTo="?attr/colorScStatusInfo"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillColor"
+ android:startOffset="150"
+ android:valueFrom="?attr/colorScStatusInfo"
+ android:valueTo="?attr/colorScStatusWarn"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="283"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M28.04 33.99 C28.04,33.99 28,33.98 28,33.98 C28,33.98 28.01,33.97 28.01,33.97 C28.01,33.97 28.02,33.98 28.02,33.98 C28.02,33.98 28.04,33.99 28.04,33.99c "
+ android:valueTo="M25.92 36.4 C25.92,36.4 25.92,31.89 25.92,31.89 C25.92,31.89 30.09,31.89 30.09,31.89 C30.09,31.89 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_3_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="167"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueTo="M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="pathData"
+ android:startOffset="167"
+ android:valueFrom="M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueTo="M25.92 28.4 C25.92,28.4 25.92,18.4 25.92,18.4 C25.92,18.4 30.09,18.4 30.09,18.4 C30.09,18.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="100"
+ android:pathData="M 0,0C 0,1.553 0,9.32 0,9.32"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="317"
+ android:pathData="M 0,9.32C 0,9.32 0,1.553 0,0"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="100">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_3_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="783"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="224dp"
+ android:height="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_3_G"
+ android:pivotX="112"
+ android:pivotY="112"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusBackgroundWarn"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_2_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusInfo"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G_N_3_T_0"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="112"
+ android:translateY="112">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillType="nonZero"
+ android:pathData=" M28.04 33.99 C28.04,33.99 28,33.98 28,33.98 C28,33.98 28.01,33.97 28.01,33.97 C28.01,33.97 28.02,33.98 28.02,33.98 C28.02,33.98 28.04,33.99 28.04,33.99c " />
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G_N_3_T_0"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="112"
+ android:translateY="112">
+ <group
+ android:name="_R_G_L_0_G_T_1"
+ android:translateX="0"
+ android:translateY="0">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillType="nonZero"
+ android:pathData=" M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c " />
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/status_scanning_end_anim_recommend_to_info.xml b/PermissionController/res/drawable-v34/status_scanning_end_anim_recommend_to_info.xml
new file mode 100644
index 000000000..859c51995
--- /dev/null
+++ b/PermissionController/res/drawable-v34/status_scanning_end_anim_recommend_to_info.xml
@@ -0,0 +1,293 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="517"
+ android:propertyName="scaleX"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="517"
+ android:propertyName="scaleY"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="?attr/colorScStatusRecommend"
+ android:valueTo="?attr/colorScStatusRecommend"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillColor"
+ android:startOffset="150"
+ android:valueFrom="?attr/colorScStatusRecommend"
+ android:valueTo="?attr/colorScStatusInfo"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M22.2 25.82 C22.2,25.82 19.84,28.17 19.84,28.17 C19.84,28.17 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 22.15,25.8 22.15,25.8 C22.15,25.8 22.22,25.82 22.22,25.82 C22.22,25.82 22.2,25.82 22.2,25.82c "
+ android:valueTo="M27.89 31.53 C27.89,31.53 25.5,33.81 25.5,33.81 C25.5,33.81 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 25.5,29.13 25.5,29.13 C25.5,29.13 25.54,29.17 25.54,29.17 C25.54,29.17 27.89,31.53 27.89,31.53c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="pathData"
+ android:startOffset="50"
+ android:valueFrom="M27.89 31.53 C27.89,31.53 25.5,33.81 25.5,33.81 C25.5,33.81 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 25.5,29.13 25.5,29.13 C25.5,29.13 25.54,29.17 25.54,29.17 C25.54,29.17 27.89,31.53 27.89,31.53c "
+ android:valueTo="M36.17 23.26 C36.17,23.26 25.5,33.81 25.5,33.81 C25.5,33.81 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 25.5,29.13 25.5,29.13 C25.5,29.13 33.83,20.89 33.83,20.89 C33.83,20.89 36.17,23.26 36.17,23.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.29,0 0.739,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="767"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="224dp"
+ android:height="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_2_G"
+ android:pivotX="112"
+ android:pivotY="112"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusRecommend"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillType="nonZero"
+ android:pathData=" M22.2 25.82 C22.2,25.82 19.84,28.17 19.84,28.17 C19.84,28.17 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 22.15,25.8 22.15,25.8 C22.15,25.8 22.22,25.82 22.22,25.82 C22.22,25.82 22.2,25.82 22.2,25.82c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/status_scanning_end_anim_recommend_to_recommend.xml b/PermissionController/res/drawable-v34/status_scanning_end_anim_recommend_to_recommend.xml
new file mode 100644
index 000000000..f6a8583c1
--- /dev/null
+++ b/PermissionController/res/drawable-v34/status_scanning_end_anim_recommend_to_recommend.xml
@@ -0,0 +1,458 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_3_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="517"
+ android:propertyName="scaleX"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="517"
+ android:propertyName="scaleY"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="317"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="?attr/colorScStatusRecommend"
+ android:valueTo="?attr/colorScStatusRecommend"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="167"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueTo="M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="pathData"
+ android:startOffset="167"
+ android:valueFrom="M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueTo="M25.92 28.4 C25.92,28.4 25.92,18.4 25.92,18.4 C25.92,18.4 30.09,18.4 30.09,18.4 C30.09,18.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="100"
+ android:pathData="M 0,0C 0,1.553 0,9.32 0,9.32"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="317"
+ android:pathData="M 0,9.32C 0,9.32 0,1.553 0,0"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="100">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_6_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="283"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M28.04 33.99 C28.04,33.99 28,33.98 28,33.98 C28,33.98 28.01,33.97 28.01,33.97 C28.01,33.97 28.02,33.98 28.02,33.98 C28.02,33.98 28.04,33.99 28.04,33.99c "
+ android:valueTo="M25.92 36.4 C25.92,36.4 25.92,31.89 25.92,31.89 C25.92,31.89 30.09,31.89 30.09,31.89 C30.09,31.89 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_3_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="767"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="224dp"
+ android:height="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_3_G"
+ android:pivotX="112"
+ android:pivotY="112"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusBackgroundRecommend"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_2_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusRecommend"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G_N_6_T_0"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="112"
+ android:translateY="112">
+ <group
+ android:name="_R_G_L_1_G_T_1"
+ android:translateX="0"
+ android:translateY="0">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="@color/sc_shield_accent_fixed_variant"
+ android:fillType="nonZero"
+ android:pathData=" M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c " />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G_N_3_T_0"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="112"
+ android:translateY="112">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="@color/sc_shield_accent_fixed_variant"
+ android:fillType="nonZero"
+ android:pathData=" M28.04 33.99 C28.04,33.99 28,33.98 28,33.98 C28,33.98 28.01,33.97 28.01,33.97 C28.01,33.97 28.02,33.98 28.02,33.98 C28.02,33.98 28.04,33.99 28.04,33.99c " />
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/status_scanning_end_anim_recommend_to_warn.xml b/PermissionController/res/drawable-v34/status_scanning_end_anim_recommend_to_warn.xml
new file mode 100644
index 000000000..59ef6b3c9
--- /dev/null
+++ b/PermissionController/res/drawable-v34/status_scanning_end_anim_recommend_to_warn.xml
@@ -0,0 +1,532 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="224dp"
+ android:width="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_4_G"
+ android:pivotX="112"
+ android:pivotY="112"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_4_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundWarn"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_3_G"
+ android:pivotX="112"
+ android:pivotY="112"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundWarn"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_2_G"
+ android:translateX="84"
+ android:translateY="84"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusRecommend"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G_N_3_T_0"
+ android:translateX="112"
+ android:translateY="112"
+ android:scaleX="4"
+ android:scaleY="4">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M28.04 33.99 C28.04,33.99 28,33.98 28,33.98 C28,33.98 28.01,33.97 28.01,33.97 C28.01,33.97 28.02,33.98 28.02,33.98 C28.02,33.98 28.04,33.99 28.04,33.99c " />
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G_N_3_T_0"
+ android:translateX="112"
+ android:translateY="112"
+ android:scaleX="4"
+ android:scaleY="4">
+ <group
+ android:name="_R_G_L_0_G_T_1"
+ android:translateX="0"
+ android:translateY="0">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillAlpha="0"
+ android:fillType="nonZero"
+ android:pathData=" M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c " />
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_4_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="250"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="250"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="517"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="517"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="250"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="250"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="517"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="517"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="fillColor"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="?attr/colorScStatusRecommend"
+ android:valueTo="?attr/colorScStatusRecommend"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="fillColor"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="?attr/colorScStatusRecommend"
+ android:valueTo="?attr/colorScStatusWarn"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="283"
+ android:startOffset="0"
+ android:valueFrom="M28.04 33.99 C28.04,33.99 28,33.98 28,33.98 C28,33.98 28.01,33.97 28.01,33.97 C28.01,33.97 28.02,33.98 28.02,33.98 C28.02,33.98 28.04,33.99 28.04,33.99c "
+ android:valueTo="M25.92 36.4 C25.92,36.4 25.92,31.89 25.92,31.89 C25.92,31.89 30.09,31.89 30.09,31.89 C30.09,31.89 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_3_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="fillAlpha"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="fillAlpha"
+ android:duration="17"
+ android:startOffset="167"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueTo="M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="250"
+ android:startOffset="167"
+ android:valueFrom="M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueTo="M25.92 28.4 C25.92,28.4 25.92,18.4 25.92,18.4 C25.92,18.4 30.09,18.4 30.09,18.4 C30.09,18.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateXY"
+ android:duration="100"
+ android:startOffset="0"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 0,0C 0,1.553 0,9.32 0,9.32">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="translateXY"
+ android:duration="317"
+ android:startOffset="100"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 0,9.32C 0,9.32 0,1.553 0,0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_3_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="783"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/status_scanning_end_anim_warn_to_info.xml b/PermissionController/res/drawable-v34/status_scanning_end_anim_warn_to_info.xml
new file mode 100644
index 000000000..07a38ea51
--- /dev/null
+++ b/PermissionController/res/drawable-v34/status_scanning_end_anim_warn_to_info.xml
@@ -0,0 +1,293 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="224dp"
+ android:width="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_2_G"
+ android:pivotX="112"
+ android:pivotY="112"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundInfo"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="84"
+ android:translateY="84"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusWarn"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="84"
+ android:translateY="84"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillAlpha="0"
+ android:fillType="nonZero"
+ android:pathData=" M22.2 25.82 C22.2,25.82 19.84,28.17 19.84,28.17 C19.84,28.17 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 22.15,25.8 22.15,25.8 C22.15,25.8 22.22,25.82 22.22,25.82 C22.22,25.82 22.2,25.82 22.2,25.82c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="250"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="250"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="517"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="517"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="fillColor"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="?attr/colorScStatusWarn"
+ android:valueTo="?attr/colorScStatusWarn"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="fillColor"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="?attr/colorScStatusWarn"
+ android:valueTo="?attr/colorScStatusInfo"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="fillAlpha"
+ android:duration="17"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="50"
+ android:startOffset="0"
+ android:valueFrom="M22.2 25.82 C22.2,25.82 19.84,28.17 19.84,28.17 C19.84,28.17 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 22.15,25.8 22.15,25.8 C22.15,25.8 22.22,25.82 22.22,25.82 C22.22,25.82 22.2,25.82 22.2,25.82c "
+ android:valueTo="M27.89 31.53 C27.89,31.53 25.5,33.81 25.5,33.81 C25.5,33.81 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 25.5,29.13 25.5,29.13 C25.5,29.13 25.54,29.17 25.54,29.17 C25.54,29.17 27.89,31.53 27.89,31.53c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="167"
+ android:startOffset="50"
+ android:valueFrom="M27.89 31.53 C27.89,31.53 25.5,33.81 25.5,33.81 C25.5,33.81 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 25.5,29.13 25.5,29.13 C25.5,29.13 25.54,29.17 25.54,29.17 C25.54,29.17 27.89,31.53 27.89,31.53c "
+ android:valueTo="M36.17 23.26 C36.17,23.26 25.5,33.81 25.5,33.81 C25.5,33.81 19.83,28.2 19.83,28.2 C19.83,28.2 22.17,25.83 22.17,25.83 C22.17,25.83 25.5,29.13 25.5,29.13 C25.5,29.13 33.83,20.89 33.83,20.89 C33.83,20.89 36.17,23.26 36.17,23.26c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.29,0 0.739,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="767"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/status_scanning_end_anim_warn_to_recommend.xml b/PermissionController/res/drawable-v34/status_scanning_end_anim_warn_to_recommend.xml
new file mode 100644
index 000000000..3f06af41e
--- /dev/null
+++ b/PermissionController/res/drawable-v34/status_scanning_end_anim_warn_to_recommend.xml
@@ -0,0 +1,469 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:height="224dp"
+ android:width="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_3_G"
+ android:pivotX="112"
+ android:pivotY="112"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusBackgroundRecommend"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_2_G"
+ android:translateX="84"
+ android:translateY="84"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="?attr/colorScStatusWarn"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G_N_3_T_0"
+ android:translateX="112"
+ android:translateY="112"
+ android:scaleX="4"
+ android:scaleY="4">
+ <group
+ android:name="_R_G_L_1_G_T_1"
+ android:translateX="0"
+ android:translateY="0">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="@color/sc_shield_accent_fixed_variant"
+ android:fillAlpha="0"
+ android:fillType="nonZero"
+ android:pathData=" M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c " />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G_N_3_T_0"
+ android:translateX="112"
+ android:translateY="112"
+ android:scaleX="4"
+ android:scaleY="4">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="@color/sc_shield_accent_fixed_variant"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M28.04 33.99 C28.04,33.99 28,33.98 28,33.98 C28,33.98 28.01,33.97 28.01,33.97 C28.01,33.97 28.02,33.98 28.02,33.98 C28.02,33.98 28.04,33.99 28.04,33.99c " />
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_3_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="250"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="250"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="517"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="517"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="fillColor"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="?attr/colorScStatusWarn"
+ android:valueTo="?attr/colorScStatusWarn"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="fillColor"
+ android:duration="167"
+ android:startOffset="150"
+ android:valueFrom="?attr/colorScStatusWarn"
+ android:valueTo="?attr/colorScStatusRecommend"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="fillAlpha"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="fillAlpha"
+ android:duration="17"
+ android:startOffset="167"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="167"
+ android:startOffset="0"
+ android:valueFrom="M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueTo="M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="250"
+ android:startOffset="167"
+ android:valueFrom="M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueTo="M25.92 28.4 C25.92,28.4 25.92,18.4 25.92,18.4 C25.92,18.4 30.09,18.4 30.09,18.4 C30.09,18.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateXY"
+ android:duration="100"
+ android:startOffset="0"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 0,0C 0,1.553 0,9.32 0,9.32">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="translateXY"
+ android:duration="317"
+ android:startOffset="100"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:pathData="M 0,9.32C 0,9.32 0,1.553 0,0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_3_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="pathData"
+ android:duration="283"
+ android:startOffset="0"
+ android:valueFrom="M28.04 33.99 C28.04,33.99 28,33.98 28,33.98 C28,33.98 28.01,33.97 28.01,33.97 C28.01,33.97 28.02,33.98 28.02,33.98 C28.02,33.98 28.04,33.99 28.04,33.99c "
+ android:valueTo="M25.92 36.4 C25.92,36.4 25.92,31.89 25.92,31.89 C25.92,31.89 30.09,31.89 30.09,31.89 C30.09,31.89 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_3_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="150"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="450"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="167"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="167"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:propertyName="translateX"
+ android:duration="783"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/status_scanning_end_anim_warn_to_warn.xml b/PermissionController/res/drawable-v34/status_scanning_end_anim_warn_to_warn.xml
new file mode 100644
index 000000000..452e7f051
--- /dev/null
+++ b/PermissionController/res/drawable-v34/status_scanning_end_anim_warn_to_warn.xml
@@ -0,0 +1,441 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_3_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="517"
+ android:propertyName="scaleX"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="517"
+ android:propertyName="scaleY"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.049,0.562 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.01,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="283"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M28.04 33.99 C28.04,33.99 28,33.98 28,33.98 C28,33.98 28.01,33.97 28.01,33.97 C28.01,33.97 28.02,33.98 28.02,33.98 C28.02,33.98 28.04,33.99 28.04,33.99c "
+ android:valueTo="M25.92 36.4 C25.92,36.4 25.92,31.89 25.92,31.89 C25.92,31.89 30.09,31.89 30.09,31.89 C30.09,31.89 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_3_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="167"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueTo="M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="pathData"
+ android:startOffset="167"
+ android:valueFrom="M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueTo="M25.92 28.4 C25.92,28.4 25.92,18.4 25.92,18.4 C25.92,18.4 30.09,18.4 30.09,18.4 C30.09,18.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="100"
+ android:pathData="M 0,0C 0,1.553 0,9.32 0,9.32"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="317"
+ android:pathData="M 0,9.32C 0,9.32 0,1.553 0,0"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="100">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_3_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="4"
+ android:valueTo="3.6"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleX"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="scaleY"
+ android:startOffset="150"
+ android:valueFrom="3.6"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="600"
+ android:valueFrom="4"
+ android:valueTo="4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="783"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="224dp"
+ android:height="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_3_G"
+ android:pivotX="112"
+ android:pivotY="112"
+ android:scaleX="0"
+ android:scaleY="0">
+ <path
+ android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusBackgroundWarn"
+ android:fillType="nonZero"
+ android:pathData=" M112 0 C112,0 112,0 112,0 C173.86,0 224,50.14 224,112 C224,112 224,112 224,112 C224,173.86 173.86,224 112,224 C112,224 112,224 112,224 C50.14,224 0,173.86 0,112 C0,112 0,112 0,112 C0,50.14 50.14,0 112,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_2_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusWarn"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G_N_3_T_0"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="112"
+ android:translateY="112">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillType="nonZero"
+ android:pathData=" M28.04 33.99 C28.04,33.99 28,33.98 28,33.98 C28,33.98 28.01,33.97 28.01,33.97 C28.01,33.97 28.02,33.98 28.02,33.98 C28.02,33.98 28.04,33.99 28.04,33.99c " />
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G_N_3_T_0"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="112"
+ android:translateY="112">
+ <group
+ android:name="_R_G_L_0_G_T_1"
+ android:translateX="0"
+ android:translateY="0">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillType="nonZero"
+ android:pathData=" M25.92 28.4 C25.92,28.4 25.92,28.4 25.92,28.4 C25.92,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c " />
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable-v34/status_warn_to_scanning_anim.xml b/PermissionController/res/drawable-v34/status_warn_to_scanning_anim.xml
new file mode 100644
index 000000000..e45618632
--- /dev/null
+++ b/PermissionController/res/drawable-v34/status_warn_to_scanning_anim.xml
@@ -0,0 +1,225 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_3_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="333"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="150"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M25.92 28.4 C25.92,28.4 25.92,18.4 25.92,18.4 C25.92,18.4 30.09,18.4 30.09,18.4 C30.09,18.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueTo="M25.92 28.4 C25.92,28.4 25.89,28.4 25.89,28.4 C25.89,28.4 30.06,28.4 30.06,28.4 C30.06,28.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.18,0 0.043,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="117"
+ android:pathData="M 112,112C 112,117.19200000000001 112,137.958 112,143.15"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="133"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="133"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="133"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M25.92 36.4 C25.92,36.4 25.92,31.89 25.92,31.89 C25.92,31.89 30.09,31.89 30.09,31.89 C30.09,31.89 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c "
+ android:valueTo="M25.92 36.4 C25.92,36.4 25.94,36.39 25.94,36.39 C25.94,36.39 30.11,36.39 30.11,36.39 C30.11,36.39 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.989,0 0.789,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="350"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="224dp"
+ android:height="224dp"
+ android:viewportHeight="224"
+ android:viewportWidth="224">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_3_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusBackgroundWarn"
+ android:fillType="nonZero"
+ android:pathData=" M28 0 C28,0 28,0 28,0 C43.46,0 56,12.54 56,28 C56,28 56,28 56,28 C56,43.46 43.46,56 28,56 C28,56 28,56 28,56 C12.54,56 0,43.46 0,28 C0,28 0,28 0,28 C0,12.54 12.54,0 28,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_2_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScStatusWarn"
+ android:fillType="nonZero"
+ android:pathData=" M14.5 25.14 C14.53,26.4 14.62,27.66 14.79,28.91 C15.59,34.32 18.62,40.45 26.93,44.74 C27.26,44.91 27.63,45 28,45 C28.37,45 28.74,44.91 29.07,44.74 C37.38,40.45 40.41,34.32 41.21,28.91 C41.38,27.66 41.48,26.4 41.5,25.14 C41.5,25.14 41.5,17.67 41.5,17.67 C41.5,17.1 41.33,16.54 41,16.07 C40.67,15.61 40.21,15.25 39.67,15.06 C39.67,15.06 28.95,11.17 28.95,11.17 C28.34,10.94 27.67,10.94 27.05,11.17 C27.05,11.17 16.33,15.06 16.33,15.06 C15.79,15.25 15.33,15.61 15,16.07 C14.68,16.54 14.5,17.1 14.5,17.67 C14.5,17.67 14.5,25.14 14.5,25.14c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G_T_1"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="112"
+ android:translateY="112">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="-28"
+ android:translateY="-28">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillType="nonZero"
+ android:pathData=" M25.92 28.4 C25.92,28.4 25.92,18.4 25.92,18.4 C25.92,18.4 30.09,18.4 30.09,18.4 C30.09,18.4 30.09,28.4 30.09,28.4 C30.09,28.4 25.92,28.4 25.92,28.4c " />
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="28"
+ android:pivotY="28"
+ android:scaleX="4"
+ android:scaleY="4"
+ android:translateX="84"
+ android:translateY="84">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?attr/colorScShieldAccent"
+ android:fillType="nonZero"
+ android:pathData=" M25.92 36.4 C25.92,36.4 25.92,31.89 25.92,31.89 C25.92,31.89 30.09,31.89 30.09,31.89 C30.09,31.89 30.09,36.4 30.09,36.4 C30.09,36.4 25.92,36.4 25.92,36.4c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable/coarse_off_dark.gif b/PermissionController/res/drawable/coarse_off_dark.gif
deleted file mode 100644
index 09a7da18d..000000000
--- a/PermissionController/res/drawable/coarse_off_dark.gif
+++ /dev/null
Binary files differ
diff --git a/PermissionController/res/drawable/coarse_off_light.gif b/PermissionController/res/drawable/coarse_off_light.gif
deleted file mode 100644
index a5419cd91..000000000
--- a/PermissionController/res/drawable/coarse_off_light.gif
+++ /dev/null
Binary files differ
diff --git a/PermissionController/res/drawable/coarse_on_dark.gif b/PermissionController/res/drawable/coarse_on_dark.gif
deleted file mode 100644
index a2ea07bd0..000000000
--- a/PermissionController/res/drawable/coarse_on_dark.gif
+++ /dev/null
Binary files differ
diff --git a/PermissionController/res/drawable/coarse_on_light.gif b/PermissionController/res/drawable/coarse_on_light.gif
deleted file mode 100644
index 491edb612..000000000
--- a/PermissionController/res/drawable/coarse_on_light.gif
+++ /dev/null
Binary files differ
diff --git a/PermissionController/res/drawable/fine_off_dark.gif b/PermissionController/res/drawable/fine_off_dark.gif
deleted file mode 100644
index 560e38a34..000000000
--- a/PermissionController/res/drawable/fine_off_dark.gif
+++ /dev/null
Binary files differ
diff --git a/PermissionController/res/drawable/fine_off_light.gif b/PermissionController/res/drawable/fine_off_light.gif
deleted file mode 100644
index 5661b9270..000000000
--- a/PermissionController/res/drawable/fine_off_light.gif
+++ /dev/null
Binary files differ
diff --git a/PermissionController/res/drawable/fine_on_dark.gif b/PermissionController/res/drawable/fine_on_dark.gif
deleted file mode 100644
index aadf7821b..000000000
--- a/PermissionController/res/drawable/fine_on_dark.gif
+++ /dev/null
Binary files differ
diff --git a/PermissionController/res/drawable/fine_on_light.gif b/PermissionController/res/drawable/fine_on_light.gif
deleted file mode 100644
index a592c6305..000000000
--- a/PermissionController/res/drawable/fine_on_light.gif
+++ /dev/null
Binary files differ
diff --git a/PermissionController/res/drawable-v31/ic_safety_warn_outline.xml b/PermissionController/res/drawable/forward_arrow.xml
index a97eba073..f1564f075 100644
--- a/PermissionController/res/drawable-v31/ic_safety_warn_outline.xml
+++ b/PermissionController/res/drawable/forward_arrow.xml
@@ -1,5 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2021 The Android Open Source Project
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -15,12 +15,11 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:pathData="M1,21L12,2L23,21H1ZM19.53,19L12,5.99L4.47,19H19.53ZM11,16V18H13V16H11ZM11,10H13V14H11V10Z"
- android:fillColor="@color/safety_center_warn"
- android:fillType="evenOdd"/>
+ android:width="12dp"
+ android:height="20dp"
+ android:viewportWidth="12.0"
+ android:viewportHeight="20.0"
+ android:tint="?android:attr/textColorPrimaryInverse">
+ <path android:pathData="M0.589966 14.59L1.99997 16L9.99997 8L1.99997 0L0.589966 1.41L7.16997 8"
+ android:fillColor="?android:attr/textColorPrimaryInverse"/>
</vector>
diff --git a/PermissionController/res/drawable-v31/indicator_background_circle.xml b/PermissionController/res/drawable/grant_dialog_permission_rationale_background.xml
index 357d11ab1..6393742aa 100644
--- a/PermissionController/res/drawable-v31/indicator_background_circle.xml
+++ b/PermissionController/res/drawable/grant_dialog_permission_rationale_background.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
@@ -15,11 +16,7 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval"
- android:id="@id/background"
- android:gravity="center">
- <size
- android:height="@dimen/ongoing_appops_dialog_circle_size"
- android:width="@dimen/ongoing_appops_dialog_circle_size"/>
- <solid android:color="@android:color/white" />
+ android:shape="rectangle">
+ <corners android:radius="16dp"/>
+ <stroke android:width="1dp" android:color="@color/permission_rationale_overview_background" />
</shape> \ No newline at end of file
diff --git a/PermissionController/res/drawable/ic_more_info_arrow.xml b/PermissionController/res/drawable/ic_more_info_arrow.xml
new file mode 100644
index 000000000..73eb5ccfc
--- /dev/null
+++ b/PermissionController/res/drawable/ic_more_info_arrow.xml
@@ -0,0 +1,23 @@
+<?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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="48dp"
+ android:height="48dp" android:viewportWidth="48" android:viewportHeight="48"
+ android:autoMirrored="true" android:tint="?attr/colorControlNormal">
+ <path android:fillColor="@android:color/white"
+ android:pathData="M18.75,36 L16.6,33.85 26.5,23.95 16.6,14.05 18.75,11.9 30.8,23.95Z"/>
+</vector> \ No newline at end of file
diff --git a/PermissionController/res/drawable/ic_settings_notification.xml b/PermissionController/res/drawable/ic_settings_notification.xml
new file mode 100644
index 000000000..3256dd2dd
--- /dev/null
+++ b/PermissionController/res/drawable/ic_settings_notification.xml
@@ -0,0 +1,92 @@
+<?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.
+ -->
+
+<vector android:width="24dp" android:height="24dp"
+ android:viewportWidth="24" android:viewportHeight="24"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:pathData="
+ M22.45 11.94
+ l-.58-.21
+ a1.19 1.19 0 0 1-.26-2.12
+ l.51-.34
+ a1.2 1.2 0 0 0-.83-2.19
+ l-.61.08
+ a1.2 1.2 0 0 1-1.21-1.76
+ l.29-.54
+ A1.2 1.2 0 0 0 18 3.31
+ l-.5.36
+ a1.21 1.21 0 0 1-1.9-1
+ v-.61
+ a1.2 1.2 0 0 0-2.27-.56
+ l-.26.5
+ a1.2 1.2 0 0 1-2.14 0
+ l-.28-.54
+ a1.2 1.2 0 0 0-2.27.56
+ v.61
+ a1.21 1.21 0 0 1-1.9 1
+ L6 3.31
+ a1.2 1.2 0 0 0-1.76 1.55
+ l.29.54
+ a1.2 1.2 0 0 1-1.21 1.76
+ l-.61-.08
+ a1.2 1.2 0 0 0-.83 2.19
+ l.51.34
+ a1.19 1.19 0 0 1-.26 2.12
+ l-.58.21
+ a1.21 1.21 0 0 0 .29 2.33
+ l.61.06
+ a1.2 1.2 0 0 1 .76 2
+ l-.42.46
+ a1.2 1.2 0 0 0 1.33 1.92
+ l.57-.22
+ a1.21 1.21 0 0 1 1.61 1.42
+ l-.16.59
+ a1.2 1.2 0 0 0 2.07 1.09
+ l.4-.47
+ a1.2 1.2 0 0 1 2.08.51
+ l.14.6
+ a1.2 1.2 0 0 0 2.34 0
+ l.14-.6
+ a1.2 1.2 0 0 1 2.08-.51
+ l.4.47
+ a1.2 1.2 0 0 0 2.07-1.09
+ l-.16-.59
+ a1.21 1.21 0 0 1 1.61-1.42
+ l.57.22
+ a1.2 1.2 0 0 0 1.33-1.92
+ l-.42-.46
+ a1.2 1.2 0 0 1 .76-2
+ l.61-.06
+ a1.21 1.21 0 0 0 .29-2.33
+ z
+ M12 19
+ a7 7 0 1 1 7-7 7 7 0 0 1-7 7
+ z
+ "
+ android:fillColor="#000000" />
+ <path android:pathData="
+ M9 7.75
+ a.75.75 0 1 0 0 1.5.75.75 0 1 0 0-1.5
+ z
+ M15 7.75
+ a.75.75 0 1 0 0 1.5.75.75 0 1 0 0-1.5
+ z
+ "
+ android:fillColor="#000000" />
+ <path android:strokeColor="#000000" android:strokeMiterLimit="10" android:strokeWidth="2"
+ android:pathData="M4 12h16M12 12v8" />
+</vector>
+
diff --git a/PermissionController/res/drawable/ic_shield_exclamation_outline.xml b/PermissionController/res/drawable/ic_shield_exclamation_outline.xml
new file mode 100644
index 000000000..5785babf9
--- /dev/null
+++ b/PermissionController/res/drawable/ic_shield_exclamation_outline.xml
@@ -0,0 +1,23 @@
+<?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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="48dp"
+ android:height="48dp" android:viewportWidth="48" android:viewportHeight="48"
+ android:tint="?attr/colorControlNormal">
+ <path android:fillColor="@android:color/white"
+ android:pathData="M24,31.3Q24.7,31.3 25.2,30.8Q25.7,30.3 25.7,29.6Q25.7,28.9 25.2,28.4Q24.7,27.9 24,27.9Q23.3,27.9 22.8,28.4Q22.3,28.9 22.3,29.6Q22.3,30.3 22.8,30.8Q23.3,31.3 24,31.3ZM22.5,24.6H25.5V14.25H22.5ZM24,43.95Q17,42.2 12.5,35.825Q8,29.45 8,21.85V9.95L24,3.95L40,9.95V21.85Q40,29.45 35.5,35.825Q31,42.2 24,43.95ZM24,40.85Q29.75,38.95 33.375,33.675Q37,28.4 37,21.85V12.05L24,7.15L11,12.05V21.85Q11,28.4 14.625,33.675Q18.25,38.95 24,40.85ZM24,24Q24,24 24,24Q24,24 24,24Q24,24 24,24Q24,24 24,24Z"/>
+</vector>
diff --git a/PermissionController/res/drawable/settings_gear.xml b/PermissionController/res/drawable/settings_gear.xml
new file mode 100644
index 000000000..86b418deb
--- /dev/null
+++ b/PermissionController/res/drawable/settings_gear.xml
@@ -0,0 +1,27 @@
+<!--
+ ~ 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20.0"
+ android:viewportHeight="20.0"
+ android:tint="?android:attr/textColorPrimaryInverse">
+ <path
+ android:pathData="M11.7583 16.5251C11.675 17.0918 11.1583 17.5418 10.5417 17.5418H7.45832C6.84166 17.5418 6.32499 17.0918 6.24999 16.4835L6.02499 14.9085C5.79999 14.7918 5.58332 14.6668 5.36666 14.5251L3.86666 15.1251C3.28332 15.3418 2.64166 15.1001 2.35833 14.5835L0.833325 11.9418C0.541658 11.3918 0.666658 10.7418 1.13333 10.3751L2.40833 9.38346C2.39999 9.25846 2.39166 9.13346 2.39166 9.00013C2.39166 8.87513 2.39999 8.7418 2.40833 8.6168L1.14166 7.62513C0.649992 7.25013 0.524992 6.57513 0.833325 6.05846L2.37499 3.40013C2.65833 2.88346 3.29999 2.65013 3.86666 2.87513L5.37499 3.48346C5.59166 3.3418 5.80833 3.2168 6.02499 3.10013L6.24999 1.50846C6.32499 0.92513 6.84166 0.466797 7.44999 0.466797H10.5333C11.15 0.466797 11.6667 0.916797 11.7417 1.52513L11.9667 3.10013C12.1917 3.2168 12.4083 3.3418 12.625 3.48346L14.125 2.88346C14.7167 2.6668 15.3583 2.90846 15.6417 3.42513L17.175 6.07513C17.475 6.62513 17.3417 7.27513 16.875 7.6418L15.6083 8.63346C15.6167 8.75846 15.625 8.88346 15.625 9.0168C15.625 9.15013 15.6167 9.27513 15.6083 9.40013L16.875 10.3918C17.3417 10.7668 17.475 11.4168 17.1833 11.9418L15.6333 14.6251C15.35 15.1418 14.7083 15.3751 14.1333 15.1501L12.6333 14.5501C12.4167 14.6918 12.2 14.8168 11.9833 14.9335L11.7583 16.5251ZM7.84999 15.8751H10.15L10.4583 13.7501L10.9 13.5668C11.2667 13.4168 11.6333 13.2001 12.0167 12.9168L12.3917 12.6335L14.375 13.4335L15.525 11.4335L13.8333 10.1168L13.8917 9.65013L13.8942 9.6277C13.9184 9.41905 13.9417 9.21735 13.9417 9.00013C13.9417 8.77513 13.9167 8.55846 13.8917 8.35013L13.8333 7.88346L15.525 6.5668L14.3667 4.5668L12.375 5.3668L12 5.07513C11.65 4.80846 11.275 4.5918 10.8917 4.43346L10.4583 4.25013L10.15 2.12513H7.84999L7.54166 4.25013L7.09999 4.42513C6.73333 4.58346 6.36666 4.7918 5.98332 5.08346L5.60832 5.35846L3.62499 4.5668L2.46666 6.55846L4.15832 7.87513L4.09999 8.3418C4.07499 8.55846 4.04999 8.78346 4.04999 9.00013C4.04999 9.2168 4.06666 9.4418 4.09999 9.65013L4.15832 10.1168L2.46666 11.4335L3.61666 13.4335L5.60832 12.6335L5.98332 12.9251C6.34166 13.2001 6.69999 13.4085 7.09166 13.5668L7.53333 13.7501L7.84999 15.8751ZM11.9167 9.00013C11.9167 10.611 10.6108 11.9168 8.99999 11.9168C7.38916 11.9168 6.08332 10.611 6.08332 9.00013C6.08332 7.3893 7.38916 6.08346 8.99999 6.08346C10.6108 6.08346 11.9167 7.3893 11.9167 9.00013Z"
+ android:fillColor="?android:attr/textColorPrimaryInverse"
+ />
+</vector>
diff --git a/PermissionController/res/layout-television/grant_permissions.xml b/PermissionController/res/layout-television/grant_permissions.xml
index c3ecb7c95..a7712e00e 100644
--- a/PermissionController/res/layout-television/grant_permissions.xml
+++ b/PermissionController/res/layout-television/grant_permissions.xml
@@ -37,7 +37,7 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/action_dialog_content_margin_left"
+ android:layout_marginStart="@dimen/action_dialog_content_margin_left"
android:orientation="vertical">
<TextView
android:id="@+id/current_page_text"
@@ -66,8 +66,8 @@
android:orientation="vertical"
android:layout_width="@dimen/action_dialog_actions_width"
android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/grant_permissions_actions_margin_left"
- android:layout_marginRight="@dimen/grant_permissions_actions_margin_right">
+ android:layout_marginStart="@dimen/grant_permissions_actions_margin_left"
+ android:layout_marginEnd="@dimen/grant_permissions_actions_margin_right">
<Button
android:id="@+id/permission_allow_button"
android:layout_width="match_parent"
diff --git a/PermissionController/res/layout-v31/expand_button_with_large_title.xml b/PermissionController/res/layout-v31/expand_button_with_large_title.xml
index 589a58709..21eef1575 100644
--- a/PermissionController/res/layout-v31/expand_button_with_large_title.xml
+++ b/PermissionController/res/layout-v31/expand_button_with_large_title.xml
@@ -31,7 +31,14 @@
android:clipToPadding="false"
android:baselineAligned="false">
- <include layout="@layout/image_frame"/>
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:maxWidth="24dp"
+ android:maxHeight="24dp"
+ android:paddingEnd="24dp" />
<RelativeLayout
android:layout_width="0dp"
diff --git a/PermissionController/res/layout-v31/preference_issue_card.xml b/PermissionController/res/layout-v31/preference_issue_card.xml
deleted file mode 100644
index 6e1a661cc..000000000
--- a/PermissionController/res/layout-v31/preference_issue_card.xml
+++ /dev/null
@@ -1,77 +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.
- -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/issue_card"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:clickable="false"
- style="@style/SafetyCenter.IssueCard">
-
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- style="@style/SafetyCenter.IssueCard.TopRow">
-
- <ImageView
- android:id="@+id/issue_card_banner_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_alignParentStart="true"
- android:importantForAccessibility="no" />
-
- <ImageButton
- android:id="@+id/issue_card_dismiss_btn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_safety_issue_dismiss"
- android:layout_alignParentEnd="true"
- android:contentDescription="@string/safety_center_issue_card_dismiss_button"
- style="@style/SafetyCenter.IssueCard.Dismiss" />
- </RelativeLayout>
-
- <TextView
- android:id="@+id/issue_card_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/summary_placeholder"
- style="@style/SafetyCenter.IssueCard.Title" />
-
- <TextView
- android:id="@+id/issue_card_subtitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/summary_placeholder"
- style="@style/SafetyCenter.IssueCard.Subtitle" />
-
- <TextView
- android:id="@+id/issue_card_summary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/summary_placeholder"
- style="@style/SafetyCenter.IssueCard.Summary" />
-
- <LinearLayout
- android:id="@+id/issue_card_action_button_list"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- style="@style/SafetyCenter.IssueCard.ActionButtonList" />
-
-</LinearLayout> \ No newline at end of file
diff --git a/PermissionController/res/layout-v31/preference_safety_status.xml b/PermissionController/res/layout-v31/preference_safety_status.xml
deleted file mode 100644
index c86f922f8..000000000
--- a/PermissionController/res/layout-v31/preference_safety_status.xml
+++ /dev/null
@@ -1,56 +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.
- -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:gravity="center"
- android:clickable="false"
- android:paddingTop="5dp"
- android:paddingBottom="12dp">
-
- <ImageView
- android:id="@+id/status_image"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:paddingBottom="22dp"
- android:src="@drawable/safety_status_info" />
-
- <TextView
- android:id="@+id/status_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/summary_placeholder"
- android:textAppearance="@style/TextAppearance.SafetyStatusTitle" />
-
- <TextView
- android:id="@+id/status_summary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingBottom="8dp"
- android:text="@string/summary_placeholder"
- android:textAppearance="@style/TextAppearance.SafetyStatusSummary" />
-
- <Button
- android:id="@+id/rescan_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/safety_center_rescan_button"
- style="@style/SafetyCenter.RescanButton" />
-</LinearLayout> \ No newline at end of file
diff --git a/PermissionController/res/layout-v31/safety_center_toggle_button.xml b/PermissionController/res/layout-v31/safety_center_toggle_button.xml
deleted file mode 100644
index b0b4933e0..000000000
--- a/PermissionController/res/layout-v31/safety_center_toggle_button.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_weight="0.33"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- style="@style/SafetyCenterSensorToggleButton"
- android:id="@+id/safety_center_toggle_button">
- <ImageView
- android:id="@+id/toggle_sensor_icon"
- android:layout_width="wrap_content"
- style="@style/SafetyCenterToggleText"
- android:layout_height="wrap_content"/>
- <TextView
- android:id="@+id/toggle_sensor_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@style/SafetyCenterToggleText"
- android:textColor="?android:textColorPrimaryInverse"/>
- <TextView
- android:id="@+id/toggle_sensor_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@style/SafetyCenterToggleText"
- android:text="@string/available"
- android:textColor="@color/safety_center_secondary"/>
-
-</LinearLayout>
diff --git a/PermissionController/res/layout-v33/action_button_list.xml b/PermissionController/res/layout-v33/action_button_list.xml
new file mode 100644
index 000000000..3217f4c78
--- /dev/null
+++ b/PermissionController/res/layout-v33/action_button_list.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.
+ -->
+
+<LinearLayout
+ 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/indicator_card.xml b/PermissionController/res/layout-v33/indicator_card.xml
new file mode 100644
index 000000000..373792b38
--- /dev/null
+++ b/PermissionController/res/layout-v33/indicator_card.xml
@@ -0,0 +1,79 @@
+<!--
+ ~ 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.
+ -->
+<androidx.cardview.widget.CardView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/parent_card_view"
+ style="@style/SafetyCenterIndicatorCardView">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/full_card"
+ style="@style/SafetyCenterIndicatorForeground">
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/indicator_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/SafetyCenterIndicatorForeground">
+ <ImageView
+ android:id="@+id/indicator_icon"
+ android:importantForAccessibility="no"
+ style="@style/SafetyCenterIndicatorImageView"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent" />
+ <TextView
+ android:id="@+id/indicator_title"
+ app:layout_constraintStart_toEndOf="@id/indicator_icon"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ style="@style/SafetyCenterIndicatorTitleText" />
+ <TextView
+ android:id="@+id/indicator_label"
+ app:layout_constraintTop_toBottomOf="@id/indicator_title"
+ app:layout_constraintStart_toStartOf="@id/indicator_title"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/expand_view"
+ style="@style/SafetyCenterIndicatorLabelText" />
+ <ImageView
+ android:id="@+id/expand_view"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ style="@style/SafetyCenterIndicatorExpandView" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/expanded_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ style="@style/SafetyCenterIndicatorForeground">
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/primary_button"
+ style="@style/SafetyCenterIndicatorActionButton"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent" />
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/secondary_button"
+ app:layout_constraintTop_toBottomOf="@id/primary_button"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ style="@style/SafetyCenterIndicatorSecondaryActionButton" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+ </LinearLayout>
+</androidx.cardview.widget.CardView>
diff --git a/PermissionController/res/layout-v33/preference_category_no_label.xml b/PermissionController/res/layout-v33/preference_category_no_label.xml
new file mode 100644
index 000000000..127d55a53
--- /dev/null
+++ b/PermissionController/res/layout-v33/preference_category_no_label.xml
@@ -0,0 +1,19 @@
+<?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.
+ -->
+<Space xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="0dp" /> \ No newline at end of file
diff --git a/PermissionController/res/layout-v33/preference_entry.xml b/PermissionController/res/layout-v33/preference_entry.xml
new file mode 100644
index 000000000..ebfc89ebe
--- /dev/null
+++ b/PermissionController/res/layout-v33/preference_entry.xml
@@ -0,0 +1,20 @@
+<?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
+ -->
+
+<com.android.permissioncontroller.safetycenter.ui.view.SafetyEntryView
+ style="@style/SafetyCenterEntry" /> \ No newline at end of file
diff --git a/PermissionController/res/layout-v33/preference_entry_icon_action_gear_widget.xml b/PermissionController/res/layout-v33/preference_entry_icon_action_gear_widget.xml
new file mode 100644
index 000000000..ca77206a8
--- /dev/null
+++ b/PermissionController/res/layout-v33/preference_entry_icon_action_gear_widget.xml
@@ -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.
+ -->
+
+<ImageButton
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/icon_action_button"
+ android:src="@drawable/ic_settings_gear"
+ android:contentDescription="@string/safety_center_gear_label"
+ style="@style/SafetyCenterEntryIconAction"/>
diff --git a/PermissionController/res/layout-v33/preference_entry_icon_action_info_widget.xml b/PermissionController/res/layout-v33/preference_entry_icon_action_info_widget.xml
new file mode 100644
index 000000000..909b64826
--- /dev/null
+++ b/PermissionController/res/layout-v33/preference_entry_icon_action_info_widget.xml
@@ -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.
+ -->
+
+<ImageButton
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/icon_action_button"
+ android:src="@drawable/ic_settings_info"
+ android:contentDescription="@string/safety_center_info_label"
+ style="@style/SafetyCenterEntryIconAction"/>
diff --git a/PermissionController/res/layout-v33/preference_group.xml b/PermissionController/res/layout-v33/preference_group.xml
new file mode 100644
index 000000000..e0a804e63
--- /dev/null
+++ b/PermissionController/res/layout-v33/preference_group.xml
@@ -0,0 +1,20 @@
+<?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
+ -->
+
+<com.android.permissioncontroller.safetycenter.ui.view.SafetyEntryGroupView
+ style="@style/SafetyCenterGroup" /> \ 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
new file mode 100644
index 000000000..571efae3b
--- /dev/null
+++ b/PermissionController/res/layout-v33/preference_issue_card.xml
@@ -0,0 +1,93 @@
+<!--
+ ~ 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.
+ -->
+
+<androidx.constraintlayout.widget.ConstraintLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/issue_card"
+ android:clickable="false"
+ android:screenReaderFocusable="true"
+ style="@style/SafetyCenterCard.Issue">
+
+ <ImageButton
+ android:id="@+id/issue_card_dismiss_btn"
+ android:src="@drawable/ic_safety_issue_dismiss"
+ android:contentDescription="@string/safety_center_issue_card_dismiss_button"
+ style="@style/SafetyCenterIssueDismiss" />
+
+ <TextView
+ android:id="@+id/issue_card_attribution_title"
+ android:text="@string/summary_placeholder"
+ android:screenReaderFocusable="false"
+ style="@style/SafetyCenterIssueAttributionTitle" />
+
+ <TextView
+ android:id="@+id/issue_card_title"
+ android:text="@string/summary_placeholder"
+ android:screenReaderFocusable="false"
+ style="@style/SafetyCenterIssueTitle" />
+
+ <TextView
+ android:id="@+id/issue_card_subtitle"
+ android:text="@string/summary_placeholder"
+ android:screenReaderFocusable="false"
+ style="@style/SafetyCenterIssueSubtitle" />
+
+ <TextView
+ android:id="@+id/issue_card_summary"
+ android:text="@string/summary_placeholder"
+ android:screenReaderFocusable="false"
+ style="@style/SafetyCenterIssueSummary" />
+
+ <include
+ android:id="@+id/issue_card_action_button_list"
+ layout="@layout/action_button_list"/>
+
+ <com.android.permissioncontroller.permission.ui.v33.widget.SafetyProtectionSectionView
+ android:id="@+id/issue_card_protected_by_android"
+ android:importantForAccessibility="no"
+ style="@style/SafetyCenterIssueSafetyProtectionSection" />
+
+ <ImageView
+ android:id="@+id/resolved_issue_image"
+ android:src="@drawable/safety_center_issue_resolved_avd"
+ android:importantForAccessibility="no"
+ style="@style/SafetyCenterIssueCardResolvedImage" />
+
+ <TextView
+ android:id="@+id/resolved_issue_text"
+ 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. -->
+ <androidx.constraintlayout.widget.Group
+ android:id="@+id/default_issue_content"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="visible"
+ app:constraint_referenced_ids="issue_card_title,issue_card_summary,issue_card_action_button_list" />
+
+ <androidx.constraintlayout.widget.Group
+ android:id="@+id/resolved_issue_content"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ app:constraint_referenced_ids="resolved_issue_image,resolved_issue_text" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/PermissionController/res/layout-v33/preference_more_issues_card.xml b/PermissionController/res/layout-v33/preference_more_issues_card.xml
new file mode 100644
index 000000000..c93125762
--- /dev/null
+++ b/PermissionController/res/layout-v33/preference_more_issues_card.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.
+ -->
+
+<com.android.permissioncontroller.safetycenter.ui.view.MoreIssuesHeaderView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/issue_card"
+ style="@style/SafetyCenterMoreIssuesCollapsed"/>
diff --git a/PermissionController/res/drawable/safety_center_button_background.xml b/PermissionController/res/layout-v33/preference_safety_status.xml
index 5723588f5..42bf1c22d 100644
--- a/PermissionController/res/drawable/safety_center_button_background.xml
+++ b/PermissionController/res/layout-v33/preference_safety_status.xml
@@ -14,8 +14,7 @@
~ limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="?android:attr/colorAccent"/>
- <corners android:radius="20dp" />
-</shape> \ No newline at end of file
+<com.android.permissioncontroller.safetycenter.ui.view.StatusCardView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:clickable="false"
+ style="@style/SafetyCenterCard.Status" /> \ No newline at end of file
diff --git a/PermissionController/res/layout-v33/safety_center_entry_common_view.xml b/PermissionController/res/layout-v33/safety_center_entry_common_view.xml
new file mode 100644
index 000000000..c1cf964c4
--- /dev/null
+++ b/PermissionController/res/layout-v33/safety_center_entry_common_view.xml
@@ -0,0 +1,46 @@
+<?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
+ -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:parentTag="LinearLayout">
+
+ <FrameLayout
+ android:id="@+id/icon_frame"
+ style="@style/SafetyCenterEntryIconFrame">
+ <ImageView
+ android:id="@+id/icon"
+ android:importantForAccessibility="no"
+ style="@style/SafetyCenterEntryIcon"/>
+ </FrameLayout>
+
+ <Space
+ android:id="@+id/empty_space"
+ style="@style/SafetyCenterEntryEmptySpace"/>
+
+ <LinearLayout
+ style="@style/SafetyCenterEntryTextContainer">
+
+ <TextView android:id="@+id/title"
+ style="@style/SafetyCenterEntryTitle" />
+
+ <TextView android:id="@+id/summary"
+ style="@style/SafetyCenterEntrySummary" />
+
+ </LinearLayout>
+</merge>
diff --git a/PermissionController/res/layout-v33/safety_center_group.xml b/PermissionController/res/layout-v33/safety_center_group.xml
new file mode 100644
index 000000000..8aa43af8a
--- /dev/null
+++ b/PermissionController/res/layout-v33/safety_center_group.xml
@@ -0,0 +1,49 @@
+<?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
+ -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:parentTag="LinearLayout">
+
+ <LinearLayout android:id="@+id/group_header"
+ style="@style/SafetyCenterGroupHeader">
+
+ <LinearLayout android:id="@+id/collapsed_header"
+ style="@style/SafetyCenterCollapsedGroupHeader">
+
+ <include layout="@layout/safety_center_entry_common_view" />
+
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/expanded_header"
+ style="@style/SafetyCenterExpandedGroupHeader">
+
+ <TextView android:id="@+id/title"
+ style="@style/SafetyCenterExpandedGroupTitle"/>
+
+ </LinearLayout>
+
+ <ImageView android:id="@+id/chevron_icon"
+ style="@style/SafetyCenterExpandedGroupIcon" />
+
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/entries_container"
+ style="@style/SafetyCenterGroupEntries"/>
+
+</merge>
diff --git a/PermissionController/res/layout-v33/safety_center_group_entry.xml b/PermissionController/res/layout-v33/safety_center_group_entry.xml
new file mode 100644
index 000000000..198191893
--- /dev/null
+++ b/PermissionController/res/layout-v33/safety_center_group_entry.xml
@@ -0,0 +1,20 @@
+<?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
+ -->
+
+<com.android.permissioncontroller.safetycenter.ui.view.SafetyEntryView
+ style="@style/SafetyCenterGroupEntry" /> \ No newline at end of file
diff --git a/PermissionController/res/layout-v33/safety_center_qs.xml b/PermissionController/res/layout-v33/safety_center_qs.xml
new file mode 100644
index 000000000..5bb89b07b
--- /dev/null
+++ b/PermissionController/res/layout-v33/safety_center_qs.xml
@@ -0,0 +1,81 @@
+<?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.
+ -->
+<androidx.core.widget.NestedScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/nested_scroll_view"
+ android:contentDescription="@string/safety_center_qs_page_landing"
+ style="@style/SafetyCenterQsContainer">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/close_button"
+ android:src="@drawable/ic_close"
+ android:contentDescription="@string/safety_center_qs_close_button"
+ style="@style/SafetyCenterQsCloseButton"/>
+
+ <LinearLayout
+ android:id="@+id/main_page_contents"
+ android:layout_height="wrap_content"
+ style="@style/SafetyCenterQsBody">
+
+ <TextView
+ android:id="@+id/permission_section_title"
+ android:text="@string/sensor_permissions_qs"
+ android:visibility="gone"
+ android:focusable="true"
+ android:importantForAccessibility="yes"
+ style="@style/SafetyCenterQsSectionTitle"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:id="@+id/permission_usage"
+ style="@style/SafetyCenterQsPermissionUsage"/>
+
+ <TextView
+ android:id="@+id/status_section_title"
+ android:text="@string/safety_privacy_qs_tile_title"
+ android:visibility="gone"
+ android:focusable="true"
+ android:importantForAccessibility="yes"
+ style="@style/SafetyCenterQsSectionTitle"/>
+
+ <FrameLayout
+ android:id="@+id/safety_center_prefs"
+ style="@style/SafetyCenterQsPreferences">
+ </FrameLayout>
+
+ <TextView
+ android:id="@+id/sensor_privacy_title"
+ android:text="@string/privacy_controls_qs"
+ android:focusable="true"
+ android:importantForAccessibility="yes"
+ style="@style/SafetyCenterQsSectionTitle"/>
+
+ <LinearLayout
+ android:id="@+id/toggle_container"
+ android:background="@drawable/safety_entity_top_large_bottom_large_background"
+ style="@style/SafetyCenterQsToggleContainer" />
+
+ </LinearLayout>
+ </LinearLayout>
+</androidx.core.widget.NestedScrollView>
diff --git a/PermissionController/res/layout-v33/safety_center_scroll_wrapper.xml b/PermissionController/res/layout-v33/safety_center_scroll_wrapper.xml
new file mode 100644
index 000000000..449e6daad
--- /dev/null
+++ b/PermissionController/res/layout-v33/safety_center_scroll_wrapper.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.
+ -->
+<androidx.core.widget.NestedScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipChildren="false">
+
+ <androidx.fragment.app.FragmentContainerView
+ android:id="@+id/fragment_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+</androidx.core.widget.NestedScrollView> \ No newline at end of file
diff --git a/PermissionController/res/layout-v33/safety_center_toggle_button.xml b/PermissionController/res/layout-v33/safety_center_toggle_button.xml
new file mode 100644
index 000000000..f790e734e
--- /dev/null
+++ b/PermissionController/res/layout-v33/safety_center_toggle_button.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/SafetyCenterQsToggleButton"
+ android:id="@+id/safety_center_toggle_button">
+ <ImageView
+ android:id="@+id/toggle_sensor_icon"
+ style="@style/SafetyCenterQsToggleIcon"/>
+
+ <LinearLayout
+ style="@style/SafetyCenterQsToggleTextContainer">
+ <TextView
+ android:id="@+id/toggle_sensor_name"
+ style="@style/SafetyCenterQsToggleText.Title"/>
+ <TextView
+ android:id="@+id/toggle_sensor_status"
+ style="@style/SafetyCenterQsToggleText.Subtitle"
+ android:text="@string/available"/>
+ </LinearLayout>
+
+ <ImageView
+ android:id="@+id/arrow_icon"
+ style="@style/SafetyCenterQsToggleArrow"
+ android:visibility="gone"/>
+</LinearLayout>
diff --git a/PermissionController/res/layout-v33/spaced_preference_category_no_label.xml b/PermissionController/res/layout-v33/spaced_preference_category_no_label.xml
new file mode 100644
index 000000000..cecdc8bcd
--- /dev/null
+++ b/PermissionController/res/layout-v33/spaced_preference_category_no_label.xml
@@ -0,0 +1,18 @@
+<!--
+ ~ 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.
+ -->
+
+<Space
+ style="@style/SafetyCenterNoLabelPreferenceCategory"/> \ No newline at end of file
diff --git a/PermissionController/res/layout-v33/view_entry.xml b/PermissionController/res/layout-v33/view_entry.xml
new file mode 100644
index 000000000..878c80131
--- /dev/null
+++ b/PermissionController/res/layout-v33/view_entry.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:parentTag="LinearLayout">
+
+ <include layout="@layout/safety_center_entry_common_view" />
+
+ <!-- A preference could place its optional widget here. This will be hidden if no widget layout
+ is set for the preference. -->
+ <LinearLayout android:id="@+id/widget_frame"
+ style="@style/SafetyCenterEntryWidgetFrame">
+ <View style="@style/SafetyCenterEntryDivider" />
+ <!-- PreferenceGroupAdapter will inflate widget layouts here -->
+ </LinearLayout>
+</merge>
diff --git a/PermissionController/res/layout-v33/view_more_issues.xml b/PermissionController/res/layout-v33/view_more_issues.xml
new file mode 100644
index 000000000..e1db725ad
--- /dev/null
+++ b/PermissionController/res/layout-v33/view_more_issues.xml
@@ -0,0 +1,45 @@
+<!--
+ ~ 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.
+ -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
+
+ <ImageView
+ android:id="@+id/status_icon"
+ android:importantForAccessibility="no"
+ android:src="@drawable/safety_status_info"
+ style="@style/SafetyCenterMoreIssuesIcon"/>
+
+ <TextView
+ android:id="@+id/title"
+ style="@style/SafetyCenterMoreIssuesTitle"/>
+
+ <LinearLayout
+ android:id="@android:id/widget_frame"
+ style="@style/SafetyCenterMoreIssuesCounter">
+
+ <TextView
+ android:id="@+id/widget_title"
+ style="@style/SafetyCenterMoreIssuesWidgetTitle" />
+
+ <ImageView
+ android:id="@+id/widget_icon"
+ android:importantForAccessibility="no"
+ style="@style/SafetyCenterMoreIssuesWidgetIcon" />
+
+ </LinearLayout>
+</merge> \ No newline at end of file
diff --git a/PermissionController/res/layout-v33/view_status_card.xml b/PermissionController/res/layout-v33/view_status_card.xml
new file mode 100644
index 000000000..4915347be
--- /dev/null
+++ b/PermissionController/res/layout-v33/view_status_card.xml
@@ -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.
+ -->
+
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
+
+ <ImageView
+ android:id="@+id/status_image"
+ android:importantForAccessibility="no"
+ android:src="@drawable/safety_status_info"
+ style="@style/SafetyCenterStatusImage" />
+
+ <LinearLayout
+ android:id="@+id/status_title_and_summary"
+ style="?attr/scStatusTitleAndSummaryContainerStyle">
+
+ <TextView
+ android:id="@+id/status_title"
+ android:text="@string/summary_placeholder"
+ style="@style/SafetyCenterStatusTitle" />
+
+ <TextView
+ android:id="@+id/status_summary"
+ android:text="@string/summary_placeholder"
+ style="@style/SafetyCenterStatusSummary" />
+ </LinearLayout>
+
+ <androidx.constraintlayout.widget.Barrier
+ android:id="@+id/sc_status_buttons_start_barrier"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:barrierDirection="start"
+ app:constraint_referenced_ids="review_settings_button,rescan_button" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/review_settings_button"
+ android:text="@string/safety_center_review_settings_button"
+ android:visibility="gone"
+ style="?attr/scStatusButtonStyle" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/rescan_button"
+ android:text="@string/safety_center_rescan_button"
+ style="?attr/scStatusButtonStyle" />
+</merge> \ No newline at end of file
diff --git a/PermissionController/res/layout-v34/app_data_sharing_details_preference.xml b/PermissionController/res/layout-v34/app_data_sharing_details_preference.xml
new file mode 100644
index 000000000..32654e577
--- /dev/null
+++ b/PermissionController/res/layout-v34/app_data_sharing_details_preference.xml
@@ -0,0 +1,32 @@
+<?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.
+ -->
+
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/AppDataSharingDetailsContainer">
+
+ <TextView
+ android:id="@+id/info_message"
+ android:text="@string/data_sharing_updates_subtitle"
+ style="@style/AppDataSharingDetailsMessage"/>
+
+ <TextView
+ android:id="@+id/no_updates_message"
+ android:text="@string/no_updates_at_this_time"
+ style="@style/AppDataSharingNoUpdatesMessage" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/PermissionController/res/layout-v34/app_data_sharing_settings_preference.xml b/PermissionController/res/layout-v34/app_data_sharing_settings_preference.xml
new file mode 100644
index 000000000..d32748e83
--- /dev/null
+++ b/PermissionController/res/layout-v34/app_data_sharing_settings_preference.xml
@@ -0,0 +1,50 @@
+<?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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/AppDataSharingUpdatePreference">
+
+ <FrameLayout
+ android:id="@android:id/icon_frame"
+ style="@style/AppDataSharingUpdateAppIconFrame">
+
+ <androidx.preference.internal.PreferenceImageView
+ style="@style/AppDataSharingUpdateAppIcon" />
+
+ </FrameLayout>
+
+ <RelativeLayout style="@style/AppDataSharingUpdatePreferenceTitleAndSummaryContainer">
+
+ <TextView
+ android:id="@android:id/title"
+ style="@style/AppDataSharingUpdatePreferenceTitle" />
+
+ <TextView
+ android:id="@android:id/summary"
+ style="@style/AppDataSharingUpdatePreferenceSummary" />
+
+ </RelativeLayout>
+
+ <FrameLayout style="@style/AppDataSharingUpdateSettingsIconFrame">
+
+ <androidx.preference.internal.PreferenceImageView
+ android:id="@+id/settings_button"
+ style="@style/AppDataSharingUpdateSettingsIcon"
+ android:contentDescription="@string/safety_label_changes_gear_description" />
+
+ </FrameLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/PermissionController/res/layout-v34/app_data_sharing_updates_footer_preference.xml b/PermissionController/res/layout-v34/app_data_sharing_updates_footer_preference.xml
new file mode 100644
index 000000000..7035a0edf
--- /dev/null
+++ b/PermissionController/res/layout-v34/app_data_sharing_updates_footer_preference.xml
@@ -0,0 +1,39 @@
+<?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.
+ -->
+
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/AppDataSharingUpdatesFooterContainer">
+
+ <FrameLayout
+ android:id="@+id/icon_frame"
+ style="@style/AppDataSharingUpdatesFooterIconFrame">
+ <androidx.preference.internal.PreferenceImageView
+ android:id="@android:id/icon"
+ style="@style/AppDataSharingUpdatesFooterIcon" />
+ </FrameLayout>
+
+ <TextView
+ android:id="@+id/footer_message"
+ style="@style/AppDataSharingUpdatesFooterMessage" />
+
+ <TextView
+ android:id="@+id/footer_link"
+ style="@style/AppDataSharingUpdatesFooterLink" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/PermissionController/res/layout-v34/permission_rationale.xml b/PermissionController/res/layout-v34/permission_rationale.xml
new file mode 100644
index 000000000..8f80a389e
--- /dev/null
+++ b/PermissionController/res/layout-v34/permission_rationale.xml
@@ -0,0 +1,143 @@
+<?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.
+ -->
+
+<!--
+ ~ A lot of content in this file is identical to grant_permissions.xml
+ ~ Be sure to update both files when making changes.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/permission_rationale_singleton"
+ android:importantForAccessibility="no"
+ android:focusable="false"
+ style="@style/PermissionRationaleSingleton">
+
+ <!-- The dialog -->
+ <LinearLayout
+ android:id="@+id/permission_rationale_dialog"
+ android:theme="@style/Theme.PermissionRationaleDialog"
+ android:importantForAccessibility="no"
+ style="@style/PermissionRationaleDialog">
+
+ <!-- In (hopefully very rare) case dialog is too high: allow scrolling -->
+ <ScrollView
+ style="@style/PermissionRationaleScrollView">
+
+ <LinearLayout
+ android:id="@+id/content_container"
+ style="@style/PermissionRationaleContent">
+
+ <LinearLayout
+ style="@style/PermissionRationaleTitleContainer">
+
+ <ImageView
+ android:id="@+id/permission_icon"
+ android:importantForAccessibility="no"
+ android:src="@drawable/ic_shield_exclamation_outline"
+ style="@style/PermissionRationaleTitleIcon" />
+
+ <TextView
+ android:id="@+id/permission_rationale_title"
+ style="@style/PermissionRationaleTitleMessage" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/data_sharing_source_section"
+ style="@style/PermissionRationaleSectionOuterContainer">
+ <ImageView
+ android:id="@+id/data_sharing_source_icon"
+ android:importantForAccessibility="no"
+ android:src="@drawable/ic_info_24dp"
+ style="@style/PermissionRationaleSectionIcon" />
+ <LinearLayout style="@style/PermissionRationaleSectionInnerContainer">
+ <TextView
+ android:id="@+id/data_sharing_source_title"
+ android:text="@string/permission_rationale_data_sharing_source_title"
+ style="@style/PermissionRationaleSectionTitle" />
+ <TextView
+ android:id="@+id/data_sharing_source_message"
+ style="@style/PermissionRationaleSectionMessage" />
+ </LinearLayout>
+ </LinearLayout>
+ <LinearLayout
+ android:id="@+id/purpose_section"
+ style="@style/PermissionRationaleSectionOuterContainer">
+ <ImageView
+ android:id="@+id/purpose_icon"
+ android:importantForAccessibility="no"
+ android:src="@drawable/ic_help"
+ style="@style/PermissionRationaleSectionIcon" />
+ <LinearLayout style="@style/PermissionRationaleSectionInnerContainer">
+ <TextView
+ android:id="@+id/purpose_title"
+ style="@style/PermissionRationaleSectionTitle" />
+ <TextView
+ android:id="@+id/purpose_message"
+ style="@style/PermissionRationaleSectionPurposeList" />
+ </LinearLayout>
+ </LinearLayout>
+ <LinearLayout
+ android:id="@+id/learn_more_section"
+ style="@style/PermissionRationaleSectionOuterContainer">
+ <ImageView
+ android:id="@+id/learn_more_icon"
+ android:importantForAccessibility="no"
+ android:src="@drawable/ic_collections_bookmark"
+ style="@style/PermissionRationaleSectionIcon" />
+ <LinearLayout style="@style/PermissionRationaleSectionInnerContainer">
+ <TextView
+ android:id="@+id/learn_more_title"
+ android:text="@string/permission_rationale_permission_data_sharing_varies_title"
+ style="@style/PermissionRationaleSectionTitle" />
+ <TextView
+ android:id="@+id/learn_more_message"
+ android:text="@string/permission_rationale_data_sharing_varies_message"
+ style="@style/PermissionRationaleSectionMessage" />
+ </LinearLayout>
+ </LinearLayout>
+ <LinearLayout
+ android:id="@+id/settings_section"
+ style="@style/PermissionRationaleSectionOuterContainer">
+ <ImageView
+ android:id="@+id/settings_icon"
+ android:importantForAccessibility="no"
+ android:src="@drawable/ic_gear"
+ style="@style/PermissionRationaleSectionIcon" />
+ <LinearLayout style="@style/PermissionRationaleSectionInnerContainer">
+ <TextView
+ android:id="@+id/settings_title"
+ android:text="@string/permission_rationale_location_settings_title"
+ style="@style/PermissionRationaleSectionTitle" />
+ <TextView
+ android:id="@+id/settings_message"
+ style="@style/PermissionRationaleSectionMessage" />
+ </LinearLayout>
+ </LinearLayout>
+ </LinearLayout>
+ </ScrollView>
+
+ <LinearLayout style="@style/PermissionRationaleButtonContainer">
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/back_button"
+ android:text="@string/back"
+ android:theme="@style/Theme.Material3.DayNight"
+ style="@style/PermissionRationaleBackButton" />
+ </LinearLayout>
+
+ </LinearLayout>
+</LinearLayout>
diff --git a/PermissionController/res/layout-v34/preference_brand_chip.xml b/PermissionController/res/layout-v34/preference_brand_chip.xml
new file mode 100644
index 000000000..4efbda486
--- /dev/null
+++ b/PermissionController/res/layout-v34/preference_brand_chip.xml
@@ -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.
+ -->
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/SafetyCenterBrandChip">
+
+ <Button
+ android:id="@+id/brand_chip"
+ android:text="@string/security_privacy_brand_name"
+ style="@style/SafetyCenterBrandChipButton"/>
+</FrameLayout> \ No newline at end of file
diff --git a/PermissionController/res/layout-v34/preference_illustration.xml b/PermissionController/res/layout-v34/preference_illustration.xml
new file mode 100644
index 000000000..c1f5af421
--- /dev/null
+++ b/PermissionController/res/layout-v34/preference_illustration.xml
@@ -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.
+ -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/SafetyCenterIllustration">
+
+ <ImageView
+ android:id="@+id/illustration_view"
+ style="@style/SafetyCenterIllustrationView" />
+</FrameLayout> \ No newline at end of file
diff --git a/PermissionController/res/layout-v34/safety_center_non_scroll_wrapper.xml b/PermissionController/res/layout-v34/safety_center_non_scroll_wrapper.xml
new file mode 100644
index 000000000..eb21c0046
--- /dev/null
+++ b/PermissionController/res/layout-v34/safety_center_non_scroll_wrapper.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.
+ -->
+<androidx.fragment.app.FragmentContainerView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/fragment_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" /> \ No newline at end of file
diff --git a/PermissionController/res/layout-w764dp-v33/action_button_list.xml b/PermissionController/res/layout-w764dp-v33/action_button_list.xml
new file mode 100644
index 000000000..4db6df47c
--- /dev/null
+++ b/PermissionController/res/layout-w764dp-v33/action_button_list.xml
@@ -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.
+ -->
+
+
+<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/app_permission.xml b/PermissionController/res/layout/app_permission.xml
index 697150b6f..6d68611fa 100644
--- a/PermissionController/res/layout/app_permission.xml
+++ b/PermissionController/res/layout/app_permission.xml
@@ -38,6 +38,47 @@
<LinearLayout
style="@style/AppPermissionSelection">
+ <LinearLayout
+ android:id="@+id/app_permission_rationale_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/AppPermissionRationaleContainer">
+ <TextView
+ android:id="@+id/app_permission_rationale_message"
+ android:text="@string/app_permission_rationale_message"
+ style="@style/AppPermissionMessage" />
+
+ <LinearLayout
+ android:id="@+id/app_permission_rationale_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/AppPermissionRationaleContent" >
+
+ <ImageView
+ android:id="@+id/app_permission_rationale_icon"
+ android:importantForAccessibility="no"
+ android:src="@drawable/ic_shield_exclamation_outline"
+ style="@style/AppPermissionRationaleIcon" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/AppPermissionRationaleTextContent">
+ <TextView
+ android:duplicateParentState="true"
+ android:id="@+id/app_permission_rationale_title"
+ android:text="@string/app_location_permission_rationale_title"
+ style="@style/AppPermissionRationaleTitle" />
+ <TextView
+ android:duplicateParentState="true"
+ android:id="@+id/app_permission_rationale_subtitle"
+ android:text="@string/app_location_permission_rationale_subtitle"
+ style="@style/AppPermissionRationaleSubtitle" />
+ </LinearLayout>
+
+ </LinearLayout>
+ </LinearLayout>
+
<TextView
android:id="@+id/permission_message"
style="@style/AppPermissionMessage" />
@@ -64,6 +105,11 @@
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" />
diff --git a/PermissionController/res/layout/grant_permissions.xml b/PermissionController/res/layout/grant_permissions.xml
index 5c9d8f34e..9becddb7f 100644
--- a/PermissionController/res/layout/grant_permissions.xml
+++ b/PermissionController/res/layout/grant_permissions.xml
@@ -29,6 +29,7 @@
<LinearLayout
android:id="@+id/grant_singleton"
android:importantForAccessibility="no"
+ android:focusable="false"
style="@style/PermissionGrantSingleton">
<!-- The dialog -->
@@ -51,6 +52,7 @@
<TextView
android:id="@+id/permission_message"
+ android:accessibilityHeading="true"
style="@style/PermissionGrantTitleMessage" />
</LinearLayout>
@@ -61,6 +63,30 @@
</LinearLayout>
+ <!-- permission rationale -->
+ <LinearLayout
+ android:id="@+id/permission_rationale_container"
+ style="@style/PermissionGrantPermissionRationaleContent">
+
+ <ImageView
+ android:id="@+id/permission_rationale_icon"
+ android:importantForAccessibility="no"
+ android:src="@drawable/ic_shield_exclamation_outline"
+ style="@style/PermissionGrantPermissionRationaleIcon" />
+
+ <TextView
+ android:id="@+id/permission_rationale_message"
+ style="@style/PermissionGrantPermissionRationaleMessage" />
+
+ <ImageView
+ android:id="@+id/permission_rationale_more_info_icon"
+ android:importantForAccessibility="no"
+ android:src="@drawable/ic_more_info_arrow"
+ style="@style/PermissionGrantPermissionRationaleMoreInfoIcon" />
+
+ </LinearLayout>
+
+ <!-- location (precise/approximate) animations -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -116,6 +142,16 @@
style="@style/PermissionGrantButtonAllowOneTime" />
<com.android.permissioncontroller.permission.ui.widget.SecureButton
+ android:id="@+id/permission_allow_selected_button"
+ android:text="@string/grant_dialog_button_allow_selected_photos"
+ style="@style/PermissionGrantButtonAllowSelected" />
+
+ <com.android.permissioncontroller.permission.ui.widget.SecureButton
+ android:id="@+id/permission_allow_all_button"
+ android:text="@string/grant_dialog_button_allow_all"
+ style="@style/PermissionGrantButtonAllowAll" />
+
+ <com.android.permissioncontroller.permission.ui.widget.SecureButton
android:id="@+id/permission_deny_button"
android:text="@string/grant_dialog_button_deny"
style="@style/PermissionGrantButtonDeny" />
@@ -144,8 +180,13 @@
android:id="@+id/permission_no_upgrade_one_time_and_dont_ask_again_button"
android:text="@string/grant_dialog_button_no_upgrade_one_time"
style="@style/PermissionGrantButtonNoUpgrade" />
+
+ <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" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
-</ScrollView> \ No newline at end of file
+</ScrollView>
diff --git a/PermissionController/res/layout/grant_permissions_material3.xml b/PermissionController/res/layout/grant_permissions_material3.xml
index fdf090280..d405976cf 100644
--- a/PermissionController/res/layout/grant_permissions_material3.xml
+++ b/PermissionController/res/layout/grant_permissions_material3.xml
@@ -30,6 +30,7 @@
<LinearLayout
android:id="@+id/grant_singleton"
android:importantForAccessibility="no"
+ android:focusable="false"
style="@style/PermissionGrantSingleton">
<!-- The dialog -->
@@ -52,6 +53,7 @@
<TextView
android:id="@+id/permission_message"
+ android:accessibilityHeading="true"
style="@style/PermissionGrantTitleMessage" />
</LinearLayout>
@@ -62,6 +64,30 @@
</LinearLayout>
+ <!-- permission rationale -->
+ <LinearLayout
+ android:id="@+id/permission_rationale_container"
+ style="@style/PermissionGrantPermissionRationaleContent">
+
+ <ImageView
+ android:id="@+id/permission_rationale_icon"
+ android:importantForAccessibility="no"
+ android:src="@drawable/ic_shield_exclamation_outline"
+ style="@style/PermissionGrantPermissionRationaleIcon" />
+
+ <TextView
+ android:id="@+id/permission_rationale_message"
+ style="@style/PermissionGrantPermissionRationaleMessage" />
+
+ <ImageView
+ android:id="@+id/permission_rationale_more_info_icon"
+ android:importantForAccessibility="no"
+ android:src="@drawable/ic_more_info_arrow"
+ style="@style/PermissionGrantPermissionRationaleMoreInfoIcon" />
+
+ </LinearLayout>
+
+ <!-- location (precise/approximate) animations -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -69,7 +95,7 @@
<RadioGroup
android:id="@+id/permission_location_accuracy_radio_group"
- style="@style/PermissionLocationAccuracyRadioGroup">
+ style="@style/PermissionLocationAccuracyRadioGroupMaterial3">
<RadioButton
android:id="@+id/permission_location_accuracy_radio_fine"
@@ -85,12 +111,12 @@
<ImageView
android:id="@+id/permission_location_accuracy_fine_only"
android:contentDescription="@string/precise_image_description"
- style="@style/PermissionLocationAccuracyFineImageView" />
+ style="@style/PermissionLocationAccuracyFineImageViewMaterial3" />
<ImageView
android:id="@+id/permission_location_accuracy_coarse_only"
android:contentDescription="@string/approximate_image_description"
- style="@style/PermissionLocationAccuracyCoarseImageView" />
+ style="@style/PermissionLocationAccuracyCoarseImageViewMaterial3" />
</LinearLayout>
@@ -117,6 +143,16 @@
style="@style/PermissionGrantButtonAllowOneTimeMaterial3" />
<com.android.permissioncontroller.permission.ui.widget.SecureButton
+ android:id="@+id/permission_allow_selected_button"
+ android:text="@string/grant_dialog_button_allow_selected_photos"
+ style="@style/PermissionGrantButtonAllowSelectedMaterial3" />
+
+ <com.android.permissioncontroller.permission.ui.widget.SecureButton
+ android:id="@+id/permission_allow_all_button"
+ android:text="@string/grant_dialog_button_allow_all"
+ style="@style/PermissionGrantButtonAllowAllMaterial3" />
+
+ <com.android.permissioncontroller.permission.ui.widget.SecureButton
android:id="@+id/permission_deny_button"
android:text="@string/grant_dialog_button_deny"
style="@style/PermissionGrantButtonDenyMaterial3" />
@@ -145,9 +181,15 @@
android:id="@+id/permission_no_upgrade_one_time_and_dont_ask_again_button"
android:text="@string/grant_dialog_button_no_upgrade_one_time"
style="@style/PermissionGrantButtonNoUpgradeMaterial3" />
+
+ <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/PermissionGrantButtonDontAllowMoreMaterial3" />
+
</LinearLayout>
- <com.android.permissioncontroller.permission.ui.widget.SafetyProtectionSectionView
+ <com.android.permissioncontroller.permission.ui.v33.widget.SafetyProtectionSectionView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
@@ -155,4 +197,4 @@
android:layout_gravity="center" />
</LinearLayout>
</LinearLayout>
-</ScrollView> \ No newline at end of file
+</ScrollView>
diff --git a/PermissionController/res/layout/image_view_with_divider.xml b/PermissionController/res/layout/image_view_with_divider.xml
index 3193da507..09b38ce26 100644
--- a/PermissionController/res/layout/image_view_with_divider.xml
+++ b/PermissionController/res/layout/image_view_with_divider.xml
@@ -25,17 +25,15 @@
android:id="@+id/divider"
android:layout_width="1dp"
android:layout_height="24dp"
- android:layout_marginLeft="16dp"
+ android:layout_marginStart="16dp"
android:layout_gravity="end|center_vertical"
android:theme="@style/PreferenceDivider" />
<ImageButton
android:id="@+id/icon"
- android:layout_width="40dp"
+ android:layout_width="56dp"
android:layout_height="56dp"
- android:paddingLeft="16dp"
- android:paddingTop="16dp"
- android:paddingBottom="16dp"
+ android:padding="16dp"
android:layout_gravity="end|center_vertical"
android:contentDescription="@string/grant_dialog_button_more_info"
android:background="@null" />
diff --git a/PermissionController/res/layout/indicator_card.xml b/PermissionController/res/layout/indicator_card.xml
deleted file mode 100644
index d3a843622..000000000
--- a/PermissionController/res/layout/indicator_card.xml
+++ /dev/null
@@ -1,66 +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.
- -->
-<androidx.cardview.widget.CardView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="10dp"
- android:id="@+id/parent_card_view"
- style="@style/IndicatorCardView">
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/full_card">
- <RelativeLayout
- android:id="@+id/permission_parent"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
- <LinearLayout
- android:id="@+id/expanded_view"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:visibility="gone"
- android:layout_marginTop="10dp">
- <com.google.android.material.card.MaterialCardView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/manage_permission"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="4dp"
- style="@style/TopCornersCardView"
- android:theme="@style/TopCornersCardView">
- <RelativeLayout
- android:id="@+id/manage_parent"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
- </com.google.android.material.card.MaterialCardView>
- <com.google.android.material.card.MaterialCardView
- android:id="@+id/see_usage"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="4dp"
- style="@style/BottomCornersCardView"
- android:theme="@style/BottomCornersCardView">
- <RelativeLayout
- android:id="@+id/usage_parent"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
- </com.google.android.material.card.MaterialCardView>
- </LinearLayout>
- </LinearLayout>
-</androidx.cardview.widget.CardView>
diff --git a/PermissionController/res/layout/preference_spacer.xml b/PermissionController/res/layout/preference_spacer.xml
new file mode 100644
index 000000000..e22b07305
--- /dev/null
+++ b/PermissionController/res/layout/preference_spacer.xml
@@ -0,0 +1,19 @@
+<!--
+ ~ 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.
+ -->
+
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"/> \ No newline at end of file
diff --git a/PermissionController/res/layout/safety_center_qs.xml b/PermissionController/res/layout/safety_center_qs.xml
deleted file mode 100644
index 6b1b169d6..000000000
--- a/PermissionController/res/layout/safety_center_qs.xml
+++ /dev/null
@@ -1,99 +0,0 @@
-<?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.
- -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- style="@style/SafetyCenter"
- android:background="?android:colorBackground"
- android:id="@+id/safety_center_root">
-
-
-
- <androidx.core.widget.NestedScrollView
- android:id="@+id/nested_scroll_view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingStart="20dp"
- android:paddingEnd="20dp"
- android:clipChildren="false">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/permission_section_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="20dp"
- android:layout_marginBottom="10dp"
- android:text="@string/sensor_permissions_qs"
- android:visibility="gone"/>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_marginTop="10dp"
- android:layout_marginBottom="10dp"
- android:id="@+id/permission_usage"/>
-
- <TextView
- android:id="@+id/sensor_privacy_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="20dp"
- android:layout_marginBottom="10dp"
- android:text="@string/privacy_controls_qs"/>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity = "center_horizontal"
- android:orientation="horizontal"
- android:layout_marginBottom="10dp"
- android:layout_marginTop="10dp">
- <include android:id="@+id/camera_toggle"
- layout="@layout/safety_center_toggle_button" />
-
- <include android:id="@+id/mic_toggle"
- layout="@layout/safety_center_toggle_button" />
-
- <include android:id="@+id/location_toggle"
- layout="@layout/safety_center_toggle_button" />
- </LinearLayout>
-
- <Button
- android:id="@+id/security_settings_button"
- android:layout_marginTop="20dp"
- android:layout_height="40dp"
- android:layout_width="300dp"
- android:layout_gravity="center_horizontal"
- android:background="@drawable/oval_outline_button"
- style="@style/SafetyCenterLinkText"
- android:textColor="#ffffffff"
- android:text="@string/security_settings"/>
-
- </LinearLayout>
-
- </androidx.core.widget.NestedScrollView>
-
-</LinearLayout>
diff --git a/PermissionController/res/navigation/nav_graph.xml b/PermissionController/res/navigation/nav_graph.xml
index cd3ba5980..874e31a87 100644
--- a/PermissionController/res/navigation/nav_graph.xml
+++ b/PermissionController/res/navigation/nav_graph.xml
@@ -186,4 +186,9 @@
app:popExitAnim="@anim/activity_close_exit"
app:popEnterAnim="@anim/activity_open_enter"/>
</fragment>
+
+ <fragment
+ android:id="@+id/app_data_sharing_updates"
+ android:name="com.android.permissioncontroller.permission.ui.handheld.v34.AppDataSharingUpdatesWrapperFragment"
+ android:label="AppDataSharingUpdates"/>
</navigation> \ No newline at end of file
diff --git a/PermissionController/res/raw-night/coarse_loc_off.json b/PermissionController/res/raw-night/coarse_loc_off.json
new file mode 100644
index 000000000..2779a0c64
--- /dev/null
+++ b/PermissionController/res/raw-night/coarse_loc_off.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":91,"w":300,"h":300,"nm":"Location_Accuracy_Approximate_OFF_DT","ddd":0,"assets":[{"id":"comp_0","nm":"Approximate_OFF_DT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Scale Controller","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[58.5,49,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.2],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":15,"s":[62,62,100]},{"t":60,"s":[90,90,100]}],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Highway_Signs","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.029,-0.19],[0,0],[0.041,0.176]],"o":[[-0.042,0.176],[0,0],[-0.03,-0.19],[0,0]],"v":[[-5.894,-0.275],[-6,0.275],[6,0.275],[5.894,-0.275]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.910000011968,0.941000007181,0.995999983245,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[130.584,67.277],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.626,-1.193],[0,0],[-1.626,3.099],[0.158,1.029],[0,0]],"o":[[1.626,3.099],[0,0],[0.626,-1.193],[0,0],[-0.158,1.029]],"v":[[-5.48,-0.218],[-0.001,3.653],[5.479,-0.218],[5.999,-3.653],[-6,-3.653]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[130.583,71.205],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.321,-0.037],[0,0],[1.358,0.037],[0,0],[0.292,-1.237],[0,0]],"o":[[0,0],[-1.358,0.037],[0,0],[-1.321,-0.037],[0,0],[0,0],[-0.292,-1.237]],"v":[[5.065,-1.046],[2.496,0.129],[0,-1.046],[-2.496,0.129],[-5.065,-1.046],[-5.894,1.046],[5.894,1.046]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917999985639,0.263000009574,0.20800000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[130.584,65.956],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.029,-0.19],[0,0],[0.041,0.176]],"o":[[-0.042,0.176],[0,0],[-0.03,-0.19],[0,0]],"v":[[-5.894,-0.275],[-6,0.275],[6,0.275],[5.894,-0.275]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.910000011968,0.941000007181,0.995999983245,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[195.904,70.159],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.626,-1.193],[0,0],[-1.626,3.099],[0.158,1.029],[0,0]],"o":[[1.626,3.099],[0,0],[0.626,-1.193],[0,0],[-0.158,1.029]],"v":[[-5.479,-0.218],[0.001,3.653],[5.48,-0.218],[5.999,-3.653],[-5.999,-3.653]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[195.904,74.086],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":4,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.321,-0.037],[0,0],[1.358,0.037],[0,0],[0.292,-1.237],[0,0]],"o":[[0,0],[-1.358,0.037],[0,0],[-1.321,-0.037],[0,0],[0,0],[-0.292,-1.237]],"v":[[5.065,-1.046],[2.496,0.129],[0,-1.046],[-2.496,0.129],[-5.065,-1.046],[-5.894,1.046],[5.894,1.046]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917999985639,0.263000009574,0.20800000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[195.904,68.837],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":4,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.029,-0.191],[0,0],[0.041,0.176]],"o":[[-0.042,0.176],[0,0],[-0.03,-0.191],[0,0]],"v":[[-5.894,-0.275],[-6,0.275],[6,0.275],[5.894,-0.275]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.910000011968,0.941000007181,0.995999983245,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[210.57,222.357],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 13","np":4,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.626,-1.193],[0,0],[-1.626,3.099],[0.158,1.029],[0,0]],"o":[[1.626,3.099],[0,0],[0.626,-1.193],[0,0],[-0.158,1.029]],"v":[[-5.479,-0.217],[-0.001,3.653],[5.48,-0.217],[5.999,-3.652],[-5.999,-3.652]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[210.57,226.283],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 14","np":4,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.321,-0.037],[0,0],[1.358,0.038],[0,0],[0.292,-1.238],[0,0]],"o":[[0,0],[-1.358,0.038],[0,0],[-1.321,-0.037],[0,0],[0,0],[-0.292,-1.238]],"v":[[5.065,-1.046],[2.496,0.128],[0,-1.046],[-2.496,0.128],[-5.065,-1.046],[-5.894,1.046],[5.894,1.046]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917999985639,0.263000009574,0.20800000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[210.57,221.035],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 15","np":4,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.029,-0.191],[0,0],[0.041,0.177]],"o":[[-0.042,0.177],[0,0],[-0.03,-0.191],[0,0]],"v":[[-5.894,-0.276],[-6,0.275],[6,0.275],[5.894,-0.276]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.910000011968,0.941000007181,0.995999983245,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[190.011,186.54],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 16","np":4,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.626,-1.192],[0,0],[-1.626,3.1],[0.158,1.028],[0,0]],"o":[[1.626,3.1],[0,0],[0.626,-1.192],[0,0],[-0.158,1.028]],"v":[[-5.479,-0.218],[-0.001,3.652],[5.48,-0.218],[5.999,-3.652],[-5.999,-3.652]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[190.01,190.467],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 17","np":4,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.321,-0.036],[0,0],[1.358,0.038],[0,0],[0.292,-1.237],[0,0]],"o":[[0,0],[-1.358,0.038],[0,0],[-1.321,-0.036],[0,0],[0,0],[-0.292,-1.237]],"v":[[5.065,-1.046],[2.496,0.128],[0,-1.046],[-2.496,0.128],[-5.065,-1.046],[-5.894,1.046],[5.894,1.046]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917999985639,0.263000009574,0.20800000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[190.011,185.218],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 18","np":4,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".yellow200","cl":"yellow200","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-10.273,-62.792],[10.273,-19.932],[5.308,43.982],[3.529,62.792]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156862745,0.886274509804,0.576470588235,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[304.691,67.791],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 19","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-69.845,50.02],[-43.615,20.333],[-43.615,-21.96],[-34.261,-28.874],[-24.095,-28.874],[-16.368,-34.974],[-1.728,-31.72],[1.931,-37.821],[7.218,-34.567],[23.079,-42.293],[55.331,-42.293],[69.845,-50.02]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156862745,0.886274509804,0.576470588235,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[373.948,242.314],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 20","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-113.972,-119.335],[-113.972,-89.146],[-110.288,-76.336],[-118.014,-57.426],[-110.288,-39.939],[-93.615,-15.54],[-81.414,-1.306],[-84.668,17.808],[-75.721,29.193],[-63.521,36.921],[-49.288,39.36],[-41.968,48.714],[-28.954,48.714],[-17.568,53.594],[-2.115,58.067],[5.205,65.794],[21.066,68.233],[51.972,97.107],[62.545,99.954],[75.559,99.954],[118.014,119.335]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156862745,0.886274509804,0.576470588235,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[245.421,175.3],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 21","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-214.415,-10.167],[-193.269,2.034],[-180.255,2.034],[-172.122,4.88],[-161.548,-0.406],[-149.349,0.001],[-132.675,-7.32],[-126.575,-5.693],[-113.969,-10.167],[-96.075,-8.133],[-88.755,-2.643],[-80.215,-2.643],[-43.208,-2.643],[-22.062,-6.1],[-13.319,0.407],[-0.61,2.034],[17.384,-2.643],[35.278,-0.406],[50.731,2.034],[53.985,6.913],[73.912,4.88],[86.111,10.167],[114.578,10.167],[150.365,10.167],[159.311,4.88],[214.415,2.034]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156862745,0.886274509804,0.576470588235,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[223.889,101.607],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 22","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-152.296,-34.933],[-152.296,-17.527],[-140.503,-1.668],[-129.523,3.62],[-129.523,10.94],[-120.577,15.413],[-117.729,22.327],[-88.449,34.933],[-76.251,30.867],[-68.117,23.953],[-38.43,27.207],[-25.417,28.833],[-7.93,24.767],[20.943,25.986],[31.924,29.24],[38.837,25.58],[51.443,25.58],[60.391,21.513],[86.01,18.667],[97.804,26.8],[152.297,26.393]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156862745,0.886274509804,0.576470588235,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[304.103,105.308],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 24","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[21.757,-76.408],[21.757,-63.89],[13.214,-63.89],[-14.031,-38.677],[-19.724,-23.223],[-21.757,54.857],[-18.098,63.803],[-21.757,76.409]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156862745,0.886274509804,0.576470588235,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[210.57,177.698],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 25","np":2,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-67.1,-42.533],[-37.413,-29.478],[-34.567,-20.938],[-28.873,-24.191],[-17.08,-23.378],[-5.693,-7.518],[12.2,-3.046],[18.3,5.495],[24.807,9.562],[38.227,11.594],[52.867,19.729],[62.525,21.355],[67.1,29.896],[67.1,42.533]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156862745,0.886274509804,0.576470588235,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[160.753,59.919],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 26","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-139.893,-158.396],[-135.827,-143.349],[-95.566,-100.243],[-75.233,-93.736],[-51.646,-67.303],[-48.8,-54.29],[-35.38,-42.496],[-32.94,-22.57],[-24.807,-18.91],[-10.574,-14.844],[8.947,16.47],[58.56,53.477],[82.147,84.79],[102.074,96.99],[125.66,133.997],[139.893,142.536],[139.893,158.396]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156862745,0.886274509804,0.576470588235,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[243.307,169.317],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 28","np":2,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".grey300","cl":"grey300","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[31.717,-1.007],[-31.717,1.007]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[287.883,119.11],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 29","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-35.365,-14.212],[-27.159,-14.715],[-22.239,-18.741],[-8.414,-18.741],[6.556,-19.629],[15.02,-18.202],[28.069,-14.212],[28.069,-5.406],[28.069,1.64],[28.069,10.949],[29.704,14.22],[35.239,16.731],[35.365,19.629]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[291.531,123.51],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 30","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-41.561,-23.371],[-37.444,-22.113],[-31.154,-25.384],[-26.499,-26.767],[-21.215,-28.151],[-18.196,-31.05],[-12.41,-31.528],[-8.761,-31.05],[-7.628,-28.906],[9.733,-22.113],[23.067,-5.129],[29.106,-0.14],[37.283,12.608],[40.931,21.004],[41.561,31.528]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[348.112,171.29],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 31","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[4.64,-38.155],[4.64,-8.29],[7.771,-2.101],[6.974,5.21],[2.462,11.432],[-0.966,22.989],[-7.771,38.155]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[251.527,139.762],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 32","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-19.621,11.458],[-23.788,-11.458],[23.788,-11.458]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[259.299,233.54],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 33","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-36.573,-3.452],[3.542,-3.452],[8.492,-1.858],[25.051,-3.452],[31.026,-2.655],[35.293,0.133],[36.573,2.352],[34.013,2.352],[32.887,3.451]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[297.973,269.1],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 34","np":2,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-25.691,-18.223],[-10.328,-18.734],[-5.207,-17.88],[1.281,-18.307],[18.009,-19.077],[25.691,-12.504],[22.789,-10.797],[14.168,0.47],[12.376,5.846],[8.45,13.615],[4.011,19.077]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[307.575,287.115],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 35","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[50.742,46.448],[51.669,43.468],[50.742,37.157],[55.148,32.302],[72.276,31.185],[72.276,5.64],[70.623,-1.526],[70.623,-40.523],[69.383,-42.865],[62.906,-43.554],[56.843,-42.865],[54.224,-44.381],[49.264,-44.381],[45.13,-46.448],[-72.276,-46.448]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[226.967,241.72],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 36","np":2,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-119.509,-44.611],[-97.824,-40.96],[-89.824,-34.688],[-72.741,-36.266],[-66.754,-33.154],[40.537,-34.971],[59.633,-38.882],[68.047,-38.882],[73.387,-37.306],[74.626,-33.154],[77.919,-31.804],[77.919,-26.232],[80.508,-24.928],[89.57,-21.215],[97.823,-16.038],[105.684,-14.257],[108.827,-8.431],[113.844,5.663],[119.508,8.884],[117.654,19.078],[110.284,25.092],[107.048,37.527],[104.562,44.612]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[278.637,267.243],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 37","np":2,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-51.352,2.509],[13.052,3.155],[35.386,-3.155],[51.352,-3.155]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[301.911,213.904],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 38","np":2,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[275.481,202.819],[275.481,222.082]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 39","np":2,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[2.805,-24.131],[-0.446,-14.804],[1.18,18.209],[-2.805,24.131]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[269.292,219.403],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 40","np":2,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-16.325,-7.523],[-4.713,-0.839],[5.806,-0.839],[16.325,7.523]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[261.745,182.35],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 41","np":2,"cix":2,"bm":0,"ix":13,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-52.188,-19.67],[-41.346,-24.51],[-9.628,-12.712],[5.098,-9.312],[20.956,-3.564],[26.135,-4.62],[34.719,-0.671],[41.671,4.326],[52.189,7.729],[46.039,15.452],[46.202,24.509]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[213.259,163.422],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 42","np":2,"cix":2,"bm":0,"ix":14,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[73.548,-6.19],[75.996,7.565],[69.525,24.299],[59.976,26.175],[53.504,28.441],[47.03,33.188],[47.03,39.488],[34.894,32.698],[26.767,21.986],[17.423,17.347],[-1.49,12.605],[-28.757,3.71],[-37.055,-16.252],[-66.354,-16.252],[-66.354,-18.782],[-69.801,-23.38],[-68.077,-26.092],[-70.654,-30.31],[-74.309,-30.31],[-75.996,-39.488]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[230.554,138.453],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 43","np":2,"cix":2,"bm":0,"ix":15,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-68.814,-67.689],[-33.186,-67.127],[-13.566,-64.287],[9.77,-52.647],[17.081,-46.04],[58.129,-44.971],[60.347,-29.873],[60.347,-12.806],[61.785,6.876],[59.395,9.068],[60.347,54.334],[65.44,54.334],[68.814,58.411],[63.612,63.472],[65.581,64.877],[63.612,67.689]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[243.756,235.438],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 44","np":2,"cix":2,"bm":0,"ix":16,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-6.636,-10.36],[-2.642,-10.95],[4.106,-13.762],[4.478,-12.242],[5.933,-6.307],[6.636,13.761]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[170.836,181.51],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 45","np":2,"cix":2,"bm":0,"ix":17,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[150.903,178.874],[176.77,178.874]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 46","np":2,"cix":2,"bm":0,"ix":18,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-46.11,-24.495],[-24.601,-24.495],[-18.978,-22.285],[10.012,-24.495],[26.288,-21.262],[39.924,-19.433],[46.11,-14.795],[41.028,24.495]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[194.482,197.586],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 47","np":2,"cix":2,"bm":0,"ix":19,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[163.403,74.086],[163.403,98.964]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 48","np":2,"cix":2,"bm":0,"ix":20,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[2.298,-13.017],[-2.298,-7.952],[0.038,-1.57],[0.038,13.017]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[138.776,74.953],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 49","np":2,"cix":2,"bm":0,"ix":21,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-25.094,-4.83],[-14.691,-5.955],[-13.004,-4.127],[-6.116,-5.041],[25.094,-5.041],[25.094,5.955]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[113.72,93.01],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 50","np":2,"cix":2,"bm":0,"ix":22,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-21.799,-26.171],[-21.799,13.635],[-20.774,20.008],[16.176,26.171],[21.799,24.503]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[143.443,79.138],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 51","np":2,"cix":2,"bm":0,"ix":23,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[88.626,74.857],[151.806,74.857]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 52","np":2,"cix":2,"bm":0,"ix":24,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[93.653,52.401],[93.653,94.366]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 53","np":2,"cix":2,"bm":0,"ix":25,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1.723,-35.415],[-1.723,-14.469],[0.62,-12.953],[1.723,35.415]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[162.477,159.858],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 54","np":2,"cix":2,"bm":0,"ix":26,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-11.575,3.259],[-0.551,-3.259],[4.821,-3.259],[7.166,-1.191],[9.784,-1.191],[11.575,-3.259]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[155.932,166.01],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 55","np":2,"cix":2,"bm":0,"ix":27,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.489,-23.839],[-6.05,-13.917],[-7.841,-12.401],[-7.841,1.329],[-11.562,10.887],[-11.562,23.84],[11.562,23.84]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.855000035903,0.862999949736,0.877999997606,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[179.069,138.912],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 56","np":2,"cix":2,"bm":0,"ix":28,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey700","cl":"grey700","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-84.172,-14.163],[-87.624,-10.786],[-87.624,-7.25],[-91.245,-3.685],[-94.866,-5.154],[-98.486,-11.792],[-101.705,-10.384],[-105.729,-11.792],[-110.154,-14.163],[-116.994,-11.792],[-121.218,-5.355],[-119.247,-2.337],[-117.598,-2.337],[-116.19,1.083],[-110.959,2.286],[-107.137,3.899],[-97.49,3.899],[-97.49,10.725],[-88.428,11.544],[-86.819,19.59],[-68.714,22.205],[-62.64,26.027],[-55.235,33.068],[-45.78,31.79],[-35.723,31.79],[-22.848,31.79],[-17.818,34.678],[-3.957,38.5],[5.315,37.695],[13.563,34.678],[23.622,33.873],[46.757,36.891],[58.826,36.891],[67.678,33.068],[75.14,30.654],[87.996,32.666],[90.209,31.79],[108.313,29.649],[117.768,25.022],[130.243,25.424],[144.523,25.022],[148.34,20.596],[149.955,15.969],[148.34,10.725],[127.193,-42.264],[-25.865,-48.73],[-69.318,-44.784],[-72.134,-37.519],[-82.394,-31.305]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.376470588235,0.388235294118,0.407843137255,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[308.06,59.651],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 57","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-53.521,-13.307],[-41.048,-20.863],[-32.801,-18.738],[-26.967,-20.863],[-15.902,-15.576],[-11.075,-15.576],[-11.075,-13.307],[4.818,-13.307],[6.83,-15.576],[17.29,-15.576],[20.308,-23.708],[24.532,-22.041],[35.194,-20.863],[45.454,-19.945],[47.264,-15.576],[52.695,-6.064],[46.459,23.708],[42.881,20.101],[34.646,17.883],[-4.626,17.883],[-13.177,20.101],[-23.946,20.101],[-30.387,15.26],[-38.835,16.264],[-49.296,17.271],[-56.009,14.456]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.376470588235,0.388235294118,0.407843137255,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[69.974,127.35],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 61","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".grey800","cl":"grey800","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[-2.851,0.95],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[2.851,-0.95],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-209.239,-23.701],[-197.204,-12.299],[-193.403,-15.149],[-193.403,-18.95],[-181.051,-21.801],[-177.251,-23.701],[-166.482,-23.701],[-157.931,-25.918],[-154.447,-25.918],[-135.761,-25.918],[-131.327,-25.918],[-124.36,-25.918],[-118.658,-25.918],[-110.424,-23.701],[-104.406,-19.108],[-98.389,-12.299],[-88.254,0.49],[-84.77,0],[-84.77,-6.282],[-81.92,-1.531],[-83.351,0],[-84.736,0.49],[-86.024,1.81],[-86.644,2.239],[-81.92,12.262],[-74.427,29.3],[-73.52,32.545],[-69.607,41.517],[-69.607,44.142],[-68.7,45.383],[-66.791,56.121],[-66.791,60.226],[-68.748,61.371],[-68.748,62.564],[-70.322,63.995],[-70.37,65.523],[-72.327,67.146],[-73.615,67.146],[-74.14,68.195],[-75.477,68.195],[-75.477,69.389],[-76.908,70.439],[-77.481,71.059],[-77.481,72.014],[-78.293,72.872],[-76.813,73.445],[-76.67,74.877],[-75.572,75.402],[-75.668,77.788],[-74.904,77.788],[-74.904,81.367],[-74.093,81.367],[-73.854,83.611],[-72.947,84.231],[-72.947,85.52],[-71.754,86.331],[-69.655,86.331],[-64.643,86.331],[-64.023,85.472],[-61.302,85.902],[-61.064,86.331],[-57.485,86.665],[-56.005,88.287],[-56.005,89.815],[-54.287,90.912],[-53.428,90.244],[-52.998,90.912],[-51.614,91.199],[-51.614,92.249],[-49.133,92.249],[-48.751,93.299],[-46.651,93.299],[-45.935,94.253],[-45.076,94.253],[-42.833,96.688],[-40.256,96.688],[-40.256,97.498],[-38.108,97.498],[-37.678,98.501],[-35.817,98.501],[-34.815,99.169],[-34.004,99.169],[-33.622,98.453],[-31.14,98.453],[-31.427,97.642],[-31.904,96.782],[-33.431,96.735],[-33.622,91.58],[-33.097,91.58],[-32.763,92.583],[-31.713,92.44],[-31.14,92.965],[-29.279,92.869],[-29.279,91.676],[-30.138,91.342],[-30.043,89.385],[-30.902,88.669],[-30.949,87.237],[-31.904,86.808],[-30.997,86.092],[-30.854,84.66],[-30.138,84.374],[-30.091,80.556],[-31.045,79.984],[-30.759,76.691],[-29.47,78.313],[-29.279,79.268],[-27.37,80.222],[-26.559,79.888],[-25.89,78.934],[-25.604,77.884],[-24.459,76.357],[-21.882,75.402],[-17.586,74.973],[-14.771,74.734],[-14.771,75.831],[-22.072,77.74],[-23.361,78.122],[-24.268,78.6],[-25.127,79.124],[-25.509,80.174],[-27.036,81.272],[-28.181,81.749],[-29.088,83.229],[-29.088,85.997],[-28.849,87.953],[-27.752,88.287],[-26.177,89.385],[-24.173,88.097],[-23.648,88.097],[-22.502,87.143],[-22.74,86.331],[-23.027,83.372],[-22.12,83.133],[-21.548,83.897],[-21.5,84.518],[-20.88,84.66],[-20.88,85.902],[-20.02,86.188],[-19.734,85.328],[-16.918,85.568],[-16.966,84.708],[-19.114,82.895],[-19.591,82.035],[-19.495,81.272],[-16.441,81.415],[-16.107,80.509],[-13.72,80.509],[-12.862,79.076],[-11.239,79.984],[-10.809,83.849],[-9.473,83.897],[-8.996,84.566],[-6.848,84.852],[-6.085,85.949],[-3.364,86.236],[-3.078,84.756],[-3.698,81.701],[-6.037,79.554],[-6.323,78.504],[-3.603,78.456],[-2.219,78.027],[-0.406,77.359],[0.549,77.74],[2.84,77.645],[4.94,77.645],[6.133,78.027],[8.567,78.6],[9.14,79.458],[11.096,79.458],[11.43,80.413],[13.149,80.413],[13.435,80.986],[14.628,81.033],[14.628,80.413],[15.868,79.936],[15.868,78.934],[16.346,81.272],[18.064,81.32],[18.064,80.222],[17.539,80.174],[17.539,78.074],[18.446,78.552],[19.973,80.031],[21.452,80.079],[21.452,82.704],[20.976,83.42],[20.976,84.518],[19.782,84.804],[19.83,85.71],[22.026,86.188],[22.884,86.999],[24.698,87.047],[25.414,87.953],[27.275,87.953],[30.855,87.953],[31.523,86.999],[32.764,87.047],[32.286,88.335],[31.761,88.956],[32.048,90.436],[36.915,90.818],[37.583,98.787],[39.97,102.366],[42.738,103.368],[44.552,106.185],[54.431,117.018],[58.582,120.216],[67.889,127.518],[73.711,130.429],[85.165,134.294],[88.458,136.013],[91.179,136.013],[97.717,142.026],[98.338,144.89],[104.494,147.849],[107.262,150],[211.975,150],[211.975,-151.69],[-210.962,-153.764]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[223.279,171.151],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 62","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey900","cl":"grey900","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-206,148.684],[206,148.684],[206,-148.684],[-206,-148.684]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[223.279,172.467],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 63","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[101.086,101.086,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.66,0.66],"y":[0,0]},"t":0,"s":[294,294]},{"t":10,"s":[300,300]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.66],"y":[0]},"t":0,"s":[6]},{"t":10,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[98.741,98.741],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[100]},{"t":20,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[64.361,64.36,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.2],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":0,"s":[150,150,100]},{"t":45,"s":[48.034,48.034,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-34.164],[34.165,0],[0,34.165],[-34.165,0]],"o":[[0,34.165],[-34.165,0],[0,-34.164],[34.165,0]],"v":[[61.861,-0.001],[0,61.861],[-61.861,-0.001],[0,-61.861]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.829000016755,0.885999971278,0.955999995213,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[100]},{"t":32,"s":[70]}],"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[64.361,64.361],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-34.164],[34.165,0],[0,34.165],[-34.165,0]],"o":[[0,34.165],[-34.165,0],[0,-34.164],[34.165,0]],"v":[[61.861,-0.001],[0,61.861],[-61.861,-0.001],[0,-61.861]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.552941203117,0.670588254929,0.921568632126,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[50]},{"t":32,"s":[20]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[64.361,64.361],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":585,"st":-15,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"CircleMatte 2","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[82.705,0],[0,-82.705],[-82.705,0],[0,82.705]],"o":[[-82.705,0],[0,82.705],[82.705,0],[0,-82.705]],"v":[[-0.125,-149.938],[-149.875,-0.188],[-0.125,149.562],[149.625,-0.188]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":-1,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[15.4,0],[0,0],[0,15.4],[0,0],[-15.4,0],[0,0],[0,-15.4],[0,0]],"o":[[0,0],[-15.4,0],[0,0],[0,-15.4],[0,0],[15.4,0],[0,0],[0,15.4]],"v":[[228,150],[-238,150],[-266,122],[-266,-122],[-238,-150],[228,-150],[256,-122],[256,122]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1800,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"Approximate_OFF_DT","tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":0,"k":[307.16,307.16,100],"ix":6,"l":2}},"ao":0,"w":117,"h":98,"ip":0,"op":585,"st":-15,"bm":0}],"markers":[{"tm":91,"cm":"","dr":0}]} \ No newline at end of file
diff --git a/PermissionController/res/raw-night/coarse_loc_on.json b/PermissionController/res/raw-night/coarse_loc_on.json
new file mode 100644
index 000000000..b6f098d30
--- /dev/null
+++ b/PermissionController/res/raw-night/coarse_loc_on.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":91,"w":300,"h":300,"nm":"Location_Accuracy_Approximate_ON_DT","ddd":0,"assets":[{"id":"comp_0","nm":"Approximate_ON_DT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Scale Controller","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[58.5,49,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.2],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":15,"s":[90,90,100]},{"t":60,"s":[62,62,100]}],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Highway_Signs","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.029,-0.19],[0,0],[0.041,0.176]],"o":[[-0.042,0.176],[0,0],[-0.03,-0.19],[0,0]],"v":[[-5.894,-0.275],[-6,0.275],[6,0.275],[5.894,-0.275]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.910000011968,0.941000007181,0.995999983245,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[130.584,67.277],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.626,-1.193],[0,0],[-1.626,3.099],[0.158,1.029],[0,0]],"o":[[1.626,3.099],[0,0],[0.626,-1.193],[0,0],[-0.158,1.029]],"v":[[-5.48,-0.218],[-0.001,3.653],[5.479,-0.218],[5.999,-3.653],[-6,-3.653]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[130.583,71.205],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.321,-0.037],[0,0],[1.358,0.037],[0,0],[0.292,-1.237],[0,0]],"o":[[0,0],[-1.358,0.037],[0,0],[-1.321,-0.037],[0,0],[0,0],[-0.292,-1.237]],"v":[[5.065,-1.046],[2.496,0.129],[0,-1.046],[-2.496,0.129],[-5.065,-1.046],[-5.894,1.046],[5.894,1.046]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917999985639,0.263000009574,0.20800000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[130.584,65.956],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.029,-0.19],[0,0],[0.041,0.176]],"o":[[-0.042,0.176],[0,0],[-0.03,-0.19],[0,0]],"v":[[-5.894,-0.275],[-6,0.275],[6,0.275],[5.894,-0.275]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.910000011968,0.941000007181,0.995999983245,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[195.904,70.159],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.626,-1.193],[0,0],[-1.626,3.099],[0.158,1.029],[0,0]],"o":[[1.626,3.099],[0,0],[0.626,-1.193],[0,0],[-0.158,1.029]],"v":[[-5.479,-0.218],[0.001,3.653],[5.48,-0.218],[5.999,-3.653],[-5.999,-3.653]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[195.904,74.086],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":4,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.321,-0.037],[0,0],[1.358,0.037],[0,0],[0.292,-1.237],[0,0]],"o":[[0,0],[-1.358,0.037],[0,0],[-1.321,-0.037],[0,0],[0,0],[-0.292,-1.237]],"v":[[5.065,-1.046],[2.496,0.129],[0,-1.046],[-2.496,0.129],[-5.065,-1.046],[-5.894,1.046],[5.894,1.046]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917999985639,0.263000009574,0.20800000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[195.904,68.837],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":4,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.029,-0.191],[0,0],[0.041,0.176]],"o":[[-0.042,0.176],[0,0],[-0.03,-0.191],[0,0]],"v":[[-5.894,-0.275],[-6,0.275],[6,0.275],[5.894,-0.275]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.910000011968,0.941000007181,0.995999983245,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[210.57,222.357],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 13","np":4,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.626,-1.193],[0,0],[-1.626,3.099],[0.158,1.029],[0,0]],"o":[[1.626,3.099],[0,0],[0.626,-1.193],[0,0],[-0.158,1.029]],"v":[[-5.479,-0.217],[-0.001,3.653],[5.48,-0.217],[5.999,-3.652],[-5.999,-3.652]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[210.57,226.283],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 14","np":4,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.321,-0.037],[0,0],[1.358,0.038],[0,0],[0.292,-1.238],[0,0]],"o":[[0,0],[-1.358,0.038],[0,0],[-1.321,-0.037],[0,0],[0,0],[-0.292,-1.238]],"v":[[5.065,-1.046],[2.496,0.128],[0,-1.046],[-2.496,0.128],[-5.065,-1.046],[-5.894,1.046],[5.894,1.046]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917999985639,0.263000009574,0.20800000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[210.57,221.035],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 15","np":4,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.029,-0.191],[0,0],[0.041,0.177]],"o":[[-0.042,0.177],[0,0],[-0.03,-0.191],[0,0]],"v":[[-5.894,-0.276],[-6,0.275],[6,0.275],[5.894,-0.276]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.910000011968,0.941000007181,0.995999983245,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[190.011,186.54],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 16","np":4,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.626,-1.192],[0,0],[-1.626,3.1],[0.158,1.028],[0,0]],"o":[[1.626,3.1],[0,0],[0.626,-1.192],[0,0],[-0.158,1.028]],"v":[[-5.479,-0.218],[-0.001,3.652],[5.48,-0.218],[5.999,-3.652],[-5.999,-3.652]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[190.01,190.467],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 17","np":4,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.321,-0.036],[0,0],[1.358,0.038],[0,0],[0.292,-1.237],[0,0]],"o":[[0,0],[-1.358,0.038],[0,0],[-1.321,-0.036],[0,0],[0,0],[-0.292,-1.237]],"v":[[5.065,-1.046],[2.496,0.128],[0,-1.046],[-2.496,0.128],[-5.065,-1.046],[-5.894,1.046],[5.894,1.046]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917999985639,0.263000009574,0.20800000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[190.011,185.218],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 18","np":4,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".yellow200","cl":"yellow200","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-10.273,-62.792],[10.273,-19.932],[5.308,43.982],[3.529,62.792]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156862745,0.886274509804,0.576470588235,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[304.691,67.791],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 19","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-69.845,50.02],[-43.615,20.333],[-43.615,-21.96],[-34.261,-28.874],[-24.095,-28.874],[-16.368,-34.974],[-1.728,-31.72],[1.931,-37.821],[7.218,-34.567],[23.079,-42.293],[55.331,-42.293],[69.845,-50.02]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156862745,0.886274509804,0.576470588235,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[373.948,242.314],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 20","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-113.972,-119.335],[-113.972,-89.146],[-110.288,-76.336],[-118.014,-57.426],[-110.288,-39.939],[-93.615,-15.54],[-81.414,-1.306],[-84.668,17.808],[-75.721,29.193],[-63.521,36.921],[-49.288,39.36],[-41.968,48.714],[-28.954,48.714],[-17.568,53.594],[-2.115,58.067],[5.205,65.794],[21.066,68.233],[51.972,97.107],[62.545,99.954],[75.559,99.954],[118.014,119.335]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156862745,0.886274509804,0.576470588235,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[245.421,175.3],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 21","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-214.415,-10.167],[-193.269,2.034],[-180.255,2.034],[-172.122,4.88],[-161.548,-0.406],[-149.349,0.001],[-132.675,-7.32],[-126.575,-5.693],[-113.969,-10.167],[-96.075,-8.133],[-88.755,-2.643],[-80.215,-2.643],[-43.208,-2.643],[-22.062,-6.1],[-13.319,0.407],[-0.61,2.034],[17.384,-2.643],[35.278,-0.406],[50.731,2.034],[53.985,6.913],[73.912,4.88],[86.111,10.167],[114.578,10.167],[150.365,10.167],[159.311,4.88],[214.415,2.034]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156862745,0.886274509804,0.576470588235,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[223.889,101.607],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 22","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-152.296,-34.933],[-152.296,-17.527],[-140.503,-1.668],[-129.523,3.62],[-129.523,10.94],[-120.577,15.413],[-117.729,22.327],[-88.449,34.933],[-76.251,30.867],[-68.117,23.953],[-38.43,27.207],[-25.417,28.833],[-7.93,24.767],[20.943,25.986],[31.924,29.24],[38.837,25.58],[51.443,25.58],[60.391,21.513],[86.01,18.667],[97.804,26.8],[152.297,26.393]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156862745,0.886274509804,0.576470588235,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[304.103,105.308],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 24","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[21.757,-76.408],[21.757,-63.89],[13.214,-63.89],[-14.031,-38.677],[-19.724,-23.223],[-21.757,54.857],[-18.098,63.803],[-21.757,76.409]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156862745,0.886274509804,0.576470588235,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[210.57,177.698],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 25","np":2,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-67.1,-42.533],[-37.413,-29.478],[-34.567,-20.938],[-28.873,-24.191],[-17.08,-23.378],[-5.693,-7.518],[12.2,-3.046],[18.3,5.495],[24.807,9.562],[38.227,11.594],[52.867,19.729],[62.525,21.355],[67.1,29.896],[67.1,42.533]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156862745,0.886274509804,0.576470588235,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[160.753,59.919],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 26","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-139.893,-158.396],[-135.827,-143.349],[-95.566,-100.243],[-75.233,-93.736],[-51.646,-67.303],[-48.8,-54.29],[-35.38,-42.496],[-32.94,-22.57],[-24.807,-18.91],[-10.574,-14.844],[8.947,16.47],[58.56,53.477],[82.147,84.79],[102.074,96.99],[125.66,133.997],[139.893,142.536],[139.893,158.396]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156862745,0.886274509804,0.576470588235,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[243.307,169.317],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 28","np":2,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey300","cl":"grey300","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[31.717,-1.007],[-31.717,1.007]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[287.883,119.11],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 29","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-35.365,-14.212],[-27.159,-14.715],[-22.239,-18.741],[-8.414,-18.741],[6.556,-19.629],[15.02,-18.202],[28.069,-14.212],[28.069,-5.406],[28.069,1.64],[28.069,10.949],[29.704,14.22],[35.239,16.731],[35.365,19.629]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[291.531,123.51],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 30","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-41.561,-23.371],[-37.444,-22.113],[-31.154,-25.384],[-26.499,-26.767],[-21.215,-28.151],[-18.196,-31.05],[-12.41,-31.528],[-8.761,-31.05],[-7.628,-28.906],[9.733,-22.113],[23.067,-5.129],[29.106,-0.14],[37.283,12.608],[40.931,21.004],[41.561,31.528]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[348.112,171.29],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 31","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[4.64,-38.155],[4.64,-8.29],[7.771,-2.101],[6.974,5.21],[2.462,11.432],[-0.966,22.989],[-7.771,38.155]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[251.527,139.762],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 32","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-19.621,11.458],[-23.788,-11.458],[23.788,-11.458]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[259.299,233.54],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 33","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-36.573,-3.452],[3.542,-3.452],[8.492,-1.858],[25.051,-3.452],[31.026,-2.655],[35.293,0.133],[36.573,2.352],[34.013,2.352],[32.887,3.451]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[297.973,269.1],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 34","np":2,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-25.691,-18.223],[-10.328,-18.734],[-5.207,-17.88],[1.281,-18.307],[18.009,-19.077],[25.691,-12.504],[22.789,-10.797],[14.168,0.47],[12.376,5.846],[8.45,13.615],[4.011,19.077]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[307.575,287.115],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 35","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[50.742,46.448],[51.669,43.468],[50.742,37.157],[55.148,32.302],[72.276,31.185],[72.276,5.64],[70.623,-1.526],[70.623,-40.523],[69.383,-42.865],[62.906,-43.554],[56.843,-42.865],[54.224,-44.381],[49.264,-44.381],[45.13,-46.448],[-72.276,-46.448]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[226.967,241.72],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 36","np":2,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-119.509,-44.611],[-97.824,-40.96],[-89.824,-34.688],[-72.741,-36.266],[-66.754,-33.154],[40.537,-34.971],[59.633,-38.882],[68.047,-38.882],[73.387,-37.306],[74.626,-33.154],[77.919,-31.804],[77.919,-26.232],[80.508,-24.928],[89.57,-21.215],[97.823,-16.038],[105.684,-14.257],[108.827,-8.431],[113.844,5.663],[119.508,8.884],[117.654,19.078],[110.284,25.092],[107.048,37.527],[104.562,44.612]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[278.637,267.243],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 37","np":2,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-51.352,2.509],[13.052,3.155],[35.386,-3.155],[51.352,-3.155]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[301.911,213.904],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 38","np":2,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[275.481,202.819],[275.481,222.082]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 39","np":2,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[2.805,-24.131],[-0.446,-14.804],[1.18,18.209],[-2.805,24.131]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[269.292,219.403],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 40","np":2,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-16.325,-7.523],[-4.713,-0.839],[5.806,-0.839],[16.325,7.523]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[261.745,182.35],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 41","np":2,"cix":2,"bm":0,"ix":13,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-52.188,-19.67],[-41.346,-24.51],[-9.628,-12.712],[5.098,-9.312],[20.956,-3.564],[26.135,-4.62],[34.719,-0.671],[41.671,4.326],[52.189,7.729],[46.039,15.452],[46.202,24.509]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[213.259,163.422],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 42","np":2,"cix":2,"bm":0,"ix":14,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[73.548,-6.19],[75.996,7.565],[69.525,24.299],[59.976,26.175],[53.504,28.441],[47.03,33.188],[47.03,39.488],[34.894,32.698],[26.767,21.986],[17.423,17.347],[-1.49,12.605],[-28.757,3.71],[-37.055,-16.252],[-66.354,-16.252],[-66.354,-18.782],[-69.801,-23.38],[-68.077,-26.092],[-70.654,-30.31],[-74.309,-30.31],[-75.996,-39.488]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[230.554,138.453],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 43","np":2,"cix":2,"bm":0,"ix":15,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-68.814,-67.689],[-33.186,-67.127],[-13.566,-64.287],[9.77,-52.647],[17.081,-46.04],[58.129,-44.971],[60.347,-29.873],[60.347,-12.806],[61.785,6.876],[59.395,9.068],[60.347,54.334],[65.44,54.334],[68.814,58.411],[63.612,63.472],[65.581,64.877],[63.612,67.689]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[243.756,235.438],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 44","np":2,"cix":2,"bm":0,"ix":16,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-6.636,-10.36],[-2.642,-10.95],[4.106,-13.762],[4.478,-12.242],[5.933,-6.307],[6.636,13.761]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[170.836,181.51],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 45","np":2,"cix":2,"bm":0,"ix":17,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[150.903,178.874],[176.77,178.874]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 46","np":2,"cix":2,"bm":0,"ix":18,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-46.11,-24.495],[-24.601,-24.495],[-18.978,-22.285],[10.012,-24.495],[26.288,-21.262],[39.924,-19.433],[46.11,-14.795],[41.028,24.495]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[194.482,197.586],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 47","np":2,"cix":2,"bm":0,"ix":19,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[163.403,74.086],[163.403,98.964]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 48","np":2,"cix":2,"bm":0,"ix":20,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[2.298,-13.017],[-2.298,-7.952],[0.038,-1.57],[0.038,13.017]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[138.776,74.953],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 49","np":2,"cix":2,"bm":0,"ix":21,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-25.094,-4.83],[-14.691,-5.955],[-13.004,-4.127],[-6.116,-5.041],[25.094,-5.041],[25.094,5.955]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[113.72,93.01],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 50","np":2,"cix":2,"bm":0,"ix":22,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-21.799,-26.171],[-21.799,13.635],[-20.774,20.008],[16.176,26.171],[21.799,24.503]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[143.443,79.138],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 51","np":2,"cix":2,"bm":0,"ix":23,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[88.626,74.857],[151.806,74.857]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 52","np":2,"cix":2,"bm":0,"ix":24,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[93.653,52.401],[93.653,94.366]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 53","np":2,"cix":2,"bm":0,"ix":25,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1.723,-35.415],[-1.723,-14.469],[0.62,-12.953],[1.723,35.415]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[162.477,159.858],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 54","np":2,"cix":2,"bm":0,"ix":26,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-11.575,3.259],[-0.551,-3.259],[4.821,-3.259],[7.166,-1.191],[9.784,-1.191],[11.575,-3.259]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[155.932,166.01],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 55","np":2,"cix":2,"bm":0,"ix":27,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.489,-23.839],[-6.05,-13.917],[-7.841,-12.401],[-7.841,1.329],[-11.562,10.887],[-11.562,23.84],[11.562,23.84]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[179.069,138.912],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 56","np":2,"cix":2,"bm":0,"ix":28,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".grey700","cl":"grey700","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-84.172,-14.163],[-87.624,-10.786],[-87.624,-7.25],[-91.245,-3.685],[-94.866,-5.154],[-98.486,-11.792],[-101.705,-10.384],[-105.729,-11.792],[-110.154,-14.163],[-116.994,-11.792],[-121.218,-5.355],[-119.247,-2.337],[-117.598,-2.337],[-116.19,1.083],[-110.959,2.286],[-107.137,3.899],[-97.49,3.899],[-97.49,10.725],[-88.428,11.544],[-86.819,19.59],[-68.714,22.205],[-62.64,26.027],[-55.235,33.068],[-45.78,31.79],[-35.723,31.79],[-22.848,31.79],[-17.818,34.678],[-3.957,38.5],[5.315,37.695],[13.563,34.678],[23.622,33.873],[46.757,36.891],[58.826,36.891],[67.678,33.068],[75.14,30.654],[87.996,32.666],[90.209,31.79],[108.313,29.649],[117.768,25.022],[130.243,25.424],[144.523,25.022],[148.34,20.596],[149.955,15.969],[148.34,10.725],[127.193,-42.264],[-25.865,-48.73],[-69.318,-44.784],[-72.134,-37.519],[-82.394,-31.305]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.376470588235,0.388235294118,0.407843137255,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[308.06,59.651],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 57","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-53.521,-13.307],[-41.048,-20.863],[-32.801,-18.738],[-26.967,-20.863],[-15.902,-15.576],[-11.075,-15.576],[-11.075,-13.307],[4.818,-13.307],[6.83,-15.576],[17.29,-15.576],[20.308,-23.708],[24.532,-22.041],[35.194,-20.863],[45.454,-19.945],[47.264,-15.576],[52.695,-6.064],[46.459,23.708],[42.881,20.101],[34.646,17.883],[-4.626,17.883],[-13.177,20.101],[-23.946,20.101],[-30.387,15.26],[-38.835,16.264],[-49.296,17.271],[-56.009,14.456]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.376470588235,0.388235294118,0.407843137255,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[69.974,127.35],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 61","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey800","cl":"grey800","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[-2.851,0.95],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[2.851,-0.95],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-209.239,-23.701],[-197.204,-12.299],[-193.403,-15.149],[-193.403,-18.95],[-181.051,-21.801],[-177.251,-23.701],[-166.482,-23.701],[-157.931,-25.918],[-154.447,-25.918],[-135.761,-25.918],[-131.327,-25.918],[-124.36,-25.918],[-118.658,-25.918],[-110.424,-23.701],[-104.406,-19.108],[-98.389,-12.299],[-88.254,0.49],[-84.77,0],[-84.77,-6.282],[-81.92,-1.531],[-83.351,0],[-84.736,0.49],[-86.024,1.81],[-86.644,2.239],[-81.92,12.262],[-74.427,29.3],[-73.52,32.545],[-69.607,41.517],[-69.607,44.142],[-68.7,45.383],[-66.791,56.121],[-66.791,60.226],[-68.748,61.371],[-68.748,62.564],[-70.322,63.995],[-70.37,65.523],[-72.327,67.146],[-73.615,67.146],[-74.14,68.195],[-75.477,68.195],[-75.477,69.389],[-76.908,70.439],[-77.481,71.059],[-77.481,72.014],[-78.293,72.872],[-76.813,73.445],[-76.67,74.877],[-75.572,75.402],[-75.668,77.788],[-74.904,77.788],[-74.904,81.367],[-74.093,81.367],[-73.854,83.611],[-72.947,84.231],[-72.947,85.52],[-71.754,86.331],[-69.655,86.331],[-64.643,86.331],[-64.023,85.472],[-61.302,85.902],[-61.064,86.331],[-57.485,86.665],[-56.005,88.287],[-56.005,89.815],[-54.287,90.912],[-53.428,90.244],[-52.998,90.912],[-51.614,91.199],[-51.614,92.249],[-49.133,92.249],[-48.751,93.299],[-46.651,93.299],[-45.935,94.253],[-45.076,94.253],[-42.833,96.688],[-40.256,96.688],[-40.256,97.498],[-38.108,97.498],[-37.678,98.501],[-35.817,98.501],[-34.815,99.169],[-34.004,99.169],[-33.622,98.453],[-31.14,98.453],[-31.427,97.642],[-31.904,96.782],[-33.431,96.735],[-33.622,91.58],[-33.097,91.58],[-32.763,92.583],[-31.713,92.44],[-31.14,92.965],[-29.279,92.869],[-29.279,91.676],[-30.138,91.342],[-30.043,89.385],[-30.902,88.669],[-30.949,87.237],[-31.904,86.808],[-30.997,86.092],[-30.854,84.66],[-30.138,84.374],[-30.091,80.556],[-31.045,79.984],[-30.759,76.691],[-29.47,78.313],[-29.279,79.268],[-27.37,80.222],[-26.559,79.888],[-25.89,78.934],[-25.604,77.884],[-24.459,76.357],[-21.882,75.402],[-17.586,74.973],[-14.771,74.734],[-14.771,75.831],[-22.072,77.74],[-23.361,78.122],[-24.268,78.6],[-25.127,79.124],[-25.509,80.174],[-27.036,81.272],[-28.181,81.749],[-29.088,83.229],[-29.088,85.997],[-28.849,87.953],[-27.752,88.287],[-26.177,89.385],[-24.173,88.097],[-23.648,88.097],[-22.502,87.143],[-22.74,86.331],[-23.027,83.372],[-22.12,83.133],[-21.548,83.897],[-21.5,84.518],[-20.88,84.66],[-20.88,85.902],[-20.02,86.188],[-19.734,85.328],[-16.918,85.568],[-16.966,84.708],[-19.114,82.895],[-19.591,82.035],[-19.495,81.272],[-16.441,81.415],[-16.107,80.509],[-13.72,80.509],[-12.862,79.076],[-11.239,79.984],[-10.809,83.849],[-9.473,83.897],[-8.996,84.566],[-6.848,84.852],[-6.085,85.949],[-3.364,86.236],[-3.078,84.756],[-3.698,81.701],[-6.037,79.554],[-6.323,78.504],[-3.603,78.456],[-2.219,78.027],[-0.406,77.359],[0.549,77.74],[2.84,77.645],[4.94,77.645],[6.133,78.027],[8.567,78.6],[9.14,79.458],[11.096,79.458],[11.43,80.413],[13.149,80.413],[13.435,80.986],[14.628,81.033],[14.628,80.413],[15.868,79.936],[15.868,78.934],[16.346,81.272],[18.064,81.32],[18.064,80.222],[17.539,80.174],[17.539,78.074],[18.446,78.552],[19.973,80.031],[21.452,80.079],[21.452,82.704],[20.976,83.42],[20.976,84.518],[19.782,84.804],[19.83,85.71],[22.026,86.188],[22.884,86.999],[24.698,87.047],[25.414,87.953],[27.275,87.953],[30.855,87.953],[31.523,86.999],[32.764,87.047],[32.286,88.335],[31.761,88.956],[32.048,90.436],[36.915,90.818],[37.583,98.787],[39.97,102.366],[42.738,103.368],[44.552,106.185],[54.431,117.018],[58.582,120.216],[67.889,127.518],[73.711,130.429],[85.165,134.294],[88.458,136.013],[91.179,136.013],[97.717,142.026],[98.338,144.89],[104.494,147.849],[107.262,150],[211.975,150],[211.975,-151.69],[-210.962,-153.764]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[223.279,171.151],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 62","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".grey900","cl":"grey900","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-206,148.684],[206,148.684],[206,-148.684],[-206,-148.684]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[223.279,172.467],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 63","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[101.086,101.086,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.34,0.34],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[300,300]},{"t":25,"s":[294,294]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.552941203117,0.670588254929,0.921568632126,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.34],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0]},{"t":25,"s":[6]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[98.741,98.741],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Pale Orange Solid 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[72,72,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Blue Circle Outlines","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":10,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[64.361,64.36,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.2],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":0,"s":[66.714,66.714,100]},{"t":45,"s":[208.333,208.333,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-34.164],[34.165,0],[0,34.165],[-34.165,0]],"o":[[0,34.165],[-34.165,0],[0,-34.164],[34.165,0]],"v":[[61.861,-0.001],[0,61.861],[-61.861,-0.001],[0,-61.861]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.829000016755,0.885999971278,0.955999995213,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[70]},{"t":21,"s":[100]}],"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[64.361,64.361],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-34.164],[34.165,0],[0,34.165],[-34.165,0]],"o":[[0,34.165],[-34.165,0],[0,-34.164],[34.165,0]],"v":[[61.861,-0.001],[0,61.861],[-61.861,-0.001],[0,-61.861]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0,0,0,1]},{"t":21,"s":[0.552941203117,0.670588254929,0.921568632126,1]}],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[20]},{"t":21,"s":[50]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[64.361,64.361],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":585,"st":-15,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"CircleMatte 4","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[82.705,0],[0,-82.705],[-82.705,0],[0,82.705]],"o":[[-82.705,0],[0,82.705],[82.705,0],[0,-82.705]],"v":[[-0.125,-149.938],[-149.875,-0.188],[-0.125,149.562],[149.625,-0.188]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":-1,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[15.4,0],[0,0],[0,15.4],[0,0],[-15.4,0],[0,0],[0,-15.4],[0,0]],"o":[[0,0],[-15.4,0],[0,0],[0,-15.4],[0,0],[15.4,0],[0,0],[0,15.4]],"v":[[228,150],[-238,150],[-266,122],[-266,-122],[-238,-150],[228,-150],[256,-122],[256,122]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1800,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"Approximate_ON_DT","tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":0,"k":[307.2,307.2,100],"ix":6,"l":2}},"ao":0,"w":117,"h":98,"ip":0,"op":585,"st":-15,"bm":0}],"markers":[]} \ No newline at end of file
diff --git a/PermissionController/res/raw-night/fine_loc_off.json b/PermissionController/res/raw-night/fine_loc_off.json
new file mode 100644
index 000000000..559cafa58
--- /dev/null
+++ b/PermissionController/res/raw-night/fine_loc_off.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":91,"w":300,"h":300,"nm":"Location_Accuracy_Exact_OFF_DT","ddd":0,"assets":[{"id":"comp_0","nm":"Exact_OFF_DT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Scale Controller","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[58.5,49,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.2],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":15,"s":[102,102,100]},{"t":60,"s":[80,80,100]}],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Location Pointer Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[58.298,63.254,0],"ix":2,"l":2},"a":{"a":0,"k":[18.25,51.679,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.967,0.967,0.2],"y":[1,1,1]},"o":{"x":[0.499,0.499,0.4],"y":[0,0,0]},"t":24,"s":[54,54,100]},{"t":42,"s":[10,10,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.551,0],[0,-3.55],[3.55,0],[0,3.551]],"o":[[3.55,0],[0,3.551],[-3.551,0],[0,-3.55]],"v":[[0.001,-6.429],[6.428,-0.001],[0.001,6.429],[-6.428,-0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[18.249,18.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[9.952,0],[0,-9.951],[0,0],[0,13.5]],"o":[[-9.952,0],[0,13.5],[0,0],[0,-9.951]],"v":[[0,-25.715],[-18,-7.715],[0,25.715],[18,-7.715]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[18.25,25.965],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":43,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Location bottom Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[58.298,63.254,0],"ix":2,"l":2},"a":{"a":0,"k":[13.432,6.364,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.967,0.967,0.2],"y":[1,1,1]},"o":{"x":[0.499,0.499,0.4],"y":[0,0,0]},"t":24,"s":[54,54,100]},{"t":42,"s":[10,10,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-2.135],[6.037,0],[0,2.134],[-6.038,0]],"o":[[0,2.134],[-6.038,0],[0,-2.135],[6.037,0]],"v":[[10.933,0],[0.001,3.863],[-10.933,0],[0.001,-3.863]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[13.432,6.364],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-2.135],[6.037,0],[0,2.134],[-6.038,0]],"o":[[0,2.134],[-6.038,0],[0,-2.135],[6.037,0]],"v":[[10.933,0],[0.001,3.863],[-10.933,0],[0.001,-3.863]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[13.432,6.364],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":43,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Pins_Blue","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.878],[0,1.37]],"o":[[-1.734,0],[0,1.37],[2.201,-1.878],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.616000007181,0.964999988032,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[24.4,206.353],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 16","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.055],[-2.2,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.201,-1.879],[0,-2.055]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.616000007181,0.964999988032,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[38.555,165.221],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 17","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.201,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.616000007181,0.964999988032,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[49.115,205.645],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 18","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.201,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.616000007181,0.964999988032,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[105.514,213.902],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 19","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.055],[-2.2,-1.878],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.201,-1.878],[0,-2.055]],"v":[[0,-4.128],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.616000007181,0.964999988032,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[171.789,167.995],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 20","np":4,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.733,0],[0,1.371],[2.201,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.616000007181,0.964999988032,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[368.126,111.436],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 21","np":4,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.733,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.616000007181,0.964999988032,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[281.531,116.994],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 22","np":4,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.733,0],[0,-2.055],[-2.2,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.055]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.616000007181,0.964999988032,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[312.438,125.251],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 23","np":4,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.733,0],[0,-2.056],[-2.201,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.128],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.616000007181,0.964999988032,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[329.856,217.762],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 24","np":4,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Pins_Orange","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.201,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[27.703,137.9],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 15","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.733,0],[0,1.371],[2.201,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.744],[0,4.128],[3.303,-0.744]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[381.288,270.794],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 25","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.733,0],[0,1.371],[2.201,-1.879],[0,-2.056]],"v":[[0,-4.128],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[368.126,210.482],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 26","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.733,0],[0,-2.057],[-2.201,-1.878],[0,1.37]],"o":[[-1.734,0],[0,1.37],[2.2,-1.878],[0,-2.057]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[350.754,184.962],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 27","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.201,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[183.575,115.565],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 28","np":4,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".grey300","cl":"grey300","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[65.394,-87.762],[21.956,-25.29],[-65.394,87.762]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[77.34,207.456],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-29.617,35.822],[12.473,-5.331],[29.618,-35.821]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[199.566,278.889],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-8.219,9.823],[8.218,-9.823]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.146,227.853],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-33.868,-25.038],[8.293,9.519],[33.867,25.038]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[209.364,226.554],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.167,15.54],[-19.167,-15.54]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[119.548,75.138],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-72.23,5.545],[32.282,-5.545],[55.773,-5.545],[72.23,5.545]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[387.97,276.339],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":2,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[6.098,-157.973],[9.854,-43.904],[-9.854,53.949],[-8.736,83.862],[-3.121,157.973]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[393.327,169.155],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-82.146,-18.015],[-17.286,18.015],[82.146,18.015]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[364.737,26.721],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":2,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-50.193,59.098],[50.193,-59.098]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.734,59.599],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":2,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-50.193,59.098],[50.193,-59.098]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[108.816,73.718],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 13","np":2,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-50.193,59.098],[50.193,-59.098]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[105.449,70.281],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 14","np":2,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-61.089,79.79],[-10.563,22.215],[30.571,-28.773],[46.604,-61.512],[61.089,-79.79]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[197.779,251.592],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 29","np":2,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.176,-130.71],[-103.059,-67.44],[-30.743,-4.641],[-18.758,22.842],[23.397,30.81],[65.134,54.857],[89.912,66.865],[181.176,130.71]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[252.512,144.213],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 30","np":2,"cix":2,"bm":0,"ix":13,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-197.801,-135.93],[-169.578,-81.272],[-25.091,29.988],[22.053,51.34],[69.798,92.618],[93.582,100.74],[139.02,95.547],[197.801,135.931]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[245.942,149.433],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 31","np":2,"cix":2,"bm":0,"ix":14,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-43.312,-42.235],[22.43,13.494],[43.312,42.235]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[45.812,287.214],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 32","np":2,"cix":2,"bm":0,"ix":15,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[18.949,23.783],[-18.949,-23.783]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[109.621,305.667],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 33","np":2,"cix":2,"bm":0,"ix":16,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-161.26,59.553],[-73.09,134.19],[-18.949,92.406],[161.26,-134.191]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[163.76,147.693],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 34","np":2,"cix":2,"bm":0,"ix":17,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-170.929,-3.155],[-48.146,106.479],[7.347,155.978],[56.846,100.678],[93.971,24.495],[114.081,-34.03],[140.8,-83.029],[163.001,-98.674],[170.928,-155.978]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[176.522,171.15],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 35","np":2,"cix":2,"bm":0,"ix":18,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-128.003,-94.842],[128.003,94.842]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[128.569,230.353],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 36","np":2,"cix":2,"bm":0,"ix":19,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-143.858,-121.852],[-139.604,-101.518],[143.858,121.852]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[169.948,211.078],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 37","np":2,"cix":2,"bm":0,"ix":20,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-101.126,-61.295],[6.382,43.506],[25.329,50.08],[48.533,50.08],[101.126,61.295]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[339.523,72.477],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 38","np":2,"cix":2,"bm":0,"ix":21,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[75.549,33.199],[0.527,16.447],[-24.997,16.447],[-75.549,-33.199]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[358.139,131.247],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 39","np":2,"cix":2,"bm":0,"ix":22,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.267,11.975],[-22.236,-5.401],[-51.24,-5.401],[-56.267,-11.975]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[381.289,156.961],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 40","np":2,"cix":2,"bm":0,"ix":23,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-23.396,-110.585],[23.396,-69.624],[14.115,-1.562],[14.115,110.585]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[301.625,214.61],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 41","np":2,"cix":2,"bm":0,"ix":24,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-152.301,-106.862],[-115.301,-91.911],[68.768,50.786],[98.546,63.161],[152.3,106.862]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[163.44,175.022],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 43","np":2,"cix":2,"bm":0,"ix":25,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[137.091,-155.846],[25.716,1.527],[6.767,17.403],[-27.65,61.101],[-76.956,108.281],[-137.091,155.846]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[205.333,169.349],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 44","np":2,"cix":2,"bm":0,"ix":26,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-56.46,-44.426],[56.46,44.426]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[221.768,59.599],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 45","np":2,"cix":2,"bm":0,"ix":27,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-157.626,-125.059],[157.625,125.059]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[276.914,138.562],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 46","np":2,"cix":2,"bm":0,"ix":28,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[128.583,-155.739],[-82.951,117.438],[-128.583,155.739]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[173.622,164.445],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 47","np":2,"cix":2,"bm":0,"ix":29,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[123.363,-155.846],[-123.363,155.846]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[149.452,169.349],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 48","np":2,"cix":2,"bm":0,"ix":30,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[119.688,-154.492],[-119.689,154.493]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[128.376,167.995],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 49","np":2,"cix":2,"bm":0,"ix":31,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[94.165,-121.947],[-94.165,121.948]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[102.853,137.12],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 50","np":2,"cix":2,"bm":0,"ix":32,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey700","cl":"grey700","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-3.871,-11.834],[12.775,-0.847],[2.691,11.834],[-12.775,-0.336]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.376470588235,0.388235294118,0.407843137255,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[260.038,79.995],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 54","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-35.787,-24.613],[-37.505,-22.753],[-34.63,-21.167],[-31.031,-23.281],[-9.88,-6.238],[-12.139,-3.2],[24.52,24.613],[37.505,7.844],[1.732,-21.035],[3.318,-23.281],[1.924,-24.613]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.376470588235,0.388235294118,0.407843137255,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[231.647,43.549],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 55","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.533,-30.467],[28.951,-30.467],[20.804,-26.143],[14.324,-20.586],[4.618,-16.81],[1.118,-16.23],[-6.173,-7.064],[-37.533,17.139],[-22.607,30.467],[8.069,1.113],[26.699,-16.712]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.376470588235,0.388235294118,0.407843137255,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[150.984,247.163],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 56","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".grey800","cl":"grey800","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-206,150],[206,150],[206,-150],[-206,-150]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.234999997008,0.250999989229,0.263000009574,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[220.851,168.936],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 58","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":3,"nm":"Exact Light Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[64.082,57.55,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[48.646,48.646,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[101.086,101.086,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.66,0.66],"y":[0,0]},"t":0,"s":[294,294]},{"t":10,"s":[300,300]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.552941203117,0.670588254929,0.921568632126,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.66],"y":[0]},"t":0,"s":[6]},{"t":10,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[98.741,98.741],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":1,"nm":"Scale Controller","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,149,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.6],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.8],"y":[0,0,0]},"t":0,"s":[306,306,100]},{"t":45,"s":[240,240,100]}],"ix":6,"l":2}},"ao":0,"sw":117,"sh":98,"sc":"#a77b57","ip":0,"op":585,"st":-15,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"CircleMatte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[82.705,0],[0,-82.705],[-82.705,0],[0,82.705]],"o":[[-82.705,0],[0,82.705],[82.705,0],[0,-82.705]],"v":[[-0.125,-149.938],[-149.875,-0.188],[-0.125,149.562],[149.625,-0.188]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":-1,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[15.4,0],[0,0],[0,15.4],[0,0],[-15.4,0],[0,0],[0,-15.4],[0,0]],"o":[[0,0],[-15.4,0],[0,0],[0,-15.4],[0,0],[15.4,0],[0,0],[0,15.4]],"v":[[228,150],[-238,150],[-266,122],[-266,-122],[-238,-150],[228,-150],[256,-122],[256,122]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1800,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"Exact_OFF_DT","tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":0,"k":[307.2,307.2,100],"ix":6,"l":2}},"ao":0,"w":117,"h":98,"ip":0,"op":585,"st":-15,"bm":0}],"markers":[{"tm":91,"cm":"","dr":0}]} \ No newline at end of file
diff --git a/PermissionController/res/raw-night/fine_loc_on.json b/PermissionController/res/raw-night/fine_loc_on.json
new file mode 100644
index 000000000..7731d7548
--- /dev/null
+++ b/PermissionController/res/raw-night/fine_loc_on.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":91,"w":300,"h":300,"nm":"Location_Accuracy_Exact_ON_DT","ddd":0,"assets":[{"id":"comp_0","nm":"Exact_ON_DT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Scale Controller","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[58.5,49,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.2],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":15,"s":[80,80,100]},{"t":60,"s":[102,102,100]}],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Location Pointer Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[58.298,63.254,0],"ix":2,"l":2},"a":{"a":0,"k":[18.25,51.679,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.552,0.552,0.667],"y":[1,1,1]},"o":{"x":[0.046,0.046,0.333],"y":[0,0,0]},"t":28,"s":[20,20,100]},{"i":{"x":[0.468,0.468,0.667],"y":[1,1,1]},"o":{"x":[0.441,0.441,0.333],"y":[0,0,0]},"t":42,"s":[58,58,100]},{"t":60,"s":[54,54,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.551,0],[0,-3.55],[3.55,0],[0,3.551]],"o":[[3.55,0],[0,3.551],[-3.551,0],[0,-3.55]],"v":[[0.001,-6.429],[6.428,-0.001],[0.001,6.429],[-6.428,-0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[18.249,18.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[9.952,0],[0,-9.951],[0,0],[0,13.5]],"o":[[-9.952,0],[0,13.5],[0,0],[0,-9.951]],"v":[[0,-25.715],[-18,-7.715],[0,25.715],[18,-7.715]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[18.25,25.965],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":28,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Location bottom Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[58.298,63.254,0],"ix":2,"l":2},"a":{"a":0,"k":[13.432,6.364,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.2],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":28,"s":[20,20,100]},{"t":41,"s":[54,54,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-2.135],[6.037,0],[0,2.134],[-6.038,0]],"o":[[0,2.134],[-6.038,0],[0,-2.135],[6.037,0]],"v":[[10.933,0],[0.001,3.863],[-10.933,0],[0.001,-3.863]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[13.432,6.364],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-2.135],[6.037,0],[0,2.134],[-6.038,0]],"o":[[0,2.134],[-6.038,0],[0,-2.135],[6.037,0]],"v":[[10.933,0],[0.001,3.863],[-10.933,0],[0.001,-3.863]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[13.432,6.364],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":28,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Pins_Blue","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.878],[0,1.37]],"o":[[-1.734,0],[0,1.37],[2.201,-1.878],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.616000007181,0.964999988032,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[24.4,206.353],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 16","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.055],[-2.2,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.201,-1.879],[0,-2.055]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.616000007181,0.964999988032,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[38.555,165.221],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 17","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.201,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.616000007181,0.964999988032,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[49.115,205.645],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 18","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.201,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.616000007181,0.964999988032,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[105.514,213.902],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 19","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.055],[-2.2,-1.878],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.201,-1.878],[0,-2.055]],"v":[[0,-4.128],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.616000007181,0.964999988032,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[171.789,167.995],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 20","np":4,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.733,0],[0,1.371],[2.201,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.616000007181,0.964999988032,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[368.126,111.436],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 21","np":4,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.733,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.616000007181,0.964999988032,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[281.531,116.994],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 22","np":4,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.733,0],[0,-2.055],[-2.2,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.055]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.616000007181,0.964999988032,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[312.438,125.251],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 23","np":4,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.733,0],[0,-2.056],[-2.201,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.128],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.616000007181,0.964999988032,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[329.856,217.762],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 24","np":4,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Pins_Orange","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.201,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[27.703,137.9],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 15","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.733,0],[0,1.371],[2.201,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.744],[0,4.128],[3.303,-0.744]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[381.288,270.794],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 25","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.733,0],[0,1.371],[2.201,-1.879],[0,-2.056]],"v":[[0,-4.128],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[368.126,210.482],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 26","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.733,0],[0,-2.057],[-2.201,-1.878],[0,1.37]],"o":[[-1.734,0],[0,1.37],[2.2,-1.878],[0,-2.057]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[350.754,184.962],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 27","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.201,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[183.575,115.565],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 28","np":4,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".grey300","cl":"grey300","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[65.394,-87.762],[21.956,-25.29],[-65.394,87.762]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[77.34,207.456],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-29.617,35.822],[12.473,-5.331],[29.618,-35.821]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[199.566,278.889],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-8.219,9.823],[8.218,-9.823]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.146,227.853],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-33.868,-25.038],[8.293,9.519],[33.867,25.038]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[209.364,226.554],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.167,15.54],[-19.167,-15.54]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[119.548,75.138],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-72.23,5.545],[32.282,-5.545],[55.773,-5.545],[72.23,5.545]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[387.97,276.339],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":2,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[6.098,-157.973],[9.854,-43.904],[-9.854,53.949],[-8.736,83.862],[-3.121,157.973]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[393.327,169.155],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-82.146,-18.015],[-17.286,18.015],[82.146,18.015]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[364.737,26.721],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":2,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-50.193,59.098],[50.193,-59.098]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.734,59.599],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":2,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-50.193,59.098],[50.193,-59.098]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[108.816,73.718],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 13","np":2,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-50.193,59.098],[50.193,-59.098]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[105.449,70.281],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 14","np":2,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-61.089,79.79],[-10.563,22.215],[30.571,-28.773],[46.604,-61.512],[61.089,-79.79]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[197.779,251.592],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 29","np":2,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.176,-130.71],[-103.059,-67.44],[-30.743,-4.641],[-18.758,22.842],[23.397,30.81],[65.134,54.857],[89.912,66.865],[181.176,130.71]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[252.512,144.213],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 30","np":2,"cix":2,"bm":0,"ix":13,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-197.801,-135.93],[-169.578,-81.272],[-25.091,29.988],[22.053,51.34],[69.798,92.618],[93.582,100.74],[139.02,95.547],[197.801,135.931]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[245.942,149.433],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 31","np":2,"cix":2,"bm":0,"ix":14,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-43.312,-42.235],[22.43,13.494],[43.312,42.235]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[45.812,287.214],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 32","np":2,"cix":2,"bm":0,"ix":15,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[18.949,23.783],[-18.949,-23.783]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[109.621,305.667],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 33","np":2,"cix":2,"bm":0,"ix":16,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-161.26,59.553],[-73.09,134.19],[-18.949,92.406],[161.26,-134.191]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[163.76,147.693],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 34","np":2,"cix":2,"bm":0,"ix":17,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-170.929,-3.155],[-48.146,106.479],[7.347,155.978],[56.846,100.678],[93.971,24.495],[114.081,-34.03],[140.8,-83.029],[163.001,-98.674],[170.928,-155.978]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[176.522,171.15],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 35","np":2,"cix":2,"bm":0,"ix":18,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-128.003,-94.842],[128.003,94.842]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[128.569,230.353],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 36","np":2,"cix":2,"bm":0,"ix":19,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-143.858,-121.852],[-139.604,-101.518],[143.858,121.852]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[169.948,211.078],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 37","np":2,"cix":2,"bm":0,"ix":20,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-101.126,-61.295],[6.382,43.506],[25.329,50.08],[48.533,50.08],[101.126,61.295]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[339.523,72.477],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 38","np":2,"cix":2,"bm":0,"ix":21,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[75.549,33.199],[0.527,16.447],[-24.997,16.447],[-75.549,-33.199]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[358.139,131.247],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 39","np":2,"cix":2,"bm":0,"ix":22,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.267,11.975],[-22.236,-5.401],[-51.24,-5.401],[-56.267,-11.975]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[381.289,156.961],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 40","np":2,"cix":2,"bm":0,"ix":23,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-23.396,-110.585],[23.396,-69.624],[14.115,-1.562],[14.115,110.585]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[301.625,214.61],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 41","np":2,"cix":2,"bm":0,"ix":24,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-152.301,-106.862],[-115.301,-91.911],[68.768,50.786],[98.546,63.161],[152.3,106.862]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[163.44,175.022],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 43","np":2,"cix":2,"bm":0,"ix":25,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[137.091,-155.846],[25.716,1.527],[6.767,17.403],[-27.65,61.101],[-76.956,108.281],[-137.091,155.846]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[205.333,169.349],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 44","np":2,"cix":2,"bm":0,"ix":26,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-56.46,-44.426],[56.46,44.426]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[221.768,59.599],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 45","np":2,"cix":2,"bm":0,"ix":27,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-157.626,-125.059],[157.625,125.059]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[276.914,138.562],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 46","np":2,"cix":2,"bm":0,"ix":28,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[128.583,-155.739],[-82.951,117.438],[-128.583,155.739]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[173.622,164.445],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 47","np":2,"cix":2,"bm":0,"ix":29,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[123.363,-155.846],[-123.363,155.846]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[149.452,169.349],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 48","np":2,"cix":2,"bm":0,"ix":30,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[119.688,-154.492],[-119.689,154.493]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[128.376,167.995],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 49","np":2,"cix":2,"bm":0,"ix":31,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[94.165,-121.947],[-94.165,121.948]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[102.853,137.12],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 50","np":2,"cix":2,"bm":0,"ix":32,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[7.927,-159.713],[-0.193,-105.055],[-1.741,54.527],[-7.927,159.714]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[344.164,173.216],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 42","np":2,"cix":2,"bm":0,"ix":33,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-10.143,-7.085],[10.143,7.085]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[89.154,175.08],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":34,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey700","cl":"grey700","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-3.871,-11.834],[12.775,-0.847],[2.691,11.834],[-12.775,-0.336]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.376470588235,0.388235294118,0.407843137255,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[260.038,79.995],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 54","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-35.787,-24.613],[-37.505,-22.753],[-34.63,-21.167],[-31.031,-23.281],[-9.88,-6.238],[-12.139,-3.2],[24.52,24.613],[37.505,7.844],[1.732,-21.035],[3.318,-23.281],[1.924,-24.613]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.376470588235,0.388235294118,0.407843137255,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[231.647,43.549],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 55","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.533,-30.467],[28.951,-30.467],[20.804,-26.143],[14.324,-20.586],[4.618,-16.81],[1.118,-16.23],[-6.173,-7.064],[-37.533,17.139],[-22.607,30.467],[8.069,1.113],[26.699,-16.712]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.376470588235,0.388235294118,0.407843137255,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[150.984,247.163],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 56","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".grey800","cl":"grey800","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-206,150],[206,150],[206,-150],[-206,-150]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.234999997008,0.250999989229,0.263000009574,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[220.851,168.936],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 58","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":3,"nm":"Exact Light Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[64.082,57.55,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[48.646,48.646,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[101.086,101.086,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.34,0.34],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[300,300]},{"t":25,"s":[294,294]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.552941203117,0.670588254929,0.921568632126,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.34],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0]},{"t":25,"s":[6]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[98.741,98.741],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":1,"nm":"Scale Controller","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,149,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.2],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":0,"s":[240,240,100]},{"t":45,"s":[306,306,100]}],"ix":6,"l":2}},"ao":0,"sw":117,"sh":98,"sc":"#a77b57","ip":0,"op":585,"st":-15,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"CircleMatte 3","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[82.705,0],[0,-82.705],[-82.705,0],[0,82.705]],"o":[[-82.705,0],[0,82.705],[82.705,0],[0,-82.705]],"v":[[-0.125,-149.938],[-149.875,-0.188],[-0.125,149.562],[149.625,-0.188]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":-1,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[15.4,0],[0,0],[0,15.4],[0,0],[-15.4,0],[0,0],[0,-15.4],[0,0]],"o":[[0,0],[-15.4,0],[0,0],[0,-15.4],[0,0],[15.4,0],[0,0],[0,15.4]],"v":[[228,150],[-238,150],[-266,122],[-266,-122],[-238,-150],[228,-150],[256,-122],[256,122]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1800,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"Exact_ON_DT","tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":0,"k":[307.2,307.2,100],"ix":6,"l":2}},"ao":0,"w":117,"h":98,"ip":0,"op":585,"st":-15,"bm":0}],"markers":[]} \ No newline at end of file
diff --git a/PermissionController/res/raw/coarse_loc_off.json b/PermissionController/res/raw/coarse_loc_off.json
new file mode 100644
index 000000000..52927c852
--- /dev/null
+++ b/PermissionController/res/raw/coarse_loc_off.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":91,"w":300,"h":300,"nm":"Location_Accuracy_Approximate_OFF_LT","ddd":0,"assets":[{"id":"comp_0","nm":"Approximate_OFF_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Scale Controller","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[58.5,49,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.2],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":15,"s":[62,62,100]},{"t":60,"s":[90,90,100]}],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Highway_Signs","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.029,-0.19],[0,0],[0.041,0.176]],"o":[[-0.042,0.176],[0,0],[-0.03,-0.19],[0,0]],"v":[[-5.894,-0.275],[-6,0.275],[6,0.275],[5.894,-0.275]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.910000011968,0.941000007181,0.995999983245,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[130.584,67.277],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.626,-1.193],[0,0],[-1.626,3.099],[0.158,1.029],[0,0]],"o":[[1.626,3.099],[0,0],[0.626,-1.193],[0,0],[-0.158,1.029]],"v":[[-5.48,-0.218],[-0.001,3.653],[5.479,-0.218],[5.999,-3.653],[-6,-3.653]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[130.583,71.205],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.321,-0.037],[0,0],[1.358,0.037],[0,0],[0.292,-1.237],[0,0]],"o":[[0,0],[-1.358,0.037],[0,0],[-1.321,-0.037],[0,0],[0,0],[-0.292,-1.237]],"v":[[5.065,-1.046],[2.496,0.129],[0,-1.046],[-2.496,0.129],[-5.065,-1.046],[-5.894,1.046],[5.894,1.046]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917999985639,0.263000009574,0.20800000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[130.584,65.956],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.029,-0.19],[0,0],[0.041,0.176]],"o":[[-0.042,0.176],[0,0],[-0.03,-0.19],[0,0]],"v":[[-5.894,-0.275],[-6,0.275],[6,0.275],[5.894,-0.275]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.910000011968,0.941000007181,0.995999983245,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[195.904,70.159],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.626,-1.193],[0,0],[-1.626,3.099],[0.158,1.029],[0,0]],"o":[[1.626,3.099],[0,0],[0.626,-1.193],[0,0],[-0.158,1.029]],"v":[[-5.479,-0.218],[0.001,3.653],[5.48,-0.218],[5.999,-3.653],[-5.999,-3.653]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[195.904,74.086],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":4,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.321,-0.037],[0,0],[1.358,0.037],[0,0],[0.292,-1.237],[0,0]],"o":[[0,0],[-1.358,0.037],[0,0],[-1.321,-0.037],[0,0],[0,0],[-0.292,-1.237]],"v":[[5.065,-1.046],[2.496,0.129],[0,-1.046],[-2.496,0.129],[-5.065,-1.046],[-5.894,1.046],[5.894,1.046]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917999985639,0.263000009574,0.20800000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[195.904,68.837],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":4,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.029,-0.191],[0,0],[0.041,0.176]],"o":[[-0.042,0.176],[0,0],[-0.03,-0.191],[0,0]],"v":[[-5.894,-0.275],[-6,0.275],[6,0.275],[5.894,-0.275]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.910000011968,0.941000007181,0.995999983245,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[210.57,222.357],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 13","np":4,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.626,-1.193],[0,0],[-1.626,3.099],[0.158,1.029],[0,0]],"o":[[1.626,3.099],[0,0],[0.626,-1.193],[0,0],[-0.158,1.029]],"v":[[-5.479,-0.217],[-0.001,3.653],[5.48,-0.217],[5.999,-3.652],[-5.999,-3.652]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[210.57,226.283],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 14","np":4,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.321,-0.037],[0,0],[1.358,0.038],[0,0],[0.292,-1.238],[0,0]],"o":[[0,0],[-1.358,0.038],[0,0],[-1.321,-0.037],[0,0],[0,0],[-0.292,-1.238]],"v":[[5.065,-1.046],[2.496,0.128],[0,-1.046],[-2.496,0.128],[-5.065,-1.046],[-5.894,1.046],[5.894,1.046]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917999985639,0.263000009574,0.20800000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[210.57,221.035],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 15","np":4,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.029,-0.191],[0,0],[0.041,0.177]],"o":[[-0.042,0.177],[0,0],[-0.03,-0.191],[0,0]],"v":[[-5.894,-0.276],[-6,0.275],[6,0.275],[5.894,-0.276]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.910000011968,0.941000007181,0.995999983245,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[190.011,186.54],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 16","np":4,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.626,-1.192],[0,0],[-1.626,3.1],[0.158,1.028],[0,0]],"o":[[1.626,3.1],[0,0],[0.626,-1.192],[0,0],[-0.158,1.028]],"v":[[-5.479,-0.218],[-0.001,3.652],[5.48,-0.218],[5.999,-3.652],[-5.999,-3.652]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[190.01,190.467],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 17","np":4,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.321,-0.036],[0,0],[1.358,0.038],[0,0],[0.292,-1.237],[0,0]],"o":[[0,0],[-1.358,0.038],[0,0],[-1.321,-0.036],[0,0],[0,0],[-0.292,-1.237]],"v":[[5.065,-1.046],[2.496,0.128],[0,-1.046],[-2.496,0.128],[-5.065,-1.046],[-5.894,1.046],[5.894,1.046]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917999985639,0.263000009574,0.20800000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[190.011,185.218],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 18","np":4,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".yellow500","cl":"yellow500","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-10.273,-62.792],[10.273,-19.932],[5.308,43.982],[3.529,62.792]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.98431372549,0.737254901961,0.01568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[304.691,67.791],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 19","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-69.845,50.02],[-43.615,20.333],[-43.615,-21.96],[-34.261,-28.874],[-24.095,-28.874],[-16.368,-34.974],[-1.728,-31.72],[1.931,-37.821],[7.218,-34.567],[23.079,-42.293],[55.331,-42.293],[69.845,-50.02]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.98431372549,0.737254901961,0.01568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[373.948,242.314],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 20","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-113.972,-119.335],[-113.972,-89.146],[-110.288,-76.336],[-118.014,-57.426],[-110.288,-39.939],[-93.615,-15.54],[-81.414,-1.306],[-84.668,17.808],[-75.721,29.193],[-63.521,36.921],[-49.288,39.36],[-41.968,48.714],[-28.954,48.714],[-17.568,53.594],[-2.115,58.067],[5.205,65.794],[21.066,68.233],[51.972,97.107],[62.545,99.954],[75.559,99.954],[118.014,119.335]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.98431372549,0.737254901961,0.01568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[245.421,175.3],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 21","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-214.415,-10.167],[-193.269,2.034],[-180.255,2.034],[-172.122,4.88],[-161.548,-0.406],[-149.349,0.001],[-132.675,-7.32],[-126.575,-5.693],[-113.969,-10.167],[-96.075,-8.133],[-88.755,-2.643],[-80.215,-2.643],[-43.208,-2.643],[-22.062,-6.1],[-13.319,0.407],[-0.61,2.034],[17.384,-2.643],[35.278,-0.406],[50.731,2.034],[53.985,6.913],[73.912,4.88],[86.111,10.167],[114.578,10.167],[150.365,10.167],[159.311,4.88],[214.415,2.034]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.98431372549,0.737254901961,0.01568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[223.889,101.607],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 22","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-152.296,-34.933],[-152.296,-17.527],[-140.503,-1.668],[-129.523,3.62],[-129.523,10.94],[-120.577,15.413],[-117.729,22.327],[-88.449,34.933],[-76.251,30.867],[-68.117,23.953],[-38.43,27.207],[-25.417,28.833],[-7.93,24.767],[20.943,25.986],[31.924,29.24],[38.837,25.58],[51.443,25.58],[60.391,21.513],[86.01,18.667],[97.804,26.8],[152.297,26.393]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.98431372549,0.737254901961,0.01568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[304.103,105.308],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 24","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[21.757,-76.408],[21.757,-63.89],[13.214,-63.89],[-14.031,-38.677],[-19.724,-23.223],[-21.757,54.857],[-18.098,63.803],[-21.757,76.409]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.98431372549,0.737254901961,0.01568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[210.57,177.698],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 25","np":2,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-67.1,-42.533],[-37.413,-29.478],[-34.567,-20.938],[-28.873,-24.191],[-17.08,-23.378],[-5.693,-7.518],[12.2,-3.046],[18.3,5.495],[24.807,9.562],[38.227,11.594],[52.867,19.729],[62.525,21.355],[67.1,29.896],[67.1,42.533]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.98431372549,0.737254901961,0.01568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[160.753,59.919],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 26","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-139.893,-158.396],[-135.827,-143.349],[-95.566,-100.243],[-75.233,-93.736],[-51.646,-67.303],[-48.8,-54.29],[-35.38,-42.496],[-32.94,-22.57],[-24.807,-18.91],[-10.574,-14.844],[8.947,16.47],[58.56,53.477],[82.147,84.79],[102.074,96.99],[125.66,133.997],[139.893,142.536],[139.893,158.396]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.98431372549,0.737254901961,0.01568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[243.307,169.317],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 28","np":2,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".grey500","cl":"grey500","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[31.717,-1.007],[-31.717,1.007]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[287.883,119.11],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 29","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-35.365,-14.212],[-27.159,-14.715],[-22.239,-18.741],[-8.414,-18.741],[6.556,-19.629],[15.02,-18.202],[28.069,-14.212],[28.069,-5.406],[28.069,1.64],[28.069,10.949],[29.704,14.22],[35.239,16.731],[35.365,19.629]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[291.531,123.51],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 30","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-41.561,-23.371],[-37.444,-22.113],[-31.154,-25.384],[-26.499,-26.767],[-21.215,-28.151],[-18.196,-31.05],[-12.41,-31.528],[-8.761,-31.05],[-7.628,-28.906],[9.733,-22.113],[23.067,-5.129],[29.106,-0.14],[37.283,12.608],[40.931,21.004],[41.561,31.528]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[348.112,171.29],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 31","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[4.64,-38.155],[4.64,-8.29],[7.771,-2.101],[6.974,5.21],[2.462,11.432],[-0.966,22.989],[-7.771,38.155]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[251.527,139.762],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 32","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-19.621,11.458],[-23.788,-11.458],[23.788,-11.458]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[259.299,233.54],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 33","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-36.573,-3.452],[3.542,-3.452],[8.492,-1.858],[25.051,-3.452],[31.026,-2.655],[35.293,0.133],[36.573,2.352],[34.013,2.352],[32.887,3.451]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[297.973,269.1],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 34","np":2,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-25.691,-18.223],[-10.328,-18.734],[-5.207,-17.88],[1.281,-18.307],[18.009,-19.077],[25.691,-12.504],[22.789,-10.797],[14.168,0.47],[12.376,5.846],[8.45,13.615],[4.011,19.077]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[307.575,287.115],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 35","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[50.742,46.448],[51.669,43.468],[50.742,37.157],[55.148,32.302],[72.276,31.185],[72.276,5.64],[70.623,-1.526],[70.623,-40.523],[69.383,-42.865],[62.906,-43.554],[56.843,-42.865],[54.224,-44.381],[49.264,-44.381],[45.13,-46.448],[-72.276,-46.448]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[226.967,241.72],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 36","np":2,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-119.509,-44.611],[-97.824,-40.96],[-89.824,-34.688],[-72.741,-36.266],[-66.754,-33.154],[40.537,-34.971],[59.633,-38.882],[68.047,-38.882],[73.387,-37.306],[74.626,-33.154],[77.919,-31.804],[77.919,-26.232],[80.508,-24.928],[89.57,-21.215],[97.823,-16.038],[105.684,-14.257],[108.827,-8.431],[113.844,5.663],[119.508,8.884],[117.654,19.078],[110.284,25.092],[107.048,37.527],[104.562,44.612]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[278.637,267.243],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 37","np":2,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-51.352,2.509],[13.052,3.155],[35.386,-3.155],[51.352,-3.155]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[301.911,213.904],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 38","np":2,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[275.481,202.819],[275.481,222.082]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 39","np":2,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[2.805,-24.131],[-0.446,-14.804],[1.18,18.209],[-2.805,24.131]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[269.292,219.403],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 40","np":2,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-16.325,-7.523],[-4.713,-0.839],[5.806,-0.839],[16.325,7.523]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[261.745,182.35],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 41","np":2,"cix":2,"bm":0,"ix":13,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-52.188,-19.67],[-41.346,-24.51],[-9.628,-12.712],[5.098,-9.312],[20.956,-3.564],[26.135,-4.62],[34.719,-0.671],[41.671,4.326],[52.189,7.729],[46.039,15.452],[46.202,24.509]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[213.259,163.422],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 42","np":2,"cix":2,"bm":0,"ix":14,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[73.548,-6.19],[75.996,7.565],[69.525,24.299],[59.976,26.175],[53.504,28.441],[47.03,33.188],[47.03,39.488],[34.894,32.698],[26.767,21.986],[17.423,17.347],[-1.49,12.605],[-28.757,3.71],[-37.055,-16.252],[-66.354,-16.252],[-66.354,-18.782],[-69.801,-23.38],[-68.077,-26.092],[-70.654,-30.31],[-74.309,-30.31],[-75.996,-39.488]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[230.554,138.453],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 43","np":2,"cix":2,"bm":0,"ix":15,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-68.814,-67.689],[-33.186,-67.127],[-13.566,-64.287],[9.77,-52.647],[17.081,-46.04],[58.129,-44.971],[60.347,-29.873],[60.347,-12.806],[61.785,6.876],[59.395,9.068],[60.347,54.334],[65.44,54.334],[68.814,58.411],[63.612,63.472],[65.581,64.877],[63.612,67.689]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[243.756,235.438],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 44","np":2,"cix":2,"bm":0,"ix":16,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-6.636,-10.36],[-2.642,-10.95],[4.106,-13.762],[4.478,-12.242],[5.933,-6.307],[6.636,13.761]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[170.836,181.51],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 45","np":2,"cix":2,"bm":0,"ix":17,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[150.903,178.874],[176.77,178.874]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 46","np":2,"cix":2,"bm":0,"ix":18,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-46.11,-24.495],[-24.601,-24.495],[-18.978,-22.285],[10.012,-24.495],[26.288,-21.262],[39.924,-19.433],[46.11,-14.795],[41.028,24.495]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[194.482,197.586],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 47","np":2,"cix":2,"bm":0,"ix":19,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[163.403,74.086],[163.403,98.964]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 48","np":2,"cix":2,"bm":0,"ix":20,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[2.298,-13.017],[-2.298,-7.952],[0.038,-1.57],[0.038,13.017]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[138.776,74.953],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 49","np":2,"cix":2,"bm":0,"ix":21,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-25.094,-4.83],[-14.691,-5.955],[-13.004,-4.127],[-6.116,-5.041],[25.094,-5.041],[25.094,5.955]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[113.72,93.01],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 50","np":2,"cix":2,"bm":0,"ix":22,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-21.799,-26.171],[-21.799,13.635],[-20.774,20.008],[16.176,26.171],[21.799,24.503]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[143.443,79.138],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 51","np":2,"cix":2,"bm":0,"ix":23,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[88.626,74.857],[151.806,74.857]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 52","np":2,"cix":2,"bm":0,"ix":24,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[93.653,52.401],[93.653,94.366]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 53","np":2,"cix":2,"bm":0,"ix":25,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1.723,-35.415],[-1.723,-14.469],[0.62,-12.953],[1.723,35.415]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[162.477,159.858],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 54","np":2,"cix":2,"bm":0,"ix":26,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-11.575,3.259],[-0.551,-3.259],[4.821,-3.259],[7.166,-1.191],[9.784,-1.191],[11.575,-3.259]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[155.932,166.01],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 55","np":2,"cix":2,"bm":0,"ix":27,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.489,-23.839],[-6.05,-13.917],[-7.841,-12.401],[-7.841,1.329],[-11.562,10.887],[-11.562,23.84],[11.562,23.84]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[179.069,138.912],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 56","np":2,"cix":2,"bm":0,"ix":28,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".green100","cl":"green100","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-84.172,-14.163],[-87.624,-10.786],[-87.624,-7.25],[-91.245,-3.685],[-94.866,-5.154],[-98.486,-11.792],[-101.705,-10.384],[-105.729,-11.792],[-110.154,-14.163],[-116.994,-11.792],[-121.218,-5.355],[-119.247,-2.337],[-117.598,-2.337],[-116.19,1.083],[-110.959,2.286],[-107.137,3.899],[-97.49,3.899],[-97.49,10.725],[-88.428,11.544],[-86.819,19.59],[-68.714,22.205],[-62.64,26.027],[-55.235,33.068],[-45.78,31.79],[-35.723,31.79],[-22.848,31.79],[-17.818,34.678],[-3.957,38.5],[5.315,37.695],[13.563,34.678],[23.622,33.873],[46.757,36.891],[58.826,36.891],[67.678,33.068],[75.14,30.654],[87.996,32.666],[90.209,31.79],[108.313,29.649],[117.768,25.022],[130.243,25.424],[144.523,25.022],[148.34,20.596],[149.955,15.969],[148.34,10.725],[127.193,-42.264],[-25.865,-48.73],[-69.318,-44.784],[-72.134,-37.519],[-82.394,-31.305]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[308.06,59.651],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 57","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-53.521,-13.307],[-41.048,-20.863],[-32.801,-18.738],[-26.967,-20.863],[-15.902,-15.576],[-11.075,-15.576],[-11.075,-13.307],[4.818,-13.307],[6.83,-15.576],[17.29,-15.576],[20.308,-23.708],[24.532,-22.041],[35.194,-20.863],[45.454,-19.945],[47.264,-15.576],[52.695,-6.064],[46.459,23.708],[42.881,20.101],[34.646,17.883],[-4.626,17.883],[-13.177,20.101],[-23.946,20.101],[-30.387,15.26],[-38.835,16.264],[-49.296,17.271],[-56.009,14.456]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[69.974,127.35],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 61","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".grey100","cl":"grey100","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[-2.851,0.95],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[2.851,-0.95],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-209.239,-23.701],[-197.204,-12.299],[-193.403,-15.149],[-193.403,-18.95],[-181.051,-21.801],[-177.251,-23.701],[-166.482,-23.701],[-157.931,-25.918],[-154.447,-25.918],[-135.761,-25.918],[-131.327,-25.918],[-124.36,-25.918],[-118.658,-25.918],[-110.424,-23.701],[-104.406,-19.108],[-98.389,-12.299],[-88.254,0.49],[-84.77,0],[-84.77,-6.282],[-81.92,-1.531],[-83.351,0],[-84.736,0.49],[-86.024,1.81],[-86.644,2.239],[-81.92,12.262],[-74.427,29.3],[-73.52,32.545],[-69.607,41.517],[-69.607,44.142],[-68.7,45.383],[-66.791,56.121],[-66.791,60.226],[-68.748,61.371],[-68.748,62.564],[-70.322,63.995],[-70.37,65.523],[-72.327,67.146],[-73.615,67.146],[-74.14,68.195],[-75.477,68.195],[-75.477,69.389],[-76.908,70.439],[-77.481,71.059],[-77.481,72.014],[-78.293,72.872],[-76.813,73.445],[-76.67,74.877],[-75.572,75.402],[-75.668,77.788],[-74.904,77.788],[-74.904,81.367],[-74.093,81.367],[-73.854,83.611],[-72.947,84.231],[-72.947,85.52],[-71.754,86.331],[-69.655,86.331],[-64.643,86.331],[-64.023,85.472],[-61.302,85.902],[-61.064,86.331],[-57.485,86.665],[-56.005,88.287],[-56.005,89.815],[-54.287,90.912],[-53.428,90.244],[-52.998,90.912],[-51.614,91.199],[-51.614,92.249],[-49.133,92.249],[-48.751,93.299],[-46.651,93.299],[-45.935,94.253],[-45.076,94.253],[-42.833,96.688],[-40.256,96.688],[-40.256,97.498],[-38.108,97.498],[-37.678,98.501],[-35.817,98.501],[-34.815,99.169],[-34.004,99.169],[-33.622,98.453],[-31.14,98.453],[-31.427,97.642],[-31.904,96.782],[-33.431,96.735],[-33.622,91.58],[-33.097,91.58],[-32.763,92.583],[-31.713,92.44],[-31.14,92.965],[-29.279,92.869],[-29.279,91.676],[-30.138,91.342],[-30.043,89.385],[-30.902,88.669],[-30.949,87.237],[-31.904,86.808],[-30.997,86.092],[-30.854,84.66],[-30.138,84.374],[-30.091,80.556],[-31.045,79.984],[-30.759,76.691],[-29.47,78.313],[-29.279,79.268],[-27.37,80.222],[-26.559,79.888],[-25.89,78.934],[-25.604,77.884],[-24.459,76.357],[-21.882,75.402],[-17.586,74.973],[-14.771,74.734],[-14.771,75.831],[-22.072,77.74],[-23.361,78.122],[-24.268,78.6],[-25.127,79.124],[-25.509,80.174],[-27.036,81.272],[-28.181,81.749],[-29.088,83.229],[-29.088,85.997],[-28.849,87.953],[-27.752,88.287],[-26.177,89.385],[-24.173,88.097],[-23.648,88.097],[-22.502,87.143],[-22.74,86.331],[-23.027,83.372],[-22.12,83.133],[-21.548,83.897],[-21.5,84.518],[-20.88,84.66],[-20.88,85.902],[-20.02,86.188],[-19.734,85.328],[-16.918,85.568],[-16.966,84.708],[-19.114,82.895],[-19.591,82.035],[-19.495,81.272],[-16.441,81.415],[-16.107,80.509],[-13.72,80.509],[-12.862,79.076],[-11.239,79.984],[-10.809,83.849],[-9.473,83.897],[-8.996,84.566],[-6.848,84.852],[-6.085,85.949],[-3.364,86.236],[-3.078,84.756],[-3.698,81.701],[-6.037,79.554],[-6.323,78.504],[-3.603,78.456],[-2.219,78.027],[-0.406,77.359],[0.549,77.74],[2.84,77.645],[4.94,77.645],[6.133,78.027],[8.567,78.6],[9.14,79.458],[11.096,79.458],[11.43,80.413],[13.149,80.413],[13.435,80.986],[14.628,81.033],[14.628,80.413],[15.868,79.936],[15.868,78.934],[16.346,81.272],[18.064,81.32],[18.064,80.222],[17.539,80.174],[17.539,78.074],[18.446,78.552],[19.973,80.031],[21.452,80.079],[21.452,82.704],[20.976,83.42],[20.976,84.518],[19.782,84.804],[19.83,85.71],[22.026,86.188],[22.884,86.999],[24.698,87.047],[25.414,87.953],[27.275,87.953],[30.855,87.953],[31.523,86.999],[32.764,87.047],[32.286,88.335],[31.761,88.956],[32.048,90.436],[36.915,90.818],[37.583,98.787],[39.97,102.366],[42.738,103.368],[44.552,106.185],[54.431,117.018],[58.582,120.216],[67.889,127.518],[73.711,130.429],[85.165,134.294],[88.458,136.013],[91.179,136.013],[97.717,142.026],[98.338,144.89],[104.494,147.849],[107.262,150],[211.975,150],[211.975,-151.69],[-210.962,-153.764]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019607843,0.952941176471,0.956862745098,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[223.279,171.151],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 62","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-206,148.684],[206,148.684],[206,-148.684],[-206,-148.684]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[223.279,172.467],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 63","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue900","cl":"blue900","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[101.086,101.086,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.66,0.66],"y":[0,0]},"t":0,"s":[294,294]},{"t":10,"s":[300,300]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.66],"y":[0]},"t":0,"s":[6]},{"t":10,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[98.741,98.741],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue900","cl":"blue900","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[100]},{"t":20,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[64.361,64.36,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.2],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":0,"s":[150,150,100]},{"t":45,"s":[48.034,48.034,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-34.164],[34.165,0],[0,34.165],[-34.165,0]],"o":[[0,34.165],[-34.165,0],[0,-34.164],[34.165,0]],"v":[[61.861,-0.001],[0,61.861],[-61.861,-0.001],[0,-61.861]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.829000016755,0.885999971278,0.955999995213,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[100]},{"t":32,"s":[70]}],"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[64.361,64.361],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-34.164],[34.165,0],[0,34.165],[-34.165,0]],"o":[[0,34.165],[-34.165,0],[0,-34.164],[34.165,0]],"v":[[61.861,-0.001],[0,61.861],[-61.861,-0.001],[0,-61.861]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[50]},{"t":32,"s":[20]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[64.361,64.361],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":585,"st":-15,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"CircleMatte 2","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[82.705,0],[0,-82.705],[-82.705,0],[0,82.705]],"o":[[-82.705,0],[0,82.705],[82.705,0],[0,-82.705]],"v":[[-0.125,-149.938],[-149.875,-0.188],[-0.125,149.562],[149.625,-0.188]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":-1,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[15.4,0],[0,0],[0,15.4],[0,0],[-15.4,0],[0,0],[0,-15.4],[0,0]],"o":[[0,0],[-15.4,0],[0,0],[0,-15.4],[0,0],[15.4,0],[0,0],[0,15.4]],"v":[[228,150],[-238,150],[-266,122],[-266,-122],[-238,-150],[228,-150],[256,-122],[256,122]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1800,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"Approximate_OFF_LT","tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":0,"k":[307.2,307.2,100],"ix":6,"l":2}},"ao":0,"w":117,"h":98,"ip":0,"op":585,"st":-15,"bm":0}],"markers":[{"tm":91,"cm":"","dr":0}]} \ No newline at end of file
diff --git a/PermissionController/res/raw/coarse_loc_on.json b/PermissionController/res/raw/coarse_loc_on.json
new file mode 100644
index 000000000..2be289c67
--- /dev/null
+++ b/PermissionController/res/raw/coarse_loc_on.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":91,"w":300,"h":300,"nm":"Location_Accuracy_Approximate_ON_LT","ddd":0,"assets":[{"id":"comp_0","nm":"Approximate_ON_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Scale Controller","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[58.5,49,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.2],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":15,"s":[90,90,100]},{"t":60,"s":[62,62,100]}],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Highway_Signs","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.029,-0.19],[0,0],[0.041,0.176]],"o":[[-0.042,0.176],[0,0],[-0.03,-0.19],[0,0]],"v":[[-5.894,-0.275],[-6,0.275],[6,0.275],[5.894,-0.275]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.910000011968,0.941000007181,0.995999983245,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[130.584,67.277],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.626,-1.193],[0,0],[-1.626,3.099],[0.158,1.029],[0,0]],"o":[[1.626,3.099],[0,0],[0.626,-1.193],[0,0],[-0.158,1.029]],"v":[[-5.48,-0.218],[-0.001,3.653],[5.479,-0.218],[5.999,-3.653],[-6,-3.653]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[130.583,71.205],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.321,-0.037],[0,0],[1.358,0.037],[0,0],[0.292,-1.237],[0,0]],"o":[[0,0],[-1.358,0.037],[0,0],[-1.321,-0.037],[0,0],[0,0],[-0.292,-1.237]],"v":[[5.065,-1.046],[2.496,0.129],[0,-1.046],[-2.496,0.129],[-5.065,-1.046],[-5.894,1.046],[5.894,1.046]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917999985639,0.263000009574,0.20800000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[130.584,65.956],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.029,-0.19],[0,0],[0.041,0.176]],"o":[[-0.042,0.176],[0,0],[-0.03,-0.19],[0,0]],"v":[[-5.894,-0.275],[-6,0.275],[6,0.275],[5.894,-0.275]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.910000011968,0.941000007181,0.995999983245,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[195.904,70.159],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.626,-1.193],[0,0],[-1.626,3.099],[0.158,1.029],[0,0]],"o":[[1.626,3.099],[0,0],[0.626,-1.193],[0,0],[-0.158,1.029]],"v":[[-5.479,-0.218],[0.001,3.653],[5.48,-0.218],[5.999,-3.653],[-5.999,-3.653]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[195.904,74.086],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":4,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.321,-0.037],[0,0],[1.358,0.037],[0,0],[0.292,-1.237],[0,0]],"o":[[0,0],[-1.358,0.037],[0,0],[-1.321,-0.037],[0,0],[0,0],[-0.292,-1.237]],"v":[[5.065,-1.046],[2.496,0.129],[0,-1.046],[-2.496,0.129],[-5.065,-1.046],[-5.894,1.046],[5.894,1.046]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917999985639,0.263000009574,0.20800000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[195.904,68.837],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":4,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.029,-0.191],[0,0],[0.041,0.176]],"o":[[-0.042,0.176],[0,0],[-0.03,-0.191],[0,0]],"v":[[-5.894,-0.275],[-6,0.275],[6,0.275],[5.894,-0.275]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.910000011968,0.941000007181,0.995999983245,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[210.57,222.357],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 13","np":4,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.626,-1.193],[0,0],[-1.626,3.099],[0.158,1.029],[0,0]],"o":[[1.626,3.099],[0,0],[0.626,-1.193],[0,0],[-0.158,1.029]],"v":[[-5.479,-0.217],[-0.001,3.653],[5.48,-0.217],[5.999,-3.652],[-5.999,-3.652]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[210.57,226.283],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 14","np":4,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.321,-0.037],[0,0],[1.358,0.038],[0,0],[0.292,-1.238],[0,0]],"o":[[0,0],[-1.358,0.038],[0,0],[-1.321,-0.037],[0,0],[0,0],[-0.292,-1.238]],"v":[[5.065,-1.046],[2.496,0.128],[0,-1.046],[-2.496,0.128],[-5.065,-1.046],[-5.894,1.046],[5.894,1.046]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917999985639,0.263000009574,0.20800000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[210.57,221.035],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 15","np":4,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.029,-0.191],[0,0],[0.041,0.177]],"o":[[-0.042,0.177],[0,0],[-0.03,-0.191],[0,0]],"v":[[-5.894,-0.276],[-6,0.275],[6,0.275],[5.894,-0.276]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.910000011968,0.941000007181,0.995999983245,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[190.011,186.54],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 16","np":4,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.626,-1.192],[0,0],[-1.626,3.1],[0.158,1.028],[0,0]],"o":[[1.626,3.1],[0,0],[0.626,-1.192],[0,0],[-0.158,1.028]],"v":[[-5.479,-0.218],[-0.001,3.652],[5.48,-0.218],[5.999,-3.652],[-5.999,-3.652]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258999992819,0.522000002394,0.957000014361,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[190.01,190.467],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 17","np":4,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.321,-0.036],[0,0],[1.358,0.038],[0,0],[0.292,-1.237],[0,0]],"o":[[0,0],[-1.358,0.038],[0,0],[-1.321,-0.036],[0,0],[0,0],[-0.292,-1.237]],"v":[[5.065,-1.046],[2.496,0.128],[0,-1.046],[-2.496,0.128],[-5.065,-1.046],[-5.894,1.046],[5.894,1.046]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917999985639,0.263000009574,0.20800000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[190.011,185.218],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 18","np":4,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".yellow500","cl":"yellow500","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-10.273,-62.792],[10.273,-19.932],[5.308,43.982],[3.529,62.792]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.98431372549,0.737254901961,0.01568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[304.691,67.791],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 19","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-69.845,50.02],[-43.615,20.333],[-43.615,-21.96],[-34.261,-28.874],[-24.095,-28.874],[-16.368,-34.974],[-1.728,-31.72],[1.931,-37.821],[7.218,-34.567],[23.079,-42.293],[55.331,-42.293],[69.845,-50.02]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.98431372549,0.737254901961,0.01568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[373.948,242.314],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 20","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-113.972,-119.335],[-113.972,-89.146],[-110.288,-76.336],[-118.014,-57.426],[-110.288,-39.939],[-93.615,-15.54],[-81.414,-1.306],[-84.668,17.808],[-75.721,29.193],[-63.521,36.921],[-49.288,39.36],[-41.968,48.714],[-28.954,48.714],[-17.568,53.594],[-2.115,58.067],[5.205,65.794],[21.066,68.233],[51.972,97.107],[62.545,99.954],[75.559,99.954],[118.014,119.335]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.98431372549,0.737254901961,0.01568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[245.421,175.3],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 21","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-214.415,-10.167],[-193.269,2.034],[-180.255,2.034],[-172.122,4.88],[-161.548,-0.406],[-149.349,0.001],[-132.675,-7.32],[-126.575,-5.693],[-113.969,-10.167],[-96.075,-8.133],[-88.755,-2.643],[-80.215,-2.643],[-43.208,-2.643],[-22.062,-6.1],[-13.319,0.407],[-0.61,2.034],[17.384,-2.643],[35.278,-0.406],[50.731,2.034],[53.985,6.913],[73.912,4.88],[86.111,10.167],[114.578,10.167],[150.365,10.167],[159.311,4.88],[214.415,2.034]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.98431372549,0.737254901961,0.01568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[223.889,101.607],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 22","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-152.296,-34.933],[-152.296,-17.527],[-140.503,-1.668],[-129.523,3.62],[-129.523,10.94],[-120.577,15.413],[-117.729,22.327],[-88.449,34.933],[-76.251,30.867],[-68.117,23.953],[-38.43,27.207],[-25.417,28.833],[-7.93,24.767],[20.943,25.986],[31.924,29.24],[38.837,25.58],[51.443,25.58],[60.391,21.513],[86.01,18.667],[97.804,26.8],[152.297,26.393]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.98431372549,0.737254901961,0.01568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[304.103,105.308],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 24","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[21.757,-76.408],[21.757,-63.89],[13.214,-63.89],[-14.031,-38.677],[-19.724,-23.223],[-21.757,54.857],[-18.098,63.803],[-21.757,76.409]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.98431372549,0.737254901961,0.01568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[210.57,177.698],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 25","np":2,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-67.1,-42.533],[-37.413,-29.478],[-34.567,-20.938],[-28.873,-24.191],[-17.08,-23.378],[-5.693,-7.518],[12.2,-3.046],[18.3,5.495],[24.807,9.562],[38.227,11.594],[52.867,19.729],[62.525,21.355],[67.1,29.896],[67.1,42.533]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.98431372549,0.737254901961,0.01568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[160.753,59.919],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 26","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-139.893,-158.396],[-135.827,-143.349],[-95.566,-100.243],[-75.233,-93.736],[-51.646,-67.303],[-48.8,-54.29],[-35.38,-42.496],[-32.94,-22.57],[-24.807,-18.91],[-10.574,-14.844],[8.947,16.47],[58.56,53.477],[82.147,84.79],[102.074,96.99],[125.66,133.997],[139.893,142.536],[139.893,158.396]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.98431372549,0.737254901961,0.01568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[243.307,169.317],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 28","np":2,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey500","cl":"grey500","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[31.717,-1.007],[-31.717,1.007]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[287.883,119.11],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 29","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-35.365,-14.212],[-27.159,-14.715],[-22.239,-18.741],[-8.414,-18.741],[6.556,-19.629],[15.02,-18.202],[28.069,-14.212],[28.069,-5.406],[28.069,1.64],[28.069,10.949],[29.704,14.22],[35.239,16.731],[35.365,19.629]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[291.531,123.51],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 30","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-41.561,-23.371],[-37.444,-22.113],[-31.154,-25.384],[-26.499,-26.767],[-21.215,-28.151],[-18.196,-31.05],[-12.41,-31.528],[-8.761,-31.05],[-7.628,-28.906],[9.733,-22.113],[23.067,-5.129],[29.106,-0.14],[37.283,12.608],[40.931,21.004],[41.561,31.528]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[348.112,171.29],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 31","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[4.64,-38.155],[4.64,-8.29],[7.771,-2.101],[6.974,5.21],[2.462,11.432],[-0.966,22.989],[-7.771,38.155]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[251.527,139.762],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 32","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-19.621,11.458],[-23.788,-11.458],[23.788,-11.458]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[259.299,233.54],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 33","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-36.573,-3.452],[3.542,-3.452],[8.492,-1.858],[25.051,-3.452],[31.026,-2.655],[35.293,0.133],[36.573,2.352],[34.013,2.352],[32.887,3.451]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[297.973,269.1],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 34","np":2,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-25.691,-18.223],[-10.328,-18.734],[-5.207,-17.88],[1.281,-18.307],[18.009,-19.077],[25.691,-12.504],[22.789,-10.797],[14.168,0.47],[12.376,5.846],[8.45,13.615],[4.011,19.077]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[307.575,287.115],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 35","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[50.742,46.448],[51.669,43.468],[50.742,37.157],[55.148,32.302],[72.276,31.185],[72.276,5.64],[70.623,-1.526],[70.623,-40.523],[69.383,-42.865],[62.906,-43.554],[56.843,-42.865],[54.224,-44.381],[49.264,-44.381],[45.13,-46.448],[-72.276,-46.448]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[226.967,241.72],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 36","np":2,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-119.509,-44.611],[-97.824,-40.96],[-89.824,-34.688],[-72.741,-36.266],[-66.754,-33.154],[40.537,-34.971],[59.633,-38.882],[68.047,-38.882],[73.387,-37.306],[74.626,-33.154],[77.919,-31.804],[77.919,-26.232],[80.508,-24.928],[89.57,-21.215],[97.823,-16.038],[105.684,-14.257],[108.827,-8.431],[113.844,5.663],[119.508,8.884],[117.654,19.078],[110.284,25.092],[107.048,37.527],[104.562,44.612]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[278.637,267.243],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 37","np":2,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-51.352,2.509],[13.052,3.155],[35.386,-3.155],[51.352,-3.155]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[301.911,213.904],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 38","np":2,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[275.481,202.819],[275.481,222.082]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 39","np":2,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[2.805,-24.131],[-0.446,-14.804],[1.18,18.209],[-2.805,24.131]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[269.292,219.403],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 40","np":2,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-16.325,-7.523],[-4.713,-0.839],[5.806,-0.839],[16.325,7.523]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[261.745,182.35],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 41","np":2,"cix":2,"bm":0,"ix":13,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-52.188,-19.67],[-41.346,-24.51],[-9.628,-12.712],[5.098,-9.312],[20.956,-3.564],[26.135,-4.62],[34.719,-0.671],[41.671,4.326],[52.189,7.729],[46.039,15.452],[46.202,24.509]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[213.259,163.422],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 42","np":2,"cix":2,"bm":0,"ix":14,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[73.548,-6.19],[75.996,7.565],[69.525,24.299],[59.976,26.175],[53.504,28.441],[47.03,33.188],[47.03,39.488],[34.894,32.698],[26.767,21.986],[17.423,17.347],[-1.49,12.605],[-28.757,3.71],[-37.055,-16.252],[-66.354,-16.252],[-66.354,-18.782],[-69.801,-23.38],[-68.077,-26.092],[-70.654,-30.31],[-74.309,-30.31],[-75.996,-39.488]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[230.554,138.453],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 43","np":2,"cix":2,"bm":0,"ix":15,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-68.814,-67.689],[-33.186,-67.127],[-13.566,-64.287],[9.77,-52.647],[17.081,-46.04],[58.129,-44.971],[60.347,-29.873],[60.347,-12.806],[61.785,6.876],[59.395,9.068],[60.347,54.334],[65.44,54.334],[68.814,58.411],[63.612,63.472],[65.581,64.877],[63.612,67.689]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[243.756,235.438],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 44","np":2,"cix":2,"bm":0,"ix":16,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-6.636,-10.36],[-2.642,-10.95],[4.106,-13.762],[4.478,-12.242],[5.933,-6.307],[6.636,13.761]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[170.836,181.51],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 45","np":2,"cix":2,"bm":0,"ix":17,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[150.903,178.874],[176.77,178.874]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 46","np":2,"cix":2,"bm":0,"ix":18,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-46.11,-24.495],[-24.601,-24.495],[-18.978,-22.285],[10.012,-24.495],[26.288,-21.262],[39.924,-19.433],[46.11,-14.795],[41.028,24.495]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[194.482,197.586],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 47","np":2,"cix":2,"bm":0,"ix":19,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[163.403,74.086],[163.403,98.964]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 48","np":2,"cix":2,"bm":0,"ix":20,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[2.298,-13.017],[-2.298,-7.952],[0.038,-1.57],[0.038,13.017]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[138.776,74.953],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 49","np":2,"cix":2,"bm":0,"ix":21,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-25.094,-4.83],[-14.691,-5.955],[-13.004,-4.127],[-6.116,-5.041],[25.094,-5.041],[25.094,5.955]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[113.72,93.01],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 50","np":2,"cix":2,"bm":0,"ix":22,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-21.799,-26.171],[-21.799,13.635],[-20.774,20.008],[16.176,26.171],[21.799,24.503]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[143.443,79.138],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 51","np":2,"cix":2,"bm":0,"ix":23,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[88.626,74.857],[151.806,74.857]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 52","np":2,"cix":2,"bm":0,"ix":24,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[93.653,52.401],[93.653,94.366]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 53","np":2,"cix":2,"bm":0,"ix":25,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1.723,-35.415],[-1.723,-14.469],[0.62,-12.953],[1.723,35.415]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[162.477,159.858],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 54","np":2,"cix":2,"bm":0,"ix":26,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-11.575,3.259],[-0.551,-3.259],[4.821,-3.259],[7.166,-1.191],[9.784,-1.191],[11.575,-3.259]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[155.932,166.01],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 55","np":2,"cix":2,"bm":0,"ix":27,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.489,-23.839],[-6.05,-13.917],[-7.841,-12.401],[-7.841,1.329],[-11.562,10.887],[-11.562,23.84],[11.562,23.84]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[179.069,138.912],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 56","np":2,"cix":2,"bm":0,"ix":28,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".green100","cl":"green100","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-84.172,-14.163],[-87.624,-10.786],[-87.624,-7.25],[-91.245,-3.685],[-94.866,-5.154],[-98.486,-11.792],[-101.705,-10.384],[-105.729,-11.792],[-110.154,-14.163],[-116.994,-11.792],[-121.218,-5.355],[-119.247,-2.337],[-117.598,-2.337],[-116.19,1.083],[-110.959,2.286],[-107.137,3.899],[-97.49,3.899],[-97.49,10.725],[-88.428,11.544],[-86.819,19.59],[-68.714,22.205],[-62.64,26.027],[-55.235,33.068],[-45.78,31.79],[-35.723,31.79],[-22.848,31.79],[-17.818,34.678],[-3.957,38.5],[5.315,37.695],[13.563,34.678],[23.622,33.873],[46.757,36.891],[58.826,36.891],[67.678,33.068],[75.14,30.654],[87.996,32.666],[90.209,31.79],[108.313,29.649],[117.768,25.022],[130.243,25.424],[144.523,25.022],[148.34,20.596],[149.955,15.969],[148.34,10.725],[127.193,-42.264],[-25.865,-48.73],[-69.318,-44.784],[-72.134,-37.519],[-82.394,-31.305]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[308.06,59.651],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 57","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-53.521,-13.307],[-41.048,-20.863],[-32.801,-18.738],[-26.967,-20.863],[-15.902,-15.576],[-11.075,-15.576],[-11.075,-13.307],[4.818,-13.307],[6.83,-15.576],[17.29,-15.576],[20.308,-23.708],[24.532,-22.041],[35.194,-20.863],[45.454,-19.945],[47.264,-15.576],[52.695,-6.064],[46.459,23.708],[42.881,20.101],[34.646,17.883],[-4.626,17.883],[-13.177,20.101],[-23.946,20.101],[-30.387,15.26],[-38.835,16.264],[-49.296,17.271],[-56.009,14.456]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[69.974,127.35],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 61","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey100","cl":"grey100","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[-2.851,0.95],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[2.851,-0.95],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-209.239,-23.701],[-197.204,-12.299],[-193.403,-15.149],[-193.403,-18.95],[-181.051,-21.801],[-177.251,-23.701],[-166.482,-23.701],[-157.931,-25.918],[-154.447,-25.918],[-135.761,-25.918],[-131.327,-25.918],[-124.36,-25.918],[-118.658,-25.918],[-110.424,-23.701],[-104.406,-19.108],[-98.389,-12.299],[-88.254,0.49],[-84.77,0],[-84.77,-6.282],[-81.92,-1.531],[-83.351,0],[-84.736,0.49],[-86.024,1.81],[-86.644,2.239],[-81.92,12.262],[-74.427,29.3],[-73.52,32.545],[-69.607,41.517],[-69.607,44.142],[-68.7,45.383],[-66.791,56.121],[-66.791,60.226],[-68.748,61.371],[-68.748,62.564],[-70.322,63.995],[-70.37,65.523],[-72.327,67.146],[-73.615,67.146],[-74.14,68.195],[-75.477,68.195],[-75.477,69.389],[-76.908,70.439],[-77.481,71.059],[-77.481,72.014],[-78.293,72.872],[-76.813,73.445],[-76.67,74.877],[-75.572,75.402],[-75.668,77.788],[-74.904,77.788],[-74.904,81.367],[-74.093,81.367],[-73.854,83.611],[-72.947,84.231],[-72.947,85.52],[-71.754,86.331],[-69.655,86.331],[-64.643,86.331],[-64.023,85.472],[-61.302,85.902],[-61.064,86.331],[-57.485,86.665],[-56.005,88.287],[-56.005,89.815],[-54.287,90.912],[-53.428,90.244],[-52.998,90.912],[-51.614,91.199],[-51.614,92.249],[-49.133,92.249],[-48.751,93.299],[-46.651,93.299],[-45.935,94.253],[-45.076,94.253],[-42.833,96.688],[-40.256,96.688],[-40.256,97.498],[-38.108,97.498],[-37.678,98.501],[-35.817,98.501],[-34.815,99.169],[-34.004,99.169],[-33.622,98.453],[-31.14,98.453],[-31.427,97.642],[-31.904,96.782],[-33.431,96.735],[-33.622,91.58],[-33.097,91.58],[-32.763,92.583],[-31.713,92.44],[-31.14,92.965],[-29.279,92.869],[-29.279,91.676],[-30.138,91.342],[-30.043,89.385],[-30.902,88.669],[-30.949,87.237],[-31.904,86.808],[-30.997,86.092],[-30.854,84.66],[-30.138,84.374],[-30.091,80.556],[-31.045,79.984],[-30.759,76.691],[-29.47,78.313],[-29.279,79.268],[-27.37,80.222],[-26.559,79.888],[-25.89,78.934],[-25.604,77.884],[-24.459,76.357],[-21.882,75.402],[-17.586,74.973],[-14.771,74.734],[-14.771,75.831],[-22.072,77.74],[-23.361,78.122],[-24.268,78.6],[-25.127,79.124],[-25.509,80.174],[-27.036,81.272],[-28.181,81.749],[-29.088,83.229],[-29.088,85.997],[-28.849,87.953],[-27.752,88.287],[-26.177,89.385],[-24.173,88.097],[-23.648,88.097],[-22.502,87.143],[-22.74,86.331],[-23.027,83.372],[-22.12,83.133],[-21.548,83.897],[-21.5,84.518],[-20.88,84.66],[-20.88,85.902],[-20.02,86.188],[-19.734,85.328],[-16.918,85.568],[-16.966,84.708],[-19.114,82.895],[-19.591,82.035],[-19.495,81.272],[-16.441,81.415],[-16.107,80.509],[-13.72,80.509],[-12.862,79.076],[-11.239,79.984],[-10.809,83.849],[-9.473,83.897],[-8.996,84.566],[-6.848,84.852],[-6.085,85.949],[-3.364,86.236],[-3.078,84.756],[-3.698,81.701],[-6.037,79.554],[-6.323,78.504],[-3.603,78.456],[-2.219,78.027],[-0.406,77.359],[0.549,77.74],[2.84,77.645],[4.94,77.645],[6.133,78.027],[8.567,78.6],[9.14,79.458],[11.096,79.458],[11.43,80.413],[13.149,80.413],[13.435,80.986],[14.628,81.033],[14.628,80.413],[15.868,79.936],[15.868,78.934],[16.346,81.272],[18.064,81.32],[18.064,80.222],[17.539,80.174],[17.539,78.074],[18.446,78.552],[19.973,80.031],[21.452,80.079],[21.452,82.704],[20.976,83.42],[20.976,84.518],[19.782,84.804],[19.83,85.71],[22.026,86.188],[22.884,86.999],[24.698,87.047],[25.414,87.953],[27.275,87.953],[30.855,87.953],[31.523,86.999],[32.764,87.047],[32.286,88.335],[31.761,88.956],[32.048,90.436],[36.915,90.818],[37.583,98.787],[39.97,102.366],[42.738,103.368],[44.552,106.185],[54.431,117.018],[58.582,120.216],[67.889,127.518],[73.711,130.429],[85.165,134.294],[88.458,136.013],[91.179,136.013],[97.717,142.026],[98.338,144.89],[104.494,147.849],[107.262,150],[211.975,150],[211.975,-151.69],[-210.962,-153.764]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019607843,0.952941176471,0.956862745098,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[223.279,171.151],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 62","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[57.694,49,0],"ix":2,"l":2},"a":{"a":0,"k":[232.123,166.357,0],"ix":1,"l":2},"s":{"a":0,"k":[79.922,79.922,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-206,148.684],[206,148.684],[206,-148.684],[-206,-148.684]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[223.279,172.467],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 63","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue900","cl":"blue900","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[101.086,101.086,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.34,0.34],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[300,300]},{"t":25,"s":[294,294]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.34],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0]},{"t":25,"s":[6]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[98.741,98.741],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Pale Orange Solid 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[72,72,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Blue Circle Outlines","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":10,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[64.361,64.36,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.2],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":0,"s":[66.714,66.714,100]},{"t":45,"s":[208.333,208.333,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-34.164],[34.165,0],[0,34.165],[-34.165,0]],"o":[[0,34.165],[-34.165,0],[0,-34.164],[34.165,0]],"v":[[61.861,-0.001],[0,61.861],[-61.861,-0.001],[0,-61.861]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.829000016755,0.885999971278,0.955999995213,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[70]},{"t":21,"s":[100]}],"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[64.361,64.361],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-34.164],[34.165,0],[0,34.165],[-34.165,0]],"o":[[0,34.165],[-34.165,0],[0,-34.164],[34.165,0]],"v":[[61.861,-0.001],[0,61.861],[-61.861,-0.001],[0,-61.861]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0,0,0,1]},{"t":21,"s":[0.552941203117,0.670588254929,0.921568632126,1]}],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[20]},{"t":21,"s":[50]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[64.361,64.361],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":585,"st":-15,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"CircleMatte 4","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[82.705,0],[0,-82.705],[-82.705,0],[0,82.705]],"o":[[-82.705,0],[0,82.705],[82.705,0],[0,-82.705]],"v":[[-0.125,-149.938],[-149.875,-0.188],[-0.125,149.562],[149.625,-0.188]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":-1,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[15.4,0],[0,0],[0,15.4],[0,0],[-15.4,0],[0,0],[0,-15.4],[0,0]],"o":[[0,0],[-15.4,0],[0,0],[0,-15.4],[0,0],[15.4,0],[0,0],[0,15.4]],"v":[[228,150],[-238,150],[-266,122],[-266,-122],[-238,-150],[228,-150],[256,-122],[256,122]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1800,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"Approximate_ON_LT","tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":0,"k":[307.2,307.2,100],"ix":6,"l":2}},"ao":0,"w":117,"h":98,"ip":0,"op":585,"st":-15,"bm":0}],"markers":[]} \ No newline at end of file
diff --git a/PermissionController/res/raw/fine_loc_off.json b/PermissionController/res/raw/fine_loc_off.json
new file mode 100644
index 000000000..3aa81bab5
--- /dev/null
+++ b/PermissionController/res/raw/fine_loc_off.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":91,"w":300,"h":300,"nm":"Location_Accuracy_Exact_OFF_LT","ddd":0,"assets":[{"id":"comp_0","nm":"Exact_OFF_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Scale Controller","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[58.5,49,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.2],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":15,"s":[102,102,100]},{"t":60,"s":[80,80,100]}],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Location Pointer Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[58.298,63.254,0],"ix":2,"l":2},"a":{"a":0,"k":[18.25,51.679,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.967,0.967,0.2],"y":[1,1,1]},"o":{"x":[0.499,0.499,0.4],"y":[0,0,0]},"t":24,"s":[54,54,100]},{"t":42,"s":[10,10,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.551,0],[0,-3.55],[3.55,0],[0,3.551]],"o":[[3.55,0],[0,3.551],[-3.551,0],[0,-3.55]],"v":[[0.001,-6.429],[6.428,-0.001],[0.001,6.429],[-6.428,-0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[18.249,18.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[9.952,0],[0,-9.951],[0,0],[0,13.5]],"o":[[-9.952,0],[0,13.5],[0,0],[0,-9.951]],"v":[[0,-25.715],[-18,-7.715],[0,25.715],[18,-7.715]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196080506,0.305882364511,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[18.25,25.965],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":43,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Location bottom Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[58.298,63.254,0],"ix":2,"l":2},"a":{"a":0,"k":[13.432,6.364,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.967,0.967,0.2],"y":[1,1,1]},"o":{"x":[0.499,0.499,0.4],"y":[0,0,0]},"t":24,"s":[54,54,100]},{"t":42,"s":[10,10,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-2.135],[6.037,0],[0,2.134],[-6.038,0]],"o":[[0,2.134],[-6.038,0],[0,-2.135],[6.037,0]],"v":[[10.933,0],[0.001,3.863],[-10.933,0],[0.001,-3.863]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[13.432,6.364],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-2.135],[6.037,0],[0,2.134],[-6.038,0]],"o":[[0,2.134],[-6.038,0],[0,-2.135],[6.037,0]],"v":[[10.933,0],[0.001,3.863],[-10.933,0],[0.001,-3.863]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[13.432,6.364],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":43,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue900","cl":"blue900","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.878],[0,1.37]],"o":[[-1.734,0],[0,1.37],[2.201,-1.878],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[24.4,206.353],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 16","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.055],[-2.2,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.201,-1.879],[0,-2.055]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[38.555,165.221],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 17","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.201,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[49.115,205.645],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 18","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.201,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[105.514,213.902],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 19","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.055],[-2.2,-1.878],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.201,-1.878],[0,-2.055]],"v":[[0,-4.128],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[171.789,167.995],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 20","np":4,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.733,0],[0,1.371],[2.201,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[368.126,111.436],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 21","np":4,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.733,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[281.531,116.994],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 22","np":4,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.733,0],[0,-2.055],[-2.2,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.055]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[312.438,125.251],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 23","np":4,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.733,0],[0,-2.056],[-2.201,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.128],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[329.856,217.762],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 24","np":4,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Pins_Orange","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.201,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[27.703,137.9],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 15","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.733,0],[0,1.371],[2.201,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.744],[0,4.128],[3.303,-0.744]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[381.288,270.794],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 25","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.733,0],[0,1.371],[2.201,-1.879],[0,-2.056]],"v":[[0,-4.128],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[368.126,210.482],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 26","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.733,0],[0,-2.057],[-2.201,-1.878],[0,1.37]],"o":[[-1.734,0],[0,1.37],[2.2,-1.878],[0,-2.057]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[350.754,184.962],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 27","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.201,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[183.575,115.565],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 28","np":4,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".grey500","cl":"grey500","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[65.394,-87.762],[21.956,-25.29],[-65.394,87.762]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[77.34,207.456],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-29.617,35.822],[12.473,-5.331],[29.618,-35.821]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[199.566,278.889],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-8.219,9.823],[8.218,-9.823]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.146,227.853],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-33.868,-25.038],[8.293,9.519],[33.867,25.038]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[209.364,226.554],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.167,15.54],[-19.167,-15.54]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[119.548,75.138],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-72.23,5.545],[32.282,-5.545],[55.773,-5.545],[72.23,5.545]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[387.97,276.339],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":2,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[6.098,-157.973],[9.854,-43.904],[-9.854,53.949],[-8.736,83.862],[-3.121,157.973]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[393.327,169.155],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-82.146,-18.015],[-17.286,18.015],[82.146,18.015]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[364.737,26.721],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":2,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-50.193,59.098],[50.193,-59.098]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.734,59.599],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":2,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-50.193,59.098],[50.193,-59.098]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[108.816,73.718],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 13","np":2,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-50.193,59.098],[50.193,-59.098]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[105.449,70.281],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 14","np":2,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-61.089,79.79],[-10.563,22.215],[30.571,-28.773],[46.604,-61.512],[61.089,-79.79]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[197.779,251.592],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 29","np":2,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.176,-130.71],[-103.059,-67.44],[-30.743,-4.641],[-18.758,22.842],[23.397,30.81],[65.134,54.857],[89.912,66.865],[181.176,130.71]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[252.512,144.213],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 30","np":2,"cix":2,"bm":0,"ix":13,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-197.801,-135.93],[-169.578,-81.272],[-25.091,29.988],[22.053,51.34],[69.798,92.618],[93.582,100.74],[139.02,95.547],[197.801,135.931]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[245.942,149.433],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 31","np":2,"cix":2,"bm":0,"ix":14,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-43.312,-42.235],[22.43,13.494],[43.312,42.235]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[45.812,287.214],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 32","np":2,"cix":2,"bm":0,"ix":15,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[18.949,23.783],[-18.949,-23.783]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[109.621,305.667],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 33","np":2,"cix":2,"bm":0,"ix":16,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-161.26,59.553],[-73.09,134.19],[-18.949,92.406],[161.26,-134.191]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[163.76,147.693],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 34","np":2,"cix":2,"bm":0,"ix":17,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-170.929,-3.155],[-48.146,106.479],[7.347,155.978],[56.846,100.678],[93.971,24.495],[114.081,-34.03],[140.8,-83.029],[163.001,-98.674],[170.928,-155.978]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[176.522,171.15],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 35","np":2,"cix":2,"bm":0,"ix":18,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-128.003,-94.842],[128.003,94.842]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[128.569,230.353],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 36","np":2,"cix":2,"bm":0,"ix":19,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-143.858,-121.852],[-139.604,-101.518],[143.858,121.852]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[169.948,211.078],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 37","np":2,"cix":2,"bm":0,"ix":20,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-101.126,-61.295],[6.382,43.506],[25.329,50.08],[48.533,50.08],[101.126,61.295]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[339.523,72.477],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 38","np":2,"cix":2,"bm":0,"ix":21,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[75.549,33.199],[0.527,16.447],[-24.997,16.447],[-75.549,-33.199]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[358.139,131.247],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 39","np":2,"cix":2,"bm":0,"ix":22,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.267,11.975],[-22.236,-5.401],[-51.24,-5.401],[-56.267,-11.975]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[381.289,156.961],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 40","np":2,"cix":2,"bm":0,"ix":23,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-23.396,-110.585],[23.396,-69.624],[14.115,-1.562],[14.115,110.585]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[301.625,214.61],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 41","np":2,"cix":2,"bm":0,"ix":24,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-152.301,-106.862],[-115.301,-91.911],[68.768,50.786],[98.546,63.161],[152.3,106.862]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[163.44,175.022],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 43","np":2,"cix":2,"bm":0,"ix":25,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[137.091,-155.846],[25.716,1.527],[6.767,17.403],[-27.65,61.101],[-76.956,108.281],[-137.091,155.846]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[205.333,169.349],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 44","np":2,"cix":2,"bm":0,"ix":26,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-56.46,-44.426],[56.46,44.426]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[221.768,59.599],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 45","np":2,"cix":2,"bm":0,"ix":27,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-157.626,-125.059],[157.625,125.059]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[276.914,138.562],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 46","np":2,"cix":2,"bm":0,"ix":28,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[128.583,-155.739],[-82.951,117.438],[-128.583,155.739]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[173.622,164.445],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 47","np":2,"cix":2,"bm":0,"ix":29,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[123.363,-155.846],[-123.363,155.846]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[149.452,169.349],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 48","np":2,"cix":2,"bm":0,"ix":30,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[119.688,-154.492],[-119.689,154.493]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[128.376,167.995],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 49","np":2,"cix":2,"bm":0,"ix":31,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[94.165,-121.947],[-94.165,121.948]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[102.853,137.12],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 50","np":2,"cix":2,"bm":0,"ix":32,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".green100","cl":"green100","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-3.871,-11.834],[12.775,-0.847],[2.691,11.834],[-12.775,-0.336]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[260.038,79.995],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 54","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-35.787,-24.613],[-37.505,-22.753],[-34.63,-21.167],[-31.031,-23.281],[-9.88,-6.238],[-12.139,-3.2],[24.52,24.613],[37.505,7.844],[1.732,-21.035],[3.318,-23.281],[1.924,-24.613]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[231.647,43.549],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 55","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.533,-30.467],[28.951,-30.467],[20.804,-26.143],[14.324,-20.586],[4.618,-16.81],[1.118,-16.23],[-6.173,-7.064],[-37.533,17.139],[-22.607,30.467],[8.069,1.113],[26.699,-16.712]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[150.984,247.163],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 56","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".grey100","cl":"grey100","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-206,150],[206,150],[206,-150],[-206,-150]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019607843,0.952941176471,0.956862745098,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[220.851,168.936],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 58","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":3,"nm":"Exact Light Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[64.082,57.55,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[48.646,48.646,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue900","cl":"blue900","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[101.086,101.086,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.66,0.66],"y":[0,0]},"t":0,"s":[294,294]},{"t":10,"s":[300,300]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.66],"y":[0]},"t":0,"s":[6]},{"t":10,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[98.741,98.741],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":1,"nm":"Scale Controller","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,149,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.6],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.8],"y":[0,0,0]},"t":0,"s":[306,306,100]},{"t":45,"s":[240,240,100]}],"ix":6,"l":2}},"ao":0,"sw":117,"sh":98,"sc":"#a77b57","ip":0,"op":585,"st":-15,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"CircleMatte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[82.705,0],[0,-82.705],[-82.705,0],[0,82.705]],"o":[[-82.705,0],[0,82.705],[82.705,0],[0,-82.705]],"v":[[-0.125,-149.938],[-149.875,-0.188],[-0.125,149.562],[149.625,-0.188]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":-1,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[15.4,0],[0,0],[0,15.4],[0,0],[-15.4,0],[0,0],[0,-15.4],[0,0]],"o":[[0,0],[-15.4,0],[0,0],[0,-15.4],[0,0],[15.4,0],[0,0],[0,15.4]],"v":[[228,150],[-238,150],[-266,122],[-266,-122],[-238,-150],[228,-150],[256,-122],[256,122]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1800,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"Exact_OFF_LT","tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":0,"k":[307.2,307.2,100],"ix":6,"l":2}},"ao":0,"w":117,"h":98,"ip":0,"op":585,"st":-15,"bm":0}],"markers":[{"tm":91,"cm":"","dr":0}]} \ No newline at end of file
diff --git a/PermissionController/res/raw/fine_loc_on.json b/PermissionController/res/raw/fine_loc_on.json
new file mode 100644
index 000000000..344942361
--- /dev/null
+++ b/PermissionController/res/raw/fine_loc_on.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":91,"w":300,"h":300,"nm":"Location_Accuracy_Exact_ON_LT","ddd":0,"assets":[{"id":"comp_0","nm":"Exact_ON_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Scale Controller","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[58.5,49,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.2],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":15,"s":[80,80,100]},{"t":60,"s":[102,102,100]}],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Location Pointer Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[58.298,63.254,0],"ix":2,"l":2},"a":{"a":0,"k":[18.25,51.679,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.552,0.552,0.667],"y":[1,1,1]},"o":{"x":[0.046,0.046,0.333],"y":[0,0,0]},"t":28,"s":[20,20,100]},{"i":{"x":[0.468,0.468,0.667],"y":[1,1,1]},"o":{"x":[0.441,0.441,0.333],"y":[0,0,0]},"t":42,"s":[58,58,100]},{"t":60,"s":[54,54,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.551,0],[0,-3.55],[3.55,0],[0,3.551]],"o":[[3.55,0],[0,3.551],[-3.551,0],[0,-3.55]],"v":[[0.001,-6.429],[6.428,-0.001],[0.001,6.429],[-6.428,-0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[18.249,18.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[9.952,0],[0,-9.951],[0,0],[0,13.5]],"o":[[-9.952,0],[0,13.5],[0,0],[0,-9.951]],"v":[[0,-25.715],[-18,-7.715],[0,25.715],[18,-7.715]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196080506,0.305882364511,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[18.25,25.965],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":28,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Location bottom Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[58.298,63.254,0],"ix":2,"l":2},"a":{"a":0,"k":[13.432,6.364,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.2],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":28,"s":[20,20,100]},{"t":41,"s":[54,54,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-2.135],[6.037,0],[0,2.134],[-6.038,0]],"o":[[0,2.134],[-6.038,0],[0,-2.135],[6.037,0]],"v":[[10.933,0],[0.001,3.863],[-10.933,0],[0.001,-3.863]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[13.432,6.364],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-2.135],[6.037,0],[0,2.134],[-6.038,0]],"o":[[0,2.134],[-6.038,0],[0,-2.135],[6.037,0]],"v":[[10.933,0],[0.001,3.863],[-10.933,0],[0.001,-3.863]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[13.432,6.364],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":28,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue900","cl":"blue900","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.878],[0,1.37]],"o":[[-1.734,0],[0,1.37],[2.201,-1.878],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[24.4,206.353],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 16","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.055],[-2.2,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.201,-1.879],[0,-2.055]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[38.555,165.221],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 17","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.201,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[49.115,205.645],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 18","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.201,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[105.514,213.902],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 19","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.055],[-2.2,-1.878],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.201,-1.878],[0,-2.055]],"v":[[0,-4.128],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[171.789,167.995],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 20","np":4,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.733,0],[0,1.371],[2.201,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[368.126,111.436],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 21","np":4,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.733,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[281.531,116.994],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 22","np":4,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.733,0],[0,-2.055],[-2.2,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.055]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[312.438,125.251],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 23","np":4,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.733,0],[0,-2.056],[-2.201,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.128],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[329.856,217.762],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 24","np":4,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Pins_Orange","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.201,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[27.703,137.9],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 15","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.733,0],[0,1.371],[2.201,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.744],[0,4.128],[3.303,-0.744]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[381.288,270.794],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 25","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.2,-1.879],[0,1.371]],"o":[[-1.733,0],[0,1.371],[2.201,-1.879],[0,-2.056]],"v":[[0,-4.128],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[368.126,210.482],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 26","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.733,0],[0,-2.057],[-2.201,-1.878],[0,1.37]],"o":[[-1.734,0],[0,1.37],[2.2,-1.878],[0,-2.057]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.128],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[350.754,184.962],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 27","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.734,0],[0,-2.056],[-2.201,-1.879],[0,1.371]],"o":[[-1.734,0],[0,1.371],[2.2,-1.879],[0,-2.056]],"v":[[0,-4.129],[-3.303,-0.743],[0,4.129],[3.303,-0.743]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.6,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[183.575,115.565],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 28","np":4,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".grey500","cl":"grey500","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[65.394,-87.762],[21.956,-25.29],[-65.394,87.762]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[77.34,207.456],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-29.617,35.822],[12.473,-5.331],[29.618,-35.821]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[199.566,278.889],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-8.219,9.823],[8.218,-9.823]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[201.146,227.853],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-33.868,-25.038],[8.293,9.519],[33.867,25.038]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[209.364,226.554],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[19.167,15.54],[-19.167,-15.54]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[119.548,75.138],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-72.23,5.545],[32.282,-5.545],[55.773,-5.545],[72.23,5.545]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[387.97,276.339],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":2,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[6.098,-157.973],[9.854,-43.904],[-9.854,53.949],[-8.736,83.862],[-3.121,157.973]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[393.327,169.155],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-82.146,-18.015],[-17.286,18.015],[82.146,18.015]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[364.737,26.721],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":2,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-50.193,59.098],[50.193,-59.098]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[142.734,59.599],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":2,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-50.193,59.098],[50.193,-59.098]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[108.816,73.718],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 13","np":2,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-50.193,59.098],[50.193,-59.098]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[105.449,70.281],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 14","np":2,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-61.089,79.79],[-10.563,22.215],[30.571,-28.773],[46.604,-61.512],[61.089,-79.79]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[197.779,251.592],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 29","np":2,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-181.176,-130.71],[-103.059,-67.44],[-30.743,-4.641],[-18.758,22.842],[23.397,30.81],[65.134,54.857],[89.912,66.865],[181.176,130.71]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[252.512,144.213],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 30","np":2,"cix":2,"bm":0,"ix":13,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-197.801,-135.93],[-169.578,-81.272],[-25.091,29.988],[22.053,51.34],[69.798,92.618],[93.582,100.74],[139.02,95.547],[197.801,135.931]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[245.942,149.433],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 31","np":2,"cix":2,"bm":0,"ix":14,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-43.312,-42.235],[22.43,13.494],[43.312,42.235]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[45.812,287.214],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 32","np":2,"cix":2,"bm":0,"ix":15,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[18.949,23.783],[-18.949,-23.783]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[109.621,305.667],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 33","np":2,"cix":2,"bm":0,"ix":16,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-161.26,59.553],[-73.09,134.19],[-18.949,92.406],[161.26,-134.191]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[163.76,147.693],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 34","np":2,"cix":2,"bm":0,"ix":17,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-170.929,-3.155],[-48.146,106.479],[7.347,155.978],[56.846,100.678],[93.971,24.495],[114.081,-34.03],[140.8,-83.029],[163.001,-98.674],[170.928,-155.978]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[176.522,171.15],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 35","np":2,"cix":2,"bm":0,"ix":18,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-128.003,-94.842],[128.003,94.842]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[128.569,230.353],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 36","np":2,"cix":2,"bm":0,"ix":19,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-143.858,-121.852],[-139.604,-101.518],[143.858,121.852]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[169.948,211.078],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 37","np":2,"cix":2,"bm":0,"ix":20,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-101.126,-61.295],[6.382,43.506],[25.329,50.08],[48.533,50.08],[101.126,61.295]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[339.523,72.477],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 38","np":2,"cix":2,"bm":0,"ix":21,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[75.549,33.199],[0.527,16.447],[-24.997,16.447],[-75.549,-33.199]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[358.139,131.247],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 39","np":2,"cix":2,"bm":0,"ix":22,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.267,11.975],[-22.236,-5.401],[-51.24,-5.401],[-56.267,-11.975]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[381.289,156.961],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 40","np":2,"cix":2,"bm":0,"ix":23,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-23.396,-110.585],[23.396,-69.624],[14.115,-1.562],[14.115,110.585]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[301.625,214.61],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 41","np":2,"cix":2,"bm":0,"ix":24,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-152.301,-106.862],[-115.301,-91.911],[68.768,50.786],[98.546,63.161],[152.3,106.862]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[163.44,175.022],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 43","np":2,"cix":2,"bm":0,"ix":25,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[137.091,-155.846],[25.716,1.527],[6.767,17.403],[-27.65,61.101],[-76.956,108.281],[-137.091,155.846]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[205.333,169.349],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 44","np":2,"cix":2,"bm":0,"ix":26,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-56.46,-44.426],[56.46,44.426]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[221.768,59.599],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 45","np":2,"cix":2,"bm":0,"ix":27,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-157.626,-125.059],[157.625,125.059]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[276.914,138.562],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 46","np":2,"cix":2,"bm":0,"ix":28,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[128.583,-155.739],[-82.951,117.438],[-128.583,155.739]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[173.622,164.445],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 47","np":2,"cix":2,"bm":0,"ix":29,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[123.363,-155.846],[-123.363,155.846]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[149.452,169.349],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 48","np":2,"cix":2,"bm":0,"ix":30,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[119.688,-154.492],[-119.689,154.493]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[128.376,167.995],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 49","np":2,"cix":2,"bm":0,"ix":31,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[94.165,-121.947],[-94.165,121.948]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[102.853,137.12],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 50","np":2,"cix":2,"bm":0,"ix":32,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[7.927,-159.713],[-0.193,-105.055],[-1.741,54.527],[-7.927,159.714]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[344.164,173.216],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 42","np":2,"cix":2,"bm":0,"ix":33,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-10.143,-7.085],[10.143,7.085]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.505882352941,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[89.154,175.08],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":34,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".green100","cl":"green100","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-3.871,-11.834],[12.775,-0.847],[2.691,11.834],[-12.775,-0.336]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[260.038,79.995],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 54","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-35.787,-24.613],[-37.505,-22.753],[-34.63,-21.167],[-31.031,-23.281],[-9.88,-6.238],[-12.139,-3.2],[24.52,24.613],[37.505,7.844],[1.732,-21.035],[3.318,-23.281],[1.924,-24.613]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[231.647,43.549],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 55","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.533,-30.467],[28.951,-30.467],[20.804,-26.143],[14.324,-20.586],[4.618,-16.81],[1.118,-16.23],[-6.173,-7.064],[-37.533,17.139],[-22.607,30.467],[8.069,1.113],[26.699,-16.712]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[150.984,247.163],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 56","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".grey100","cl":"grey100","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230.884,168.455,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-206,150],[206,150],[206,-150],[-206,-150]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019607843,0.952941176471,0.956862745098,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[220.851,168.936],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 58","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":3,"nm":"Exact Light Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[64.082,57.55,0],"ix":2,"l":2},"a":{"a":0,"k":[231.35,167.715,0],"ix":1,"l":2},"s":{"a":0,"k":[48.646,48.646,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue900","cl":"blue900","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[101.086,101.086,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.34,0.34],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[300,300]},{"t":25,"s":[294,294]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.34],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0]},{"t":25,"s":[6]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[98.741,98.741],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":1,"nm":"Scale Controller","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,149,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0.2],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":0,"s":[240,240,100]},{"t":45,"s":[306,306,100]}],"ix":6,"l":2}},"ao":0,"sw":117,"sh":98,"sc":"#a77b57","ip":0,"op":585,"st":-15,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"CircleMatte 3","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[82.705,0],[0,-82.705],[-82.705,0],[0,82.705]],"o":[[-82.705,0],[0,82.705],[82.705,0],[0,-82.705]],"v":[[-0.125,-149.938],[-149.875,-0.188],[-0.125,149.562],[149.625,-0.188]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":-1,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[15.4,0],[0,0],[0,15.4],[0,0],[-15.4,0],[0,0],[0,-15.4],[0,0]],"o":[[0,0],[-15.4,0],[0,0],[0,-15.4],[0,0],[15.4,0],[0,0],[0,15.4]],"v":[[228,150],[-238,150],[-266,122],[-266,-122],[-238,-150],[228,-150],[256,-122],[256,122]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1800,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"Exact_ON_LT","tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2,"l":2},"a":{"a":0,"k":[58.5,49,0],"ix":1,"l":2},"s":{"a":0,"k":[307.2,307.2,100],"ix":6,"l":2}},"ao":0,"w":117,"h":98,"ip":0,"op":585,"st":-15,"bm":0}],"markers":[]} \ No newline at end of file
diff --git a/PermissionController/res/values-af-v33/strings.xml b/PermissionController/res/values-af-v33/strings.xml
index 2afe77139..6d6a118cd 100644
--- a/PermissionController/res/values-af-v33/strings.xml
+++ b/PermissionController/res/values-af-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Hierdie program sal toegelaat word om vir jou kennisgewings te stuur, en sal toegang tot jou kamera, kontakte, mikrofoon, foon en SMS\'e kry"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Hierdie program sal toegelaat word om vir jou kennisgewings te stuur, en sal toegang kry tot jou kamera, kontakte, lêers, mikrofoon, foon en SMS\'e"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Programme met hierdie toestemming het toegang tot alle lêers op hierdie toestel"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Jou werkbeleidinligting"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Instellings wat deur jou IT-admin bestuur word"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Vou uit en wys lys"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Vou lys in en verberg instellings"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Lys. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Lys. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Handelinge word benodig. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Lysitem. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Maak toe"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Vou uit en wys opsies"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Vou in"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Skakelaar. <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">"Wisselaar"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Maak oop"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Gaan instellings na"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Instellings"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Inligting"</string>
</resources>
diff --git a/PermissionController/res/values-af-v34/strings.xml b/PermissionController/res/values-af-v34/strings.xml
new file mode 100644
index 000000000..db69a7032
--- /dev/null
+++ b/PermissionController/res/values-af-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Sekuriteit en privaatheid"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Kontroles"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Bestuur apptoegang tot gesondheidsdata"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Liggingtoegang"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"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="6846532794702613851">"Vir apps en dienste"</string>
+</resources>
diff --git a/PermissionController/res/values-af/strings.xml b/PermissionController/res/values-af/strings.xml
index 355c06b39..9a5f38d08 100644
--- a/PermissionController/res/values-af/strings.xml
+++ b/PermissionController/res/values-af/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Terug"</string>
<string name="available" msgid="6007778121920339498">"Beskikbaar"</string>
<string name="blocked" msgid="9195547604866033708">"Geblokkeer"</string>
+ <string name="on" msgid="280241003226755921">"Aan"</string>
+ <string name="off" msgid="1438489226422866263">"Af"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Deïnstalleer of deaktiveer"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Program nie gevind nie"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Moenie toelaat nie"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Hou \"Terwyl die program gebruik word\""</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Hou \"Net hierdie keer\""</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Moet steeds nie toelaat nie"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Maak toe"</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>
@@ -107,9 +114,6 @@
<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="screen_overlay_title" msgid="6977038513913222078">"Skermoorlegger bespeur"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Om hierdie toestemminginstelling te verander, moet jy eers die skermoorlegger by Instellings &gt; Programme afskakel"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Maak instellings oop"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Tydlyn van wanneer programme jou <xliff:g id="PERMGROUP">%1$s</xliff:g> in die afgelope 7 dae gebruik het"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Wanneer hierdie program jou <xliff:g id="PERMGROUP">%1$s</xliff:g>-toestemming gebruik het"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Kom meer te wete"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Kom meer te wete oor <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Beheer apptoegang tot jou <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 dag}other{# dae}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 uur}other{# uur}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min.}other{# min.}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 sek.}other{# sek.}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# dag}other{# dae}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# uur}other{# uur}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min.}other{# min.}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# sek.}other{# sek.}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Enige toestemming"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Enige tyd"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Afgelope 7 dae"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Afgelope 24 uur"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Afgelope 1 uur"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Afgelope 15 minute"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Afgelope 1 minuut"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Afgelope # dag}other{Afgelope # dae}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Afgelope # uur}other{Afgelope # uur}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Afgelope # minuut}other{Afgelope # minute}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Geen toestemminggebruike nie"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Mees onlangse toegang in enige tydperk"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Mees onlangse toegang in afgelope 7 dae"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Toestemminggebruik in afgelope 1 uur"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Toestemminggebruik in afgelope 15 minute"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Toestemminggebruik in afgelope 1 minuut"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Nie in die afgelope 24 uur gebruik nie"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Nie in die afgelope 7 dae gebruik nie"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Nie in die afgelope # dag gebruik nie}other{Nie in die afgelope # dae gebruik nie}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Nie in die afgelope # uur gebruik nie}other{Nie in die afgelope # uur gebruik nie}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Gebruik deur 1 program}other{Gebruik deur # programme}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Sien alles in Dashboard"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Gefiltreer volgens: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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 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>
<string name="precise_image_description" msgid="6349638632303619872">"Presiese ligging"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> en <xliff:g id="PERM_1">%2$s</xliff:g> toestemmings sal verwyder word."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Toestemmings wat verwyder sal word: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Bestuur toestemmings outomaties"</string>
- <string name="off" msgid="1438489226422866263">"Af"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"<xliff:g id="PERMISSION_NAME">%s</xliff:g>-toestemming verwyder"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g>- en <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g>-toestemming verwyder"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> en <xliff:g id="NUMBER">%2$s</xliff:g> ander toestemmings verwyder"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Ongebruikte programme"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"As \'n program vir \'n paar maande nie gebruik word nie:\n\n• Word toestemmings verwyder om jou privaatheid te beskerm\n• Word kennisgewings gestop om batterykrag te bespaar\n• Word tydelike lêers verwyder om spasie beskikbaar te maak\n\nMaak die program oop om weer toestemmings en kennisgewings toe te laat."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"As ’n program ’n paar maande lank nie gebruik is nie:\n\n• Word toestemmings verwyder om jou data te beskerm\n• Word tydelike lêers verwyder om spasie beskikbaar te maak\n\nMaak die program oop om weer toestemmings te gee."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Meer as <xliff:g id="NUMBER">%s</xliff:g> maande gelede laas oopgemaak"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"As ’n app ’n maand lank nie gebruik is nie:\n\n• Toestemmings word verwyder om jou data te beskerm\n• Tydelike lêers word verwyder om spasie beskikbaar te maak\n\nMaak die app oop om weer toestemmings te gee."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Meer as # maande gelede laas oopgemaak}other{Meer as # maande gelede laas oopgemaak}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Program is <xliff:g id="DATE">%s</xliff:g> laas oopgemaak"</string>
<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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Nie toegelaat nie"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Sien meer programme wat toegang tot alle lêers het"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 dag}other{# dae}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 uur}other{# uur}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minuut}other{# minute}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 sekonde}other{# sekondes}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# uur}other{# uur}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minuut}other{# minute}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# sekonde}other{# sekondes}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Toestemmingonthounotas"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 ongebruikte program"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> ongebruikte programme"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Sommige programme is \'n paar maande laas gebruik. Tik om te na te gaan."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# ongebruikte program}other{# ongebruikte programme}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Toestemmings en tydelike lêers is verwyder en kennisgewings is gestop. Tik om na te gaan."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Gaan programme na waarvoor toestemmings verwyder is"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Toestemmings en tydelike lêers is verwyder en kennisgewings is gestop vir programme wat jy ’n ruk lank nie gebruik het nie."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Gaan programme na"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Gaan onlangse toestemmings na"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Terwyl jy bestuur het, het jy <xliff:g id="APP">%1$s</xliff:g> toegang gegee tot <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Terwyl jy bestuur het, het jy <xliff:g id="APP">%1$s</xliff:g> toegang gegee tot <xliff:g id="PERMISSION_1">%2$s</xliff:g> en <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Toestemmings is verwyder om jou privaatheid te beskerm"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> het jou ligging op die agtergrond gekry"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Hierdie program het altyd toegang tot jou ligging. Tik om te verander."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Gaan program met toegang tot jou kennisgewings na"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> kan inhoud in jou kennisgewings toemaak, daarop reageer en toegang daartoe kry"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Hierdie program kan inhoud in jou kennisgewings toemaak, daarop reageer en toegang daartoe kry. Sommige programme het hierdie toegang nodig om te werk soos hulle moet."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Verwyder toegang"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Sien meer opsies"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Toegang is verwyder"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Gaan program met volle toesteltoegang na"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> kan jou skerm sien en handelinge op jou toestel uitvoer. Toeganklikheidprogramme het hierdie soort toegang nodig om te werk soos hulle moet."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Hierdie program kan jou skerm sien en handelinge op jou toestel uitvoer. Toeganklikheidprogramme het hierdie soort toegang nodig om te werk soos hulle moet, maar gaan die program na en maak seker dat jy dit kan vertrou."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Verwyder toegang"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Bekyk program met volle toegang"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Toegang is verwyder"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android-stelsel"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Programtoestemmings is verwyder om privaatheid te beskerm"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> is vir \'n paar maande nie gebruik nie. Tik om te kontroleer."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> en 1 ander program is vir \'n paar maande nie gebruik nie. Tik om te kontroleer."</string>
@@ -318,7 +337,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>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> sal interaksie met jou kennisgewings mag hê en toegang kry tot jou Foon-, SMS-, Kontakte- en Kalender-toestemmings."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> sal toegelaat word om interaksie met jou kennisgewings te hê en jou programme na die gekoppelde toestel te stroom."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Hierdie diens deel jou foto\'s, media en kennisgewings van jou foon af na ander toestelle toe."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Versteknotasapp"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Beheerde toestemmings"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Kan toegang tot ligging kry"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Jou IT-admin laat <xliff:g id="APP_NAME">%s</xliff:g> toe om toegang tot jou ligging te kry"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Vir programme en dienste"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Mikrofoondata kan steeds gedeel word wanneer jy \'n noodnommer bel."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Verander"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Sekuriteit en privaatheid"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Soek"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Sekuriteit en privaatheid"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Skandeer toestel"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Maak toe"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Maak hierdie waarskuwing toe?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Gaan jou sekuriteit- en privaatheidinstellings enige tyd na om nog beskerming by te voeg"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Maak toe"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Kanselleer"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Instellings"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Sekuriteit- en privaatheidstatus. <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">"Sekuriteitinstellings"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Sensortoestemmings"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Privaatheidkontroles"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Toestemmings"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Sekuriteit en privaatheid"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Gaan status na"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Jou privaatheidkontroles"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Nog instellings"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Kameratoegang"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Mikrofoontoegang"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Toestemming is verwyder"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Sien meer kameragebruik"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Sien meer mikrofoongebruik"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Verwyder kameratoestemming"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Verwyder mikrofoontoestemming"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Sien onlangse kameragebruik"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Sien onlangse mikrofoongebruik"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Verwyder toestemming vir hierdie program"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Verwyder toestemming vir hierdie program"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Bestuur diens"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Bestuur toestemmings"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Word tans gebruik deur foonoproep"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Onlangs gebruik deur <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">"Word tans gebruik deur <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">"Onlangs gebruik deur <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Sekuriteit en privaatheid"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Gaan status na"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Bevestig"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Terug"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Toegang tot ander lêers sal ook toegelaat word"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"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="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Hierdie program steun nie die jongste weergawe van Android nie. As hierdie program toegang tot foto\'s en video\'s het, sal dit ook toegelaat word toegang tot musiek-, oudio- en ander lêers te kry."</string>
<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 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 apps 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="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 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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Datapraktyke kan verskil op grond van jou appweergawe en -gebruik, streek en ouderdom. "<annotation id="link">"Meer oor datadeling"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Datapraktyke kan verskil op grond van jou appweergawe en -gebruik, streek en ouderdom."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Jou liggingdata"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Verander hierdie app se toegang in "<annotation id="link">"privaatheidinstellings"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Appfunksies"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Ontledings"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Ontwikkelaarkommunikasie"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Reklame of bemarking"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Bedrogvoorkoming, sekuriteit en voldoening"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalisering"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Rekeningbestuur"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Die ontwikkelaars van hierdie apps het inligting oor hul datadelingpraktyke met ’n appwinkel gedeel. Hulle kan dit mettertyd opdateer.\n\nDatadelingpraktyke kan verskil op grond van jou appweergawe en -gebruik, streek en ouderdom."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Kom meer te wete oor datadeling"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Jou liggingdata word nou met derde partye gedeel"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Jou liggingdata word nou met derde partye gedeel vir reklame of bemarking"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{In die afgelope dag opgedateer}=1{In die afgelope dag opgedateer}other{In die afgelope # dae opgedateer}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Geen opdaterings op hierdie tydstip nie"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-am-v33/strings.xml b/PermissionController/res/values-am-v33/strings.xml
index 5c65b7e92..e2a599a3c 100644
--- a/PermissionController/res/values-am-v33/strings.xml
+++ b/PermissionController/res/values-am-v33/strings.xml
@@ -19,4 +19,28 @@
<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_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>
+ <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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"ዝጋ"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"ዘርጋ እና አማራጮችን አሳይ"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"ሰብስብ"</string>
+ <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_gear_label" msgid="5175877094379694098">"ቅንብሮች"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"መረጃ"</string>
</resources>
diff --git a/PermissionController/res/values-am-v34/strings.xml b/PermissionController/res/values-am-v34/strings.xml
new file mode 100644
index 000000000..52f5188ba
--- /dev/null
+++ b/PermissionController/res/values-am-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-am/strings.xml b/PermissionController/res/values-am/strings.xml
index 2b8cb9787..aa5edc983 100644
--- a/PermissionController/res/values-am/strings.xml
+++ b/PermissionController/res/values-am/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"ሁልጊዜ ሁሉንም ፍቀድ"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"የማያ ገፅ ተደራቢ ተገኝ"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"ይህን የፍቃድ ቅንብር ለመቀየር መጀመሪያ የማያ ገፅ ተደራቢውን ከቅንብሮች &gt; መተግበሪያዎች ማጥፋት አለብዎ"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"ቅንብሮችን ክፈት"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 ቀን}one{# ቀኖች}other{# ቀኖች}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 ሰዓት}one{# ሰዓቶች}other{# ሰዓቶች}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 ደቂቃ}one{# ደቂቃዎች}other{# ደቂቃዎች}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 ሴኮ}one{# ሰከንዶች}other{# ሰከንዶች}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# ቀን}one{# ቀን}other{# ቀናት}}"</string>
+ <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_time" msgid="3802087027301631827">"በማንኛውም ጊዜ"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"ባለፉት 7 ቀኖች"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"ባለፉት 24 ሰዓቶች"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"ባለፈው 1 ሰዓት"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"ባለፉት 15 ደቂቃዎች"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"ባለፈው 1 ደቂቃ"</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>
+ <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>
@@ -158,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_24h" msgid="3087783232178611025">"ባለፉት 24 ሰዓታት ውስጥ ስራ ላይ አልዋለም"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"ባለፉት 7 ቀናት ውስጥ ስራ ላይ አልዋለም"</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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"ሁልጊዜ ሁሉንም ፍቀድ"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"ሁልጊዜ ጠይቅ"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"አትፍቀድ"</string>
<string name="precise_image_description" msgid="6349638632303619872">"ትክክለኛ አካባቢ"</string>
@@ -196,10 +200,10 @@
<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_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>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"የ<xliff:g id="PERM_0">%1$s</xliff:g> እና የ<xliff:g id="PERM_1">%2$s</xliff:g> ፈቃዶች ይወገዳሉ።"</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"የሚወገዱ ፈቃዶች፦ <xliff:g id="PERMS">%1$s</xliff:g>።"</string>
<string name="auto_manage_title" msgid="7693181026874842935">"ፈቃዶችን በራስ-ሰር አቀናብር"</string>
- <string name="off" msgid="1438489226422866263">"ቅናሽ"</string>
<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_tv_summary" msgid="3685907153054355671">"አንድ መተግበሪያ ለጥቂት ወራት ስራ ላይ ካልዋለ፦\n\n• ውሂብዎን ለመጠበቅ ሲባል ፈቃዶች ይወገዳሉ\n• ቦታ ለማስለቀቅ ጊዜያዊ ፋይሎች ይወገዳሉ \n\nፈቃዶችን እንደገና ለመፍቀድ መተግበሪያውን ይክፈቱ።"</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"መጨረሻ የተከፈተው ከ<xliff:g id="NUMBER">%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="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>
@@ -244,31 +247,34 @@
<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>
<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{# ቀኖች}other{# ቀኖች}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 ሰዓት}one{# ሰዓቶች}other{# ሰዓቶች}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 ደቂቃ}one{# ደቂቃዎች}other{# ደቂቃዎች}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 ሰከንድ}one{# ሰከንዶች}other{# ሰከንዶች}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# ሰዓት}one{# ሰዓት}other{# ሰዓታት}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# ደቂቃ}one{# ደቂቃ}other{# ደቂቃዎች}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# ሰከንድ}one{# ሰከንድ}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_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>
+ <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> &amp; <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> &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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"የAndroid ሥርዓት"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"ግላዊነትን ለመጠበቅ የመተግበሪያ ፈቃዶች ተወግደዋል"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> ለጥቂት ወራት ጥቅም ላይ ውሎ አያውቅም። ለመገምገም መታ ያድርጉ።"</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> እና 1 ሌላ መተግበሪያ ለጥቂት ወራት ጥቅም ላይ ውሎ አያውቅም። ለመገምገም መታ ያድርጉ።"</string>
@@ -378,12 +397,16 @@
<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_search_keywords" msgid="7710756695666744631">"ማስታወሻዎች"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -471,11 +495,11 @@
<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="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="permgrouprequest_notifications" msgid="6396739062335106181">"&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="1438871159268985993">"የመገኛ አካባቢ ሊደርስበት ይችላል"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"የእርስዎ አይቲ አስተዳዳሪ <xliff:g id="APP_NAME">%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>
@@ -496,29 +520,38 @@
<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="7514620345152008005">"ደህንነት እና ግላዊነት"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"ቃኝ"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"የዳሳሽ ፈቃዶች"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"የግላዊነት ቁጥጥሮች"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"ፈቃድ ተወግዷል"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"ተጨማሪ የካሜራ አጠቃቀምን ይመልከቱ"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"ተጨማሪ የማይክሮፎን አጠቃቀም ይመልከቱ"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"የካሜራ ፈቃድ ያስወግዱ"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"የማይክሮፎን ፈቃድ ያስወግዱ"</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="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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"ደህንነት እና ግላዊነት"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"ሁኔታ አረጋግጥ"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"የገንቢ ተግባቦት"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{ባለፈው ቀን ውስጥ የተዘመነ}=1{ባለፈው ቀን ውስጥ የተዘመነ}one{ባለፈው # ቀን ውስጥ የተዘመነ}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>
</resources>
diff --git a/PermissionController/res/values-ar-v33/strings.xml b/PermissionController/res/values-ar-v33/strings.xml
index c61744df1..6b881f064 100644
--- a/PermissionController/res/values-ar-v33/strings.xml
+++ b/PermissionController/res/values-ar-v33/strings.xml
@@ -19,4 +19,28 @@
<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_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>
+ <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{التوسيع لعرض تنبيه واحد إضافي}zero{التوسيع لعرض # تنبيه إضافي}two{التوسيع لعرض تنبيهين إضافيَين}few{التوسيع لعرض # تنبيهات إضافية}many{التوسيع لعرض # تنبيهًا إضافيًا}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"إغلاق"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"توسيع الخيارات وعرضها"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"تصغير"</string>
+ <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_gear_label" msgid="5175877094379694098">"الإعدادات"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"المعلومات"</string>
</resources>
diff --git a/PermissionController/res/values-ar-v34/strings.xml b/PermissionController/res/values-ar-v34/strings.xml
new file mode 100644
index 000000000..5a0d25e63
--- /dev/null
+++ b/PermissionController/res/values-ar-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-ar/strings.xml b/PermissionController/res/values-ar/strings.xml
index 93af53261..92353fe85 100644
--- a/PermissionController/res/values-ar/strings.xml
+++ b/PermissionController/res/values-ar/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"السماح بالكل دومًا"</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>
@@ -64,7 +71,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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"تمّ اكتشاف طبقة متراكبة للشاشة."</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"لتغيير إعداد هذا الإذن، يتعيَّن عليك أولاً إيقاف الطبقة المتراكبة للشاشة من الإعدادات &gt; التطبيقات"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"فتح الإعدادات"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{يوم واحد}zero{# يوم}two{يومان}few{# أيام}many{# يومًا}other{# يوم}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{ساعة واحدة}zero{# ساعة}two{ساعتان}few{# ساعات}many{# ساعةً}other{# ساعة}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{دقيقة واحدة}zero{# دقيقة}two{دقيقتان}few{# دقائق}many{# دقيقةً}other{# دقيقة}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{ثانية واحدة}zero{# ثانية}two{ثانيتان}few{# ثوانٍ}many{# ثانيةً}other{# ثانية}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{يوم واحد}zero{# يوم}two{يومان}few{# أيام}many{# يومًا}other{# يوم}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{ساعة واحدة}zero{# ساعة}two{ساعتان}few{# ساعات}many{# ساعةً}other{# ساعة}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{دقيقة واحدة}zero{# دقيقة}two{دقيقتان}few{# دقائق}many{# دقيقة}other{# دقيقة}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{ثانية واحدة}zero{# ثانية}two{ثانيتان}few{# ثوانٍ}many{# ثانيةً}other{# ثانية}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"أيّ إذن"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"أي وقت"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"آخر 7 أيام"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"آخر 24 ساعة"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"آخر ساعة"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"آخر 15 دقيقة"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"الدقيقة الماضية"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{آخر يوم}zero{آخر # يوم}two{آخر يومَين}few{آخر # أيام}many{آخر # يومًا}other{آخر # يوم}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{آخر ساعة}zero{آخر # ساعة}two{آخر ساعتين}few{آخر # ساعات}many{آخر # ساعة}other{آخر # ساعة}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{آخر دقيقة}zero{آخر # دقيقة}two{آخر دقيقتين}few{آخر # دقائق}many{آخر # دقيقة}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>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"استخدام الإذن خلال الساعة الأخيرة"</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">"استخدام الإذن خلال الدقيقة الماضية"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"لم يتم استخدام الإذن في آخر 24 ساعة."</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"لم يتم استخدام الإذن في آخر 7 أيام."</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{لم يتم استخدام الإذن في اليوم السابق.}zero{لم يتم استخدام الإذن في الأيام الـ # السابقة.}two{لم يتم استخدام الإذن في اليومين السابقين.}few{لم يتم استخدام الإذن في الأيام الـ # السابقة.}many{لم يتم استخدام الإذن في الأيام الـ # السابقة.}other{لم يتم استخدام الإذن في الأيام الـ # السابقة.}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{لم يتم استخدام الإذن خلال الساعة السابقة}zero{لم يتم استخدام الإذن خلال الساعات الـ # السابقة.}two{لم يتم استخدام الإذن خلال الساعتين السابقتين.}few{لم يتم استخدام الإذن خلال الساعات الـ # السابقة.}many{لم يتم استخدام الإذن خلال الساعات الـ # السابقة.}other{لم يتم استخدام الإذن خلال الساعات الـ # السابقة.}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{يستخدِمه تطبيق واحد.}zero{يستخدِمه # تطبيق.}two{يستخدِمه تطبيقان.}few{يستخدِمه # تطبيقات.}many{يستخدِمه # تطبيقًا.}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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"السماح بالكل دومًا"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"الطلب في كل مرة"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"عدم السماح"</string>
<string name="precise_image_description" msgid="6349638632303619872">"الموقع الجغرافي الدقيق"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"ستتم إزالة إذنَي <xliff:g id="PERM_0">%1$s</xliff:g> و<xliff:g id="PERM_1">%2$s</xliff:g>."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"الأذونات التي ستتم إزالتها: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"إدارة الأذونات تلقائيًا"</string>
- <string name="off" msgid="1438489226422866263">"إيقاف"</string>
<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_tv_summary" msgid="3685907153054355671">"في حال عدم استخدام تطبيق لبضعة أشهر:\n\n• تتم إزالة الأذونات لحماية بياناتك.\n• تتم إزالة الملفات المؤقَّتة لإخلاء بعض المساحة.\n\nللسماح بالأذونات مرة أخرى، ما عليك غير فتح التطبيق."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"تم فتح هذه التطبيقات آخر مرة قبل أكثر من <xliff:g id="NUMBER">%s</xliff:g> شهر"</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_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>
@@ -243,7 +246,7 @@
<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_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>
@@ -251,9 +254,9 @@
<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="3447767892295843282">"{count,plural, =1{ساعة واحدة}zero{# ساعة}two{ساعتان}few{# ساعات}many{# ساعةً}other{# ساعة}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{دقيقة واحدة}zero{# دقيقة}two{دقيقتان}few{# دقائق}many{# دقيقةً}other{# دقيقة}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{ثانية واحدة}zero{# ثانية}two{ثانيتان}few{# ثوانٍ}many{# ثانيةً}other{# ثانية}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{ساعة واحدة}zero{# ساعة}two{ساعتان}few{# ساعات}many{# ساعةً}other{# ساعة}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{دقيقة واحدة}zero{# دقيقة}two{دقيقتان}few{# دقائق}many{# دقيقةً}other{# دقيقة}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{ثانية واحدة}zero{# ثانية}two{ثانيتان}few{# ثوانٍ}many{# ثانية}other{# ثانية}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"تذكيرات الأذونات"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"تطبيق واحد غير مستخدم"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"عدد التطبيقات غير المُستخدمة: <xliff:g id="NUMBER_OF_APPS">%s</xliff:g>"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"لم يتم استخدام بعض التطبيقات منذ عدة أشهر. انقر لمراجعة الأذونات."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{تطبيق واحد غير مستخدَم}zero{# تطبيق غير مستخدَم}two{تطبيقان غير مستخدَمين}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>
+ <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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"‏نظام Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"تمت إزالة أذونات التطبيقات لحماية الخصوصية"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"لم يتم استخدام <xliff:g id="APP_NAME">%s</xliff:g> منذ بضعة أشهر. انقر لمراجعة الأذونات."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"لم يتم استخدام <xliff:g id="APP_NAME">%s</xliff:g> وتطبيق واحد آخر منذ بضعة أشهر. انقر لمراجعة الأذونات."</string>
@@ -321,7 +340,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>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"ملاحظات"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"الأذونات خاضعة لتحكّم المشرف"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"يمكن الوصول إلى الموقع الجغرافي"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"يسمح مشرف تكنولوجيا المعلومات لتطبيق <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"الأمان والخصوصية"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"فحص"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"أذونات أدوات الاستشعار"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"عناصر التحكّم في الخصوصية"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"تمت إزالة الإذن."</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"عرض المزيد من المعلومات عن استخدام الكاميرا"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"عرض المزيد من المعلومات عن استخدام الميكروفون"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"إزالة إذن الكاميرا"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"إزالة إذن الميكروفون"</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="manage_service_qs" msgid="7862555549364153805">"إدارة الخدمة"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"إدارة الأذونات"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"يتم الاستخدام في المكالمة الهاتفية"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"الأمان والخصوصية"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"فحص الحالة"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"مراسلات المطوّر"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{تم التعديل خلال آخر 24 ساعة}=1{تم التعديل خلال آخر 24 ساعة}two{تم التعديل خلال آخر يومَين}few{تم التعديل خلال آخر # أيام}many{تم التعديل خلال آخر # يومًا}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>
</resources>
diff --git a/PermissionController/res/values-as-v33/strings.xml b/PermissionController/res/values-as-v33/strings.xml
index eb541c5fe..db8b95d3e 100644
--- a/PermissionController/res/values-as-v33/strings.xml
+++ b/PermissionController/res/values-as-v33/strings.xml
@@ -19,4 +19,28 @@
<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_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>
+ <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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"বন্ধ কৰক"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"বিস্তাৰ কৰক আৰু বিকল্পসমূহ দেখুৱাওক"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"সংকোচন কৰক"</string>
+ <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_gear_label" msgid="5175877094379694098">"ছেটিং"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"তথ্য"</string>
</resources>
diff --git a/PermissionController/res/values-as-v34/strings.xml b/PermissionController/res/values-as-v34/strings.xml
new file mode 100644
index 000000000..219f79370
--- /dev/null
+++ b/PermissionController/res/values-as-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-as/strings.xml b/PermissionController/res/values-as/strings.xml
index 54321095d..2656530e4 100644
--- a/PermissionController/res/values-as/strings.xml
+++ b/PermissionController/res/values-as/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"আটাইবোৰকে সদায় অনুমতি দিয়ক"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"স্ক্ৰীন অভাৰলে\' চিনাক্ত কৰা হৈছে"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"এই অনুমতিৰ ছেটিং সলনি কৰিবলৈ আপুনি প্ৰথমে ছেটিংসমূহ &gt; এপসমূহলৈ গৈ স্ক্ৰীন অভাৰলে\' অফ কৰিব লাগিব"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"ছেটিং খোলক"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"এপে যোৱা ৭ দিনত আপোনাৰ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{১ দিন}one{# দিন}other{# দিন}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{১ ঘণ্টা}one{# ঘণ্টা}other{# ঘণ্টা}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{১ মিনিট}one{# মিনিট}other{# মিনিট}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{১ ছেকেণ্ড}one{# ছেকেণ্ড}other{# ছেকেণ্ড}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# দিন}one{# দিন}other{# দিন}}"</string>
+ <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_time" msgid="3802087027301631827">"যিকোনো সময়ত"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"যোৱা ৭ দিনত"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"যোৱা ২৪ ঘণ্টাত"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"যোৱা ১ ঘণ্টাত"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"যোৱা ১৫ মিনিটত"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"যোৱা ১ মিনিটত"</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>
+ <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">"যোৱা ৭ দিনত একেবাৰে শেহতীয়া এক্সেছ"</string>
@@ -158,8 +161,8 @@
<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_preference_summary_not_used_24h" msgid="3087783232178611025">"যোৱা ২৪ ঘণ্টাত ব্যৱহাৰ কৰা হোৱা নাই"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"যোৱা ৭ দিনত ব্যৱহাৰ কৰা হোৱা নাই"</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>
<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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"আটাইবোৰকে সদায় অনুমতি দিয়ক"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"প্ৰতিবাৰতে সোধক"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"অনুমতি নিদিব"</string>
<string name="precise_image_description" msgid="6349638632303619872">"সঠিক অৱস্থান"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> আৰু <xliff:g id="PERM_1">%2$s</xliff:g>ৰ অনুমতিসমূহ আঁতৰোৱা হ’ব।"</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"আঁতৰাবলগা অনুমতিসমূহ: <xliff:g id="PERMS">%1$s</xliff:g>।"</string>
<string name="auto_manage_title" msgid="7693181026874842935">"অনুমতিসমূহ স্বয়ংক্ৰিয়ভাৱে পৰিচালনা কৰক"</string>
- <string name="off" msgid="1438489226422866263">"অফ আছে"</string>
<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_tv_summary" msgid="3685907153054355671">"কোনো এপ্‌ কেইমাহমানৰ বাবে ব্যৱহাৰ নকৰাকৈ থাকিলে:\n\n• আপোনাৰ ডেটা সুৰক্ষিত কৰিবলৈ অনুমতিসমূহ আঁতৰোৱা হয়\n• ঠাই খালী কৰিবলৈ অস্থায়ী ফাইলসমূহ আঁতৰোৱা হয়\n\nপুনৰ অনুমতি দিবলৈ এপ্‌টো খোলক।"</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"<xliff:g id="NUMBER">%s</xliff:g> মাহ পূর্বে অন্তিমবাৰ খোলা হৈছিল"</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>
<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,9 +254,9 @@
<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="3447767892295843282">"{count,plural, =1{১ ঘণ্টা}one{# ঘণ্টা}other{# ঘণ্টা}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{১ মিনিট}one{# মিনিট}other{# মিনিট}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{১ ছেকেণ্ড}one{# ছেকেণ্ড}other{# ছেকেণ্ড}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# ঘণ্টা}one{# ঘণ্টা}other{# ঘণ্টা}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# মিনিট}one{# মিনিট}other{# মিনিট}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# ছেকেণ্ড}one{# ছেকেণ্ড}other{# ছেকেণ্ড}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"অনুমতি বিষয়ক ৰিমাইণ্ডাৰ"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"১ টা অব্যৱহৃত এপ্‌"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> টা অব্যৱহৃত এপ্‌"</string>
@@ -262,6 +265,9 @@
<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>
+ <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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android ছিষ্টেম"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"গোপনীয়তা সুৰক্ষিত কৰিবলৈ এপৰ অনুমতিসমূহক আঁতৰোৱা হ\'ল"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> কেইমাহমান ব্যৱহাৰ কৰা হোৱা নাই। পর্যালোচনা কৰিবলৈ টিপক।"</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> আৰু অন্য এটা এপ্ কেইমাহমান ব্যৱহাৰ কৰা হোৱা নাই। পর্যালোচনা কৰিবলৈ টিপক।"</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"টোকা"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"নিয়ন্ত্ৰিত অনুমতিসমূহ"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"অৱস্থান এক্সেছ কৰিব পাৰি"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"আপোনাৰ আইটি প্ৰশাসকে <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"সুৰক্ষা আৰু গোপনীয়তা"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"স্কেন কৰক"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"ছেন্সৰৰ অনুমতি"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"গোপনীয়তাৰ নিয়ন্ত্ৰণ"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"অনুমতি আঁতৰোৱা হ’ল"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"কেমেৰাৰ অধিক ব্যৱহাৰ চাওক"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"মাইক্ৰ’ফ’নৰ অধিক ব্যৱহাৰ চাওক"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"কেমেৰাৰ অনুমতি আঁতৰাওক"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"মাইক্ৰ’ফ’নৰ অনুমতি আঁতৰাওক"</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="manage_service_qs" msgid="7862555549364153805">"সেৱা পৰিচালনা কৰক"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"অনুমতি পৰিচালনা কৰক"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"ফ’ন কলে ব্যৱহাৰ কৰি আছে"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"সুৰক্ষা আৰু গোপনীয়তা"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"স্থিতি পৰীক্ষা কৰক"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"বিকাশকৰ্তাৰ যোগাযোগ"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{কালিৰ ভিতৰত আপডে’ট কৰা হৈছে}=1{কালিৰ ভিতৰত আপডে’ট কৰা হৈছে}one{# দিনৰ ভিতৰত আপডে’ট কৰা হৈছে}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>
</resources>
diff --git a/PermissionController/res/values-az-v33/strings.xml b/PermissionController/res/values-az-v33/strings.xml
index cd37967b6..da3e73e74 100644
--- a/PermissionController/res/values-az-v33/strings.xml
+++ b/PermissionController/res/values-az-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Bu tətbiqə Sizə Bildirişlər göndərmək üçün icazə veriləcək və Kamera, Kontaktlar, Mikrofon, Telefon və SMS-ə giriş icazəsi veriləcək"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Bu tətbiqə Sizə Bildirişlər göndərmək üçün icazə veriləcək və Kamera, Kontaktlar, Fayllar, Mikrofon, Telefon və SMS\'ə giriş icazəsi veriləcək"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Bu icazəsi olan tətbiqlər bu cihazdakı bütün fayllara giriş edə bilər"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"İş siyasətiniz haqqında məlumat"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Ayarlar IT admininiz tərəfindən idarə edilir"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Genişləndirin və siyahını göstərin"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Siyahını yığcamlaşdırın və ayarları gizlədin"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Siyahı. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Siyahı. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Əməliyyat tələb olunur. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Siyahı elementi. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Bağlayın"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Genişləndirin və seçimləri göstərin"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Yığcamlaşdırın"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Keçirin. <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">"Dəyişdirin"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Açın"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Ayarları nəzərdən keçirin"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Ayarlar"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Məlumat"</string>
</resources>
diff --git a/PermissionController/res/values-az-v34/strings.xml b/PermissionController/res/values-az-v34/strings.xml
new file mode 100644
index 000000000..7e403dadc
--- /dev/null
+++ b/PermissionController/res/values-az-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Güvənlik və məxfilik"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Nizamlayıcılar"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Tətbiqin sağlamlıq datasına girişini idarə edin"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Məkana giriş"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Tətbiq və xidmətlər üçün. Bu ayar deaktivdirsə, təcili nömrəyə zəng etdikdə mikrofon datası yenə də paylaşıla bilər"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Tətbiq və xidmətlər üçün"</string>
+</resources>
diff --git a/PermissionController/res/values-az/strings.xml b/PermissionController/res/values-az/strings.xml
index 2ce4dfc22..a517d458f 100644
--- a/PermissionController/res/values-az/strings.xml
+++ b/PermissionController/res/values-az/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Geri"</string>
<string name="available" msgid="6007778121920339498">"Əlçatan"</string>
<string name="blocked" msgid="9195547604866033708">"Bloklanıb"</string>
+ <string name="on" msgid="280241003226755921">"Aktiv"</string>
+ <string name="off" msgid="1438489226422866263">"Deaktiv"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Ləğv edin və ya deaktiv edin"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Tətbiq tapılmadı"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"İcazə verməyin"</string>
@@ -30,11 +32,16 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"“Tətbiq istifadə edilən zaman” saxlansın"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"“Ancaq bu dəfə” saxlanılsın"</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"İstənilən halda icazə verməyin"</string>
<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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Ekran örtüyü aşkarlandı"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Bu icazə ayarını dəyişdirmək üçün əvvəldə Ayarlar və Tətbiqlər bölməsindən ekran örtüyünü deaktiv etməlisiniz"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Ayarları açın"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"<xliff:g id="PERMGROUP">%1$s</xliff:g> icazənizin son 7 gün ərzində tətbiqlərin nə zaman istifadə edildiyini göstərən taymlayn"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Bu tətbiqin <xliff:g id="PERMGROUP">%1$s</xliff:g> icazənizdən istifadə etdiyi vaxt"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Ətraflı məlumat"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"<xliff:g id="PERMGROUP">%1$s</xliff:g> haqqında ətraflı məlumat"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"<xliff:g id="PERMGROUP">%1$s</xliff:g> üçün tətbiq girişinə nəzarət edin"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 gün}other{# gün}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 saat}other{# saat}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 dəq}other{# dəq}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 san}other{# san}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# gün}other{# gün}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# saat}other{# saat}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# dəq}other{# dəq}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# san}other{# san}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Hər hansı icazə"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"İstənilən vaxt"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Son 7 gün"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Son 24 saat"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Son 1 saat"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Son 15 dəqiqə"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Son 1 dəqiqə"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Son # gün}other{Son # gün}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Son # saat}other{Son # saat}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Son # dəqiqə}other{Son # dəqiqə}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"İcazələrdən istifadə olunmayıb"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"İstənilən vaxt üçün fəaliyyət"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Son 7 gün ərzindəki fəaliyyət"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Son 1 saat ərzində icazə istifadəsi"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Son 15 dəqiqə ərzində icazə istifadəsi"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Son 1 dəqiqə ərinzdə icazə istifadəsi"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Son 24 saat ərzində istifadə edilməyib"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Son 7 gün ərzində istifadə edilməyib"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Son # gün ərzində istifadə edilməyib}other{Son # gün ərzində istifadə edilməyib}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Son # saat ərzində istifadə edilməyib}other{Son # saat ərzində istifadə edilməyib}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{1 tətbiq istifadə edir}other{# tətbiq istifadə edir}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Hamısına İdarə panelində baxın"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrlədi: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Yalnız mediaya giriş icazəsi verin"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Həmişə icazə verin"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Yalnız istifadə zamanı"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Həmişə hamısına icazə verin"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Həmişə soruşulsun"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"İcazə verməyin"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Dəqiq məkan"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> və <xliff:g id="PERM_1">%2$s</xliff:g> icazələri silinəcək."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Silinəcək icazələr: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"İcazələrin avtomatik idarə edilməsi"</string>
- <string name="off" msgid="1438489226422866263">"Deaktiv"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"<xliff:g id="PERMISSION_NAME">%s</xliff:g> icazəsi silindi"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> və <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> icazəsi silindi"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> və digər <xliff:g id="NUMBER">%2$s</xliff:g> icazə silindi"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"İstifadə olunmayan tətbiqlər"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Tətbiq bir neçə ay istifadə edilmirsə:\n\n• Datanızı qorumaq üçün icazələr silinir\n• Enerjiyə qənaət üçün bildirişlər dayandırılır\n• Yer boşaltmaq üçün müvəqqəti fayllar silinir\n\nİcazələrə və bildirişlərə yenidən icazə vermək üçün tətbiqi açın."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Tətbiq bir neçə ay istifadə edilmirsə:\n\n• Datanızı qorumaq üçün icazələr silinir\n• Yer boşaltmaq üçün müvəqqəti fayllar silinir\n\nYenidən icazə vermək üçün tətbiqi açın."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Sonuncu dəfə ən azı <xliff:g id="NUMBER">%s</xliff:g> ay əvvəl açılıb"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Tətbiq bir ay istifadə edilmirsə:\n\n• Datanızı qorumaq üçün icazələr silinir\n• Yer boşaltmaq üçün müvəqqəti fayllar silinir\n\nYenidən icazə vermək üçün tətbiqi açın."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Sonuncu dəfə ən azı # ay əvvəl açılıb}other{Sonuncu dəfə ən azı # ay əvvəl açılıb}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Tətbiq sonuncu dəfə <xliff:g id="DATE">%s</xliff:g> tarixində açılıb"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Sonuncu dəfə <xliff:g id="DATE">%s</xliff:g> tarixində açılıb"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Bununla, tətbiq bu və ya qoşulmuş cihazlarda ümumi yaddaşdakı bütün fayllara daxil ola, dəyişiklik edə və ya onları silə bilər. Fayllara sizdən xəbərsiz girə bilər."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"İcazə verilməyib"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Bütün fayllara giriş edə bilən digər tətbiqlərə baxın"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 gün}other{# gün}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 saat}other{# saat}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 dəqiqə}other{# dəqiqə}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 saniyə}other{# saniyə}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# saat}other{# saat}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# dəqiqə}other{# dəqiqə}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# saniyə}other{# saniyə}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"İcazə xatırladıcıları"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 tətbiq istifadə edilmir"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> istifadə olunmayan tətbiq"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Bəzi tətbiqlər bir neçə aydır ki, istifadə edilməyib. Nəzərdən keçirmək üçün toxunun."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# istifadə olunmayan tətbiq}other{# istifadə olunmayan tətbiq}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"İcazə ləğv edildi, müvəqqəti fayllar silindi və bildirişlər söndürüldü. Ətraflı məlumat üçün toxunun."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"İcazələri silinmiş tətbiqləri nəzərdən keçirin"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Bir müddət istifadə etmədiyiniz tətbiqlər üçün icazələr və müvəqqəti fayllar silinib və bildirişlər dayandırılıb."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Tətbiqləri nəzərdən keçirin"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Son icazələri yoxlayın"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Avtomobil sürərkən <xliff:g id="APP">%1$s</xliff:g> tətbiqinə <xliff:g id="PERMISSION">%2$s</xliff:g> icazəsi vermisiniz"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Avtomobil sürərkən <xliff:g id="APP">%1$s</xliff:g> tətbiqinə <xliff:g id="PERMISSION_1">%2$s</xliff:g> və <xliff:g id="PERMISSION_2">%3$s</xliff:g> icazəsi vermisiniz"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Məxfiliyinizi qorumaq üçün icazələr silinib"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> arxa fonda məkanınıza daxil oldu"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Bu tətbiq daima məkana daxil ola bilər. Dəyişmək üçün klikləyin."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Bildirişlərinizə girişi olan tətbiqi nəzərdən keçirin"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> bildirişlərinizi qapada, əməliyyat edə və məzmuna giriş edə bilər"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Bu tətbiq bildirişlərinizi qapada, əməliyyat edə və məzmuna giriş edə bilər. Bəzi tətbiqlər nəzərdə tutulduğu kimi işləmək üçün bu girişə ehtiyac duyur."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Girişi silin"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Digər seçimlərə baxın"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Giriş silindi"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Tam cihaz girişi olan tətbiqi nəzərdən keçirin"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> ekranınıza baxa və cihazınızda əməliyyatlar edə bilər. Əlçatımlılıq tətbiqləri nəzərdə tutulduğu kimi işləmək üçün bu cür girişə ehtiyac duyur."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Bu tətbiq ekranınıza baxa və cihazınızda əməliyyatlar edə bilər. AccessibƏlçatımlılıq tətbiqləri nəzərdə tutulduğu kimi işləmək üçün bu cür girişə ehtiyac duyur, lakin tətbiqi yoxlayın və ona etibar etdiyinizə əmin olun."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Girişi silin"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Tam girişi olan tətbiqlərə baxın"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Giriş silindi"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android Sistemi"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Məxfiliyi qorumaq üçün tətbiq icazələri silindi"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> bir neçə aydır ki, istifadə edilməyib. Nəzərdən keçirmək üçün toxunun."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> və digər 1 tətbiq bir neçə aydır ki, istifadə edilməyib. Nəzərdən keçirmək üçün toxunun."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirişlərinizə, Telefon, SMS, Kontaktlar və Təqvimə giriş əldə edəcək."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirişlərinizə giriş əldə edəcək və tətbiqlərinizi qoşulmuş cihazda yayımlaya biləcək"</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Bu xidmət telefonunuzdakı foto, media və bildirişləri digər cihazlarla paylaşır."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Defolt qeyd tətbiqi"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"İdarə edilən icazələr"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Məkana giriş edilə bilər"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"İT admininiz <xliff:g id="APP_NAME">%s</xliff:g> tətbiqinə məkanınıza giriş icazəsi verir"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Tətbiqlər və xidmətlər üçün"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Fövqəladə hallar nömrəsinə zəng etdiyiniz zaman mikrofon datası yenə də paylaşıla bilər."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Dəyişin"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Güvənlik və məxfilik"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Skan edin"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Güvənlik və məxfilik"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Cihazı skanlayın"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Qapadın"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Bu siqnal qapadılsın?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Daha çox qoruma əlavə etmək üçün istənilən vaxt təhlükəsizlik və məxfilik ayarlarınızı nəzərdən keçirin"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Qapadın"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Ləğv edin"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Ayarlar"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Güvənlik və məxfilik statusu. <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">"Təhlükəsizlik Ayarları"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Sensor İcazələri"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Məxfilik Nizamlayıcıları"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"İcazələr"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Güvənlik və məxfilik"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Statusu yoxlayın"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Məxfilik nəzarətləriniz"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Digər ayarlar"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Kameraya giriş"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Mikrofona giriş"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"İcazəsi silindi"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Digər kamera istifadəsinə baxın"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Digər mikrofon istifadəsinə baxın"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Kamera icazəsini silin"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Mikrofon icazəsini silin"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Son kamera istifadəsinə baxın"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Son mikrofon istifadəsinə baxın"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Bu tətbiq üçün icazəni silin"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Bu tətbiq üçün icazəni silin"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Xidməti idarə edin"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"İcazələri idarə edin"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Telefon zəngində istifadə edilir"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Bu yaxınlarda <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) tərəfindən istifadə edilib"</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>) tərəfindən istifadə edilir"</string>
<string name="recent_app_usage_2_qs" msgid="3591205954235694403">"Bu yaxınlarda <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>) tərəfindən istifadə edilib"</string>
- <string name="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Güvənlik və məxfilik"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Statusu yoxlayın"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Təsdiq"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Geriyə"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Digər fayllara da giriş etməyə icazə veriləcək"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Bu tətbiq Android\'in ən son versiyasını dəstəkləmir. Əgər bu tətbiq musiqi və audio fayllarına giriş edə bilmirsə, ona foto və videolara da giriş etməyə icazə verilməyəcək."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Bu tətbiq Android\'in ən son versiyasını dəstəkləmir. Əgər bu tətbiq foto və video fayllarına giriş edə bilirsə, ona musiqi və audio fayllarına da giriş etməyə icazə veriləcək."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Bu tətbiq Android\'in ən son versiyasını dəstəkləmir. Əgər bu tətbiq musiqi və audio fayllarına giriş edə bilmirsə, ona foto və videolara da giriş etməyə icazə verilməyəcək."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Arxa fon məkanına girişi olan tətbiqi nəzərdən keçirin"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> bağlı olsa belə, həmişə məkanınıza giriş edə bilər"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Arxa fon məkanına girişi olan tətbiqi nəzərdən keçirin"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Tətbiq bağlı olsa belə, məkana daxil ola bilər.\n\nBəzi təhlükəsizlik və fövqəladə hal tətbiqləri lazımi qaydada işləmək üçün arxa fonda məkana giriş tələb edir."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Giriş dəyişdirildi"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Ən son məkan istifadəsinə baxın"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Məxfilik kontrolları"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Kameraya giriş"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Mikrofona giriş"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Tətbiqlər və xidmətlər üçün"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Tətbiqlər və xidmətlər üçün. Bu ayar deaktivdirsə, fövqəladə hal nömrəsinə zəng etdiyiniz zaman mikrofon datası hələ də paylaşıla bilər."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Məkana girişi olan tətbiqlərə və xidmətlərə baxın"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Panoya giriş göstərilsin"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Tətbiq kopyalanmış mətn, şəkil və ya digər kontent işlədəndə bildiriş göstərilsin"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Parolları göstərin"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Yazarkən simvollar qısa müddət göstərilsin"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Data praktikaları tətbiq versiyası, istifadə, region və yaşınıza görə dəyişə bilər. "<annotation id="link">"Data paylaşma haqqında ətraflı"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Data praktikaları tətbiq versiyası, istifadə, region və yaşa görə dəyişə bilər."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Məkan datanız"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Bu tətbiqin girişini "<annotation id="link">"məxfilik ayarlarında"</annotation>" dəyişin"</string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Tətbiq funksionallığı"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analitik"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Developer kommunikasiyaları"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Reklam və ya marketinq"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Dələduzluğun qarşısının alınması, güvənlik və uyğunluq"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Fərdiləşdirmə"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Hesabın idarə edilməsi"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Bu tətbiqlərin developerləri data paylaşımı təcrübələri haqqında məlumatı tətbiq mağazasına təqdim edib. Bu məlumat zaman keçdikcə yenilənə bilər.\n\nData paylaşımı təcrübələri tətbiq versiyası, istifadə, region və yaşa görə dəyişə bilər."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Data paylaşması haqqında məlumat əldə edin"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Məkan datası artıq üçüncü tərəflərlə paylaşılır"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Məkan datası artıq reklam və ya marketinq üçün üçüncü tərəflərlə paylaşılır"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Son gün ərzində yenilənib}=1{Son gün ərzində yenilənib}other{# gün ərzində yenilənib}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Hazırda yenilik yoxdur"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-b+sr+Latn-v33/strings.xml b/PermissionController/res/values-b+sr+Latn-v33/strings.xml
index f9305ad07..acc79ac84 100644
--- a/PermissionController/res/values-b+sr+Latn-v33/strings.xml
+++ b/PermissionController/res/values-b+sr+Latn-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Ovoj aplikaciji će biti dozvoljeno da vam šalje obaveštenja i dobiće pristup kameri, kontaktima, mikrofonu, telefonu i SMS-ovima"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Ovoj aplikaciji će biti dozvoljeno da vam šalje obaveštenja i dobiće pristup kameri, kontaktima, fajlovima, mikrofonu, telefonu i SMS-ovima"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Aplikacija sa ovom dozvolom može da pristupa svim fajlovima na ovom uređaju"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Informacije o smernicama za posao"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Podešavanjima upravlja IT administrator"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Proširi i prikaži listu"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Skupi listu i sakrij podešavanja"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Lista: <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_with_actions_needed_content_description" msgid="2708884606775932657">"Lista: <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Treba da reagujete. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Stavka liste. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Zatvori"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Proširi i prikaži opcije"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Skupi"</string>
+ <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">"Prikaži pregled podešavanja"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Podešavanja"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Informacije"</string>
</resources>
diff --git a/PermissionController/res/values-b+sr+Latn-v34/strings.xml b/PermissionController/res/values-b+sr+Latn-v34/strings.xml
new file mode 100644
index 000000000..d5bf45128
--- /dev/null
+++ b/PermissionController/res/values-b+sr+Latn-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Bezbednost i privatnost"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Kontrole"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Povezivanje zdravlja"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Upravljajte pristupom aplikacija podacima o zdravlju"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Pristup lokaciji"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Za aplikacije i usluge. Ako je ovo podešavanje isključeno, podaci mikrofona mogu i dalje da se dele kada pozovete broj za hitne slučajeve"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Za aplikacije i usluge"</string>
+</resources>
diff --git a/PermissionController/res/values-b+sr+Latn/strings.xml b/PermissionController/res/values-b+sr+Latn/strings.xml
index ea45b4a57..510680ef7 100644
--- a/PermissionController/res/values-b+sr+Latn/strings.xml
+++ b/PermissionController/res/values-b+sr+Latn/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Nazad"</string>
<string name="available" msgid="6007778121920339498">"Dostupno"</string>
<string name="blocked" msgid="9195547604866033708">"Blokirano"</string>
+ <string name="on" msgid="280241003226755921">"Uključeno"</string>
+ <string name="off" msgid="1438489226422866263">"Isključeno"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Deinstaliraj ili onemogući"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Aplikacija nije pronađena"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Ne dozvoli"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Zadrži „Dok se aplikacija koristi“"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Zadrži Samo ovaj put"</string>
<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_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">"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>
@@ -107,9 +114,6 @@
<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="screen_overlay_title" msgid="6977038513913222078">"Otkriven je element koji prekriva sadržaj ekrana"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Da biste promenili podešavanje ove dozvole, prvo treba da isključite element koji prekriva sadržaj ekrana u odeljku Podešavanja &gt; Aplikacije"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Otvori podešavanja"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Hronologija korišćenja grupe dozvola <xliff:g id="PERMGROUP">%1$s</xliff:g> od strane aplikacija u poslednjih 7 dana"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Kada je ova aplikacija koristila dozvolu <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Saznajte više"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Saznajte više o grupi <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Kontrolišite pristup aplikacije dozvoli <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 dan}one{# dan}few{# dana}other{# dana}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 sat}one{# sat}few{# sata}other{# sati}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}one{# min}few{# min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 sek}one{# sek}few{# sek}other{# sek}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# dan}one{# dan}few{# dana}other{# dana}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# sat}one{# sat}few{# sata}other{# sati}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}one{# min}few{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# sek}one{# sek}few{# sek}other{# sek}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Bilo koja dozvola"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Bilo kada"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Poslednjih 7 dana"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Poslednja 24 sata"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Poslednji sat"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Poslednjih 15 minuta"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Poslednji minut"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Poslednji # dan}one{Poslednji # dan}few{Poslednja # dana}other{Poslednjih # dana}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Poslednji # sat}one{Poslednji # sat}few{Poslednja # sata}other{Poslednjih # sati}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Poslednji # minut}one{Poslednji # minut}few{Poslednja # minuta}other{Poslednjih # minuta}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Dozvole nisu korišćene"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Najskoriji pristup u bilo kom trenutku"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Najskoriji pristup u poslednjih 7 dana"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Korišćenje dozvola u poslednjih sat vremena"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Korišćenje dozvole u poslednjih 15 minuta"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Korišćenje dozvola u poslednjem minutu"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Nije korišćeno u poslednja 24 sata"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Nije korišćeno u poslednjih 7 dana"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Nije korišćeno tokom poslednjeg # dana}one{Nije korišćeno tokom poslednjeg # dana}few{Nije korišćeno tokom poslednja # dana}other{Nije korišćeno tokom poslednjih # dana}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Nije korišćeno tokom poslednjeg # sata}one{Nije korišćeno tokom poslednjeg # sata}few{Nije korišćeno tokom poslednja # sata}other{Nije korišćeno tokom poslednjih # sati}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Koristi 1 aplikacija}one{Koristi # aplikacija}few{Koriste # aplikacije}other{Koristi # aplikacija}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Prikaži sve na kontrolnoj tabli"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrirano prema: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Dozvoli samo pristup medijima"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Dozvoli uvek"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Dozv. samo dok se apl. koristi"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Uvek dozvoli sve"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Pitaj svaki put"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Ne dozvoli"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Precizna lokacija"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Ukloniće se dozvole: <xliff:g id="PERM_0">%1$s</xliff:g> i <xliff:g id="PERM_1">%2$s</xliff:g>."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Dozvole koje će se ukloniti: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Upravljajte dozvolama automatski"</string>
- <string name="off" msgid="1438489226422866263">"Isključeno"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Dozvola <xliff:g id="PERMISSION_NAME">%s</xliff:g> je uklonjena"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Dozvole <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> i <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> su uklonjene"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Uklonjeno: <xliff:g id="PERMISSION_NAME">%1$s</xliff:g> i još <xliff:g id="NUMBER">%2$s</xliff:g> dozvole"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Aplikacije koje se ne koriste"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Ako ne koristite aplikaciju nekoliko meseci:\n\n• dozvole se uklanjaju da bi se zaštitili podaci\n• obaveštenja se zaustavljaju da bi se štedela baterija\n• privremeni fajlovi se uklanjaju da bi se oslobodio prostor\n\nDa biste ponovo omogućili dozvole i obaveštenja, otvorite aplikaciju."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Ako ne koristite aplikaciju nekoliko meseci:\n\n• dozvole se uklanjaju da bi se zaštitili podaci\n• privremeni fajlovi se uklanjaju da bi se oslobodio prostor\n\nDa biste ponovo omogućili dozvole, otvorite aplikaciju."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Poslednji put otvoreno pre više od <xliff:g id="NUMBER">%s</xliff:g> mes."</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Ako ne koristite aplikaciju mesec dana:\n\n• dozvole se uklanjaju da bi se zaštitili podaci\n• privremeni fajlovi se uklanjaju da bi se oslobodio prostor\n\nDa biste ponovo omogućili dozvole, otvorite aplikaciju."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Poslednji put otvoreno pre više od # meseca}one{Poslednji put otvoreno pre više od # meseca}few{Poslednji put otvoreno pre više od # meseca}other{Poslednji put otvoreno pre više od # meseci}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Aplikacija je poslednji put otvorena: <xliff:g id="DATE">%s</xliff:g>"</string>
<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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Nije dozvoljeno"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Prikaži još aplikacija sa pristupom svim fajlovima"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 dan}one{# dan}few{# dana}other{# dana}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 sat}one{# sat}few{# sata}other{# sati}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minut}one{# minut}few{# minuta}other{# minuta}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 sekunda}one{# sekunda}few{# sekunde}other{# sekundi}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# sat}one{# sat}few{# sata}other{# sati}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minut}one{# minut}few{# minuta}other{# minuta}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# sekunda}one{# sekunda}few{# sekunde}other{# sekundi}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Podsetnici za dozvole"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 aplikacija koja se ne koristi"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"Aplikacija koje se ne koriste: <xliff:g id="NUMBER_OF_APPS">%s</xliff:g>"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Neke aplikacije nisu korišćene par meseci. Dodirnite da biste pregledali."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# aplikacija koja se ne koristi}one{# aplikacija koje se ne koristi}few{# aplikacije koje se ne koriste}other{# aplikacija koje se ne koriste}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Dozvole i privremeni fajlovi su uklonjeni i obaveštenja su zaustavljena. Dodirnite da biste pregledali."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Pregledajte aplikacije sa uklonjenim dozvolama"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Za aplikacije koje niste koristili neko vreme, dozvole i privremeni fajlovi su uklonjeni, a obaveštenja su zaustavljena."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Pregledajte aplikacije"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Proverite nedavne dozvole"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Tokom vožnje ste dali aplikaciji <xliff:g id="APP">%1$s</xliff:g> pristup dozvoli <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Tokom vožnje ste dali aplikaciji <xliff:g id="APP">%1$s</xliff:g> pristup dozvolama <xliff:g id="PERMISSION_1">%2$s</xliff:g> i <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Dozvole su uklonjene radi zaštite privatnosti"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> ima vašu lokaciju u pozadini"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Ova aplikacija može uvek da pristupa lokaciji. Dodirnite da biste to promenili."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Pregledajte aplikaciju sa pristupom obaveštenjima"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> može da reaguje, odbacuje i pristupa sadržaju u obaveštenjima"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Ova aplikacija može da reaguje, odbacuje i pristupa sadržaju u obaveštenjima. Nekim aplikacijama je potreban ovakav tip pristupa da bi funkcionisale kao što je predviđeno."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Ukloni pristup"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Prikaži još opcija"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Pristup je uklonjen"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Pregledajte aplikaciju sa punim pristupom uređaju"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> može da pregleda sadržaj ekrana i obavlja radnje na vašem uređaju. Aplikacijama za pristupačnost je potreban ovakav tip pristupa da bi funkcionisale kao što je predviđeno."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Ova aplikacija može da pregleda sadržaj ekrana i obavlja radnje na vašem uređaju. Aplikacijama za pristupačnost je potreban ovakav tip pristupa da bi funkcionisale kao što je predviđeno, ali proverite aplikaciju i uverite se da je pouzdana."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Ukloni pristup"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Prikaži aplikacije sa punim pristupom"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Pristup je uklonjen"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android sistem"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Dozvole za aplikacije su uklonjene radi zaštite privatnosti"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Aplikcija <xliff:g id="APP_NAME">%s</xliff:g> nije korišćena par meseci. Dodirnite da biste pregledali."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> i još jedna aplikacija nisu korišćene par meseci. Dodirnite da biste pregledali."</string>
@@ -378,6 +397,10 @@
<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 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>
<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>
@@ -452,6 +475,7 @@
<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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Kontrolisane dozvole"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Može da se pristupi lokaciji"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"IT administrator dozvoljava aplikaciji <xliff:g id="APP_NAME">%s</xliff:g> da pristupa lokaciji"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Za aplikacije i usluge"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Podaci mikrofona mogu i dalje da se dele kada pozovete broj za hitne slučajeve."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Promeni"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Bezbednost i privatnost"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Skeniraj"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Bezbednost i privatnost"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Skeniraj uređaj"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Odbaci"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Želite da odbacite ovo obaveštenje?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Uvek pregledajte podešavanja bezbednosti i privatnosti da biste dodali još zaštite"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Odbaci"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Otkaži"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Podešavanja"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Status bezbednosti i privatnosti. <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">"Bezbednosna podešavanja"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Dozvole za senzore"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Kontrole privatnosti"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Dozvole"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Bezbednost i privatnost"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Proverite status"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Vaše kontrole privatnosti"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Još podešavanja"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Pristup kameri"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Pristup mikrofonu"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Dozvola je uklonjena"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Prikaži još korišćenja kamere"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Prikaži još korišćenja mikrofona"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Ukloni dozvolu za kameru"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Ukloni dozvolu za mikrofon"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Pogledajte nedavnu upotrebu kamere"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Pogledajte nedavnu upotrebu mikrofona"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Uklonite dozvolu za ovu aplikaciju"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Uklonite dozvolu za ovu aplikaciju"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Upravljajte uslugom"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Upravljajte dozvolama"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Koristi ga telefonski poziv"</string>
@@ -517,8 +552,6 @@
<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>
<string name="recent_app_usage_2_qs" msgid="3591205954235694403">"Nedavno koristila 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>
- <string name="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Bezbednost i privatnost"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Proverite status"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Potvrdi"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Nazad"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Biće dozvoljen pristup i drugim fajlovima"</string>
@@ -537,4 +570,53 @@
<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="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>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Ova aplikacija uvek može da pristupa vašoj lokaciji, čak i kad je zatvorena.\n\nNeke aplikacije za bezbednost i hitne slučajeve zahtevaju pristup lokaciji u pozadini da bi radile kako treba."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Pristup je promenjen"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Prikaži nedavno korišćenje lokacije"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Kontrole privatnosti"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Pristup kameri"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Pristup mikrofonu"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Za aplikacije i usluge"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Za aplikacije i usluge. Ako je ovo podešavanje isključeno, podaci mikrofona mogu i dalje da se dele kada pozovete broj za hitne slučajeve."</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">"Prikazuj pristup privremenoj memoriji"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Prikazuje poruku kada aplikacije pristupaju tekstu, slikama ili drugom sadržaju koji ste kopirali"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Prikazuj lozinke"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Prikazuje znakove nakratko dok kucate"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Prakse za podatke mogu da se razlikuju u zavisnosti od verzije aplikacije, korišćenja, regiona i uzrasta. "<annotation id="link">"Više o deljenju podataka"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Prakse za podatke mogu da se razlikuju u zavisnosti od verzije aplikacije, korišćenja, regiona i uzrasta."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Podaci o lokaciji"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Promenite pristup ove aplikacije u "<annotation id="link">"podešavanjima privatnosti"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Funkcije aplikacije"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analitika"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Poruke programera"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Oglašavanje ili marketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Sprečavanje prevara, bezbednost i usaglašenost"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalizacija"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Upravljanje nalogom"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Programeri ovih aplikacija su pružili podatke o praksama za deljenje podataka prodavnici aplikacija. Mogu da ih ažuriraju tokom vremena.\n\nPrakse za deljenje podataka mogu da se razlikuju u zavisnosti od verzije aplikacije, korišćenja, regiona i uzrasta."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Saznajte više o deljenju podataka"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Podaci o lokaciji se sada dele sa trećim stranama"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Podaci o lokaciji se sada dele sa trećim stranama u svrhu oglašavanja ili marketinga"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Ažurirano tokom prethodnog dana}=1{Ažurirano tokom prethodnog dana}one{Ažurirano tokom prethodnog # dana}few{Ažurirano tokom prethodna # dana}other{Ažurirano tokom prethodnih # dana}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Trenutno nema ažuriranja"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-be-v33/strings.xml b/PermissionController/res/values-be-v33/strings.xml
index eb0fae33e..511ed49c6 100644
--- a/PermissionController/res/values-be-v33/strings.xml
+++ b/PermissionController/res/values-be-v33/strings.xml
@@ -19,4 +19,28 @@
<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="work_policy_title" msgid="832967780713677409">"Інфармацыя пра вашу працоўную палітыку"</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>
+ <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{Разгарніце, каб убачыць яшчэ # абвестку}few{Разгарніце, каб убачыць яшчэ # абвесткі}many{Разгарніце, каб убачыць яшчэ # абвестак}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Закрыць"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Разгарнуць і паказаць варыянты"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Згарнуць"</string>
+ <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_gear_label" msgid="5175877094379694098">"Налады"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Інфармацыя"</string>
</resources>
diff --git a/PermissionController/res/values-be-v34/strings.xml b/PermissionController/res/values-be-v34/strings.xml
new file mode 100644
index 000000000..330681ded
--- /dev/null
+++ b/PermissionController/res/values-be-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-be/strings.xml b/PermissionController/res/values-be/strings.xml
index aafc44a3a..c6e081982 100644
--- a/PermissionController/res/values-be/strings.xml
+++ b/PermissionController/res/values-be/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,10 +32,15 @@
<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_always_allow_all" msgid="1719900027660252167">"Заўсёды дазваляць усе"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Выяўлена накладанне на экран"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Каб змяніць гэту наладу дазволу, вы павінны спачатку выключыць накладанне на экран з меню \"Налады &gt; Праграмы\""</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Адкрыць налады"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 дзень}one{# дзень}few{# дні}many{# дзён}other{# дня}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 гадзіна}one{# гадзіна}few{# гадзіны}many{# гадзін}other{# гадзіны}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 хв}one{# хв}few{# хв}many{# хв}other{# хв}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 с}one{# с}few{# с}many{# с}other{# с}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# дзень}one{# дзень}few{# дні}many{# дзён}other{# дня}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# гадзіна}one{# гадзіна}few{# гадзіны}many{# гадзін}other{# гадзіны}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# хв}one{# хв}few{# хв}many{# хв}other{# хв}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# с}one{# с}few{# с}many{# с}other{# с}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Любы дазвол"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"За любы час"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"За апошнія 7 дзён"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"За апошнія 24 гадзіны"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"За апошнюю гадзіну"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"За апошнія 15 хвілін"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"За апошнюю хвіліну"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{За апошні # дзень}one{За апошні # дзень}few{За апошнія # дні}many{За апошнія # дзён}other{За апошнія # дня}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{За апошнюю # гадзіну}one{За апошнюю # гадзіну}few{За апошнія # гадзіны}many{За апошнія # гадзін}other{За апошнія # гадзіны}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{За апошнюю # хвіліну}one{За апошнюю # хвіліну}few{За апошнія # хвіліны}many{За апошнія # хвілін}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>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Выкарыстанне дазволаў за апошнюю гадзіну"</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">"Выкарыстанне дазволаў за апошнюю хвіліну"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"За апошнія 24 гадзіны доступ не выкарыстоўваўся"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"За апошнія 7 сутак доступ не выкарыстоўваўся"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{За апошнія # суткі дазвол не выкарыстоўваўся}one{За апошнія # суткі дазвол не выкарыстоўваўся}few{За апошнія # сутак дазвол не выкарыстоўваўся}many{За апошнія # сутак дазвол не выкарыстоўваўся}other{За апошнія # сутак дазвол не выкарыстоўваўся}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{За апошнюю # гадзіну дазвол не выкарыстоўваўся}one{За апошнюю # гадзіну дазвол не выкарыстоўваўся}few{За апошнія # гадзіны дазвол не выкарыстоўваўся}many{За апошнія # гадзін дазвол не выкарыстоўваўся}other{За апошнія # гадзіны дазвол не выкарыстоўваўся}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Выкарыстоўваецца 1 праграмай}one{Выкарыстоўваецца # праграмай}few{Выкарыстоўваецца # праграмамі}many{Выкарыстоўваецца # праграмамі}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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"Заўсёды дазваляць усе"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Заўсёды пытацца"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Не дазваляць"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Дакладнае месцазнаходжанне"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Дазволы \"<xliff:g id="PERM_0">%1$s</xliff:g>\" і \"<xliff:g id="PERM_1">%2$s</xliff:g>\" будуць выдалены."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Дазволы, якія будуць выдалены: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Аўтаматычнае кіраванне дазволамі"</string>
- <string name="off" msgid="1438489226422866263">"Выключыць"</string>
<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_tv_summary" msgid="3685907153054355671">"Калі праграма не выкарыстоўвалася некалькі месяцаў:\n\n• у мэтах абароны вашых даных выдаляюцца дазволы;\n• для вызвалення месца выдаляюцца часовыя файлы.\n\nКаб зноў даць дазволы, адкрыйце праграму."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Адкрывалася ў апошні раз больш за <xliff:g id="NUMBER">%s</xliff:g> мес. таму"</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{Апошні раз адкрываліся больш чым # месяц таму}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>
<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,9 +254,9 @@
<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="3447767892295843282">"{count,plural, =1{1 гадзіна}one{# гадзіна}few{# гадзіны}many{# гадзін}other{# гадзіны}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 хвіліна}one{# хвіліна}few{# хвіліны}many{# хвілін}other{# хвіліны}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 секунда}one{# секунда}few{# секунды}many{# секунд}other{# секунды}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# гадзіна}one{# гадзіна}few{# гадзіны}many{# гадзін}other{# гадзіны}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# хвіліна}one{# хвіліна}few{# хвіліны}many{# хвілін}other{# хвіліны}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# секунда}one{# секунда}few{# секунды}many{# секунд}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>
@@ -262,6 +265,9 @@
<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_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_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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Сістэма Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"У мэтах абароны прыватнасці дазволы праграмы выдалены"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Праграма \"<xliff:g id="APP_NAME">%s</xliff:g>\" не выкарыстоўвалася некалькі месяцаў. Націсніце, каб праглядзець."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> і яшчэ 1 праграма не выкарыстоўваліся некалькі месяцаў. Націсніце, каб праглядзець."</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"нататкі"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"Кіраваныя дазволы"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Доступ да даных пра месцазнаходжанне атрыманы"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Ваш ІТ-адміністратар дазваляе праграме \"<xliff:g id="APP_NAME">%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">"Iншыя дазволы"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Дазвол, які выкарыстоўваецца сістэмай"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Дазволы, якія выкарыстоўваюцца толькі сістэмнымі праграмамі."</string>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"Бяспека і прыватнасць"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Сканіраваць"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"Дазволы на доступ да датчыка"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Налады прыватнасці"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"Дазвол выдалены"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Паказаць больш звестак пра выкарыстанне камеры"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Паказаць больш звестак пра выкарыстанне мікрафона"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Выдаліць дазвол на доступ да камеры"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Выдаліць дазвол на доступ да мікрафона"</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="manage_service_qs" msgid="7862555549364153805">"Кіраваць сэрвісамі"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Кіраваць дазволамі"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Выкарыстоўваецца падчас тэлефонных выклікаў"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Бяспека і прыватнасць"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Праверыць стан"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Сувязь з распрацоўшчыкам"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Абнаўленні за апошні дзень}=1{Абнаўленні за апошні дзень}one{Абнаўленні за # дзень}few{Абнаўленні за # дні}many{Абнаўленні за # дзён}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>
</resources>
diff --git a/PermissionController/res/values-bg-v33/strings.xml b/PermissionController/res/values-bg-v33/strings.xml
index 92348ebc6..6080b29b8 100644
--- a/PermissionController/res/values-bg-v33/strings.xml
+++ b/PermissionController/res/values-bg-v33/strings.xml
@@ -19,4 +19,28 @@
<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="work_policy_title" msgid="832967780713677409">"Информация за служебните правила"</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>
+ <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{Разгънете и вижте още един сигнал}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Затваряне"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Разгъване и показване на опциите"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Свиване"</string>
+ <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_gear_label" msgid="5175877094379694098">"Настройки"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Информация"</string>
</resources>
diff --git a/PermissionController/res/values-bg-v34/strings.xml b/PermissionController/res/values-bg-v34/strings.xml
new file mode 100644
index 000000000..33b3a52f0
--- /dev/null
+++ b/PermissionController/res/values-bg-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-bg/strings.xml b/PermissionController/res/values-bg/strings.xml
index 6c95a2f8a..a8c0e6315 100644
--- a/PermissionController/res/values-bg/strings.xml
+++ b/PermissionController/res/values-bg/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"Винаги да се разрешава пълен достъп"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Открито е екранно наслагване"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"За да промените настройката за това разрешение, трябва първо да изключите екранното наслагване от „Настройки“ &gt; „Приложения“"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Отваряне на настройките"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 ден}other{# дни}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 час}other{# часа}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 мин}other{# мин}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 сек}other{# сек}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# ден}other{# дни}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# час}other{# часа}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# мин}other{# мин}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# сек}other{# сек}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Всички разрешения"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"По всяко време"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Последните 7 дни"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Последните 24 часа"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Последния 1 час"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Последните 15 минути"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Последната минута"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Последният # ден}other{Последните # дни}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Последният # час}other{Последните # часа}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Последната # минута}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>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Използвани разрешения през последния час"</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">"Използвани разрешения през последната минута"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Не е използвано през последните 24 часа"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Не е използвано през последните 7 дни"</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_view_details" msgid="6675335735468752787">"Преглед на всичко в таблото за управление"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Филтрирано по: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"Винаги да се разрешава пълен достъп"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Извеждане на запитване всеки път"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Забраняване"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Точно местоположение"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Разрешенията за <xliff:g id="PERM_0">%1$s</xliff:g> и <xliff:g id="PERM_1">%2$s</xliff:g> ще бъдат премахнати."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Разрешения, които ще бъдат премахнати: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Автоматично управление на разрешенията"</string>
- <string name="off" msgid="1438489226422866263">"Изкл."</string>
<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_tv_summary" msgid="3685907153054355671">"Ако дадено приложение не бъде използвано няколко месеца:\n\n• разрешенията ще бъдат премахнати с цел защита на данните ви;\n• временните файлове ще бъдат премахнати, за да се освободи място.\n\nЗа да предоставите отново разрешенията, отворете приложението."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Последно отваряне преди повече от <xliff:g id="NUMBER">%s</xliff:g> месеца"</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>
@@ -251,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 час}other{# часа}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 минута}other{# минути}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 секунда}other{# секунди}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# час}other{# часа}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<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_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_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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Система Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Премахнати са разр. за прил. с цел защита на поверителността"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Приложението <xliff:g id="APP_NAME">%s</xliff:g> не е използвано от няколко месеца. Докоснете за преглед."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> и още 1 приложение не са използвани от няколко месеца. Докоснете за преглед."</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"бележки"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"Контролирани разрешения"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Разрешен достъп до местопол."</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Системният ви администратор разрешава на <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"Сигурност и поверителност"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Сканиране"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"Разрешения за сензорите"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Контроли за поверителност"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"Разрешението е премахнато"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Вижте още употреби на камерата"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Вижте още употреби на микрофона"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Премахване на разрешението за камерата"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Премахване на разрешението за микрофона"</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="manage_service_qs" msgid="7862555549364153805">"Управление на услугата"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Управление на разрешенията"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Използва се от телефонно обаждане"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Сигурност и поверителност"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Проверка на състоянието"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"получаване на съобщения от програмиста;"</string>
+ <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="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="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="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>
</resources>
diff --git a/PermissionController/res/values-bn-v33/strings.xml b/PermissionController/res/values-bn-v33/strings.xml
index 5e5f882bb..6bef7e90d 100644
--- a/PermissionController/res/values-bn-v33/strings.xml
+++ b/PermissionController/res/values-bn-v33/strings.xml
@@ -19,4 +19,28 @@
<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_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>
+ <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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"বন্ধ করুন"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"বড় করুন ও বিকল্প দেখান"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"আড়াল করুন"</string>
+ <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_gear_label" msgid="5175877094379694098">"সেটিংস"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"তথ্য"</string>
</resources>
diff --git a/PermissionController/res/values-bn-v34/strings.xml b/PermissionController/res/values-bn-v34/strings.xml
new file mode 100644
index 000000000..c93980dd1
--- /dev/null
+++ b/PermissionController/res/values-bn-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-bn/strings.xml b/PermissionController/res/values-bn/strings.xml
index a7096f130..ca112b542 100644
--- a/PermissionController/res/values-bn/strings.xml
+++ b/PermissionController/res/values-bn/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,11 +32,16 @@
<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_always_allow_all" msgid="1719900027660252167">"সবসময় সব অনুমতি দিন"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"স্ক্রিন ওভারলে শনাক্ত করা হয়েছে"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"অনুমতির এই সেটিংটি পরিবর্তন করতে আপনাকে প্রথমে সেটিংস &gt; অ্যাপ বিকল্পে গিয়ে স্ক্রিন ওভারলে বন্ধ করতে হবে"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"সেটিংসে যান"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"গত ৭ দিনে অ্যাপ কখন আপনার <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{১ দিন}one{# দিন}other{# দিন}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{১ ঘণ্টা}one{# ঘণ্টা}other{# ঘণ্টা}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{১ মিনিট}one{# মিনিট}other{# মিনিট}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{১ সেকেন্ড}one{# সেকেন্ড}other{# সেকেন্ড}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# দিন}one{# দিন}other{# দিন}}"</string>
+ <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_time" msgid="3802087027301631827">"যেকোনও সময়"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"গত ৭ দিন"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"গত ২৪ ঘন্টায়"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"শেষ ১ ঘণ্টা"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"গত ১৫ মিনিট"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"গত ১ মিনিটে"</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>
+ <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">"গত ৭ দিনের মধ্যে সাম্প্রতিক অ্যাক্সেস"</string>
@@ -158,8 +161,8 @@
<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_preference_summary_not_used_24h" msgid="3087783232178611025">"গত ২৪ ঘন্টায় ব্যবহার করা হয়নি"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"গত ৭ দিনে ব্যবহার করা হয়নি"</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>
<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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"সবসময় সব অনুমোদন করুন"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"প্রতিবার জিজ্ঞাসা করা হবে"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"অনুমতি দেবেন না"</string>
<string name="precise_image_description" msgid="6349638632303619872">"সুনির্দিষ্ট লোকেশন"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> ও <xliff:g id="PERM_1">%2$s</xliff:g> অনুমতি সরিয়ে দেওয়া হবে।"</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"এই অনুমতি সরিয়ে দেওয়া হবে: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_manage_title" msgid="7693181026874842935">"অনুমোদন অটোমেটিক ম্যানেজ করুন"</string>
- <string name="off" msgid="1438489226422866263">"বন্ধ করুন"</string>
<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_tv_summary" msgid="3685907153054355671">"কোনও অ্যাপ বেশ কয়েকমাস ধরে ব্যবহার করা না হলে:\n\n• আপনার ডেটা সুরক্ষিত রাখতে অনুমতি সরিয়ে নেওয়া হয়\n• স্পেস খালি করতে অস্থায়ী ফাইল সরিয়ে নেওয়া হয়\n\nআবার অনুমতি দিতে, অ্যাপ খুলুন।"</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"<xliff:g id="NUMBER">%s</xliff:g> মাসেরও বেশি সময় আগে শেষ খোলা হয়েছিল"</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>
<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>
@@ -251,9 +254,9 @@
<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="3447767892295843282">"{count,plural, =1{১ ঘণ্টা}one{# ঘণ্টা}other{# ঘণ্টা}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{১ মিনিট}one{# মিনিট}other{# মিনিট}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{১ সেকেন্ড}one{# সেকেন্ড}other{# সেকেন্ড}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# ঘণ্টা}one{# ঘণ্টা}other{# ঘণ্টা}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# মিনিট}one{# মিনিট}other{# মিনিট}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# সেকেন্ড}one{# সেকেন্ড}other{# সেকেন্ড}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"অনুমতির রিমাইন্ডার"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"ব্যবহার হয়নি এমন ১টি অ্যাপ"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"ব্যবহার হয়নি এমন <xliff:g id="NUMBER_OF_APPS">%s</xliff:g>টি অ্যাপ"</string>
@@ -262,6 +265,9 @@
<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>
+ <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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android সিস্টেম"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"গোপনীয়তা রক্ষা করতে অ্যাপকে দেওয়া অনুমতি প্রত্যাহার করা হয়েছে"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> গত কয়েক মাসে ব্যবহার করা হয়নি। পর্যালোচনা করতে ট্যাপ করুন।"</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> ও অন্য ১টি অ্যাপ গত কয়েক মাসে ব্যবহার করা হয়নি। পর্যালোচনা করতে ট্যাপ করুন।"</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"নোট"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"নিয়ন্ত্রিত অনুমতি"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"লোকেশন অ্যাক্সেস করা হতে পারে"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"আপনার আইটি অ্যাডমিন <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"নিরাপত্তা এবং গোপনীয়তা"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"স্ক্যান করুন"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"সেন্সর সংক্রান্ত অনুমতি"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"গোপনীয়তার নিয়ন্ত্রণ"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"অনুমতি সরিয়ে দেওয়া হয়েছে"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"আরও বেশি ক্যামেরার ব্যবহার দেখুন"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"আরও বেশি মাইক্রোফোনের ব্যবহার দেখুন"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"ক্যামেরার অনুমতি সরান"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"মাইক্রোফোনের অনুমতি সরান"</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="manage_service_qs" msgid="7862555549364153805">"পরিষেবা ম্যানেজ করুন"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"অনুমতি ম্যানেজ করুন"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"ফোন কলে ব্যবহার করা হচ্ছে"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"নিরাপত্তা এবং গোপনীয়তা"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"স্ট্যাটাস চেক করুন"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"ডেভেলপারের কথোপকথন"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{গতকালের মধ্যে আপডেট করা হয়েছে}=1{গতকালের মধ্যে আপডেট করা হয়েছে}one{# দিনের মধ্যে আপডেট করা হয়েছে}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>
</resources>
diff --git a/PermissionController/res/values-bs-v33/strings.xml b/PermissionController/res/values-bs-v33/strings.xml
index ae884afb8..598dc6a6c 100644
--- a/PermissionController/res/values-bs-v33/strings.xml
+++ b/PermissionController/res/values-bs-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Ovoj aplikaciji će biti dozvoljeno da vam šalje obavještenja i dobit će pristup vašoj Kameri, Kontaktima, Mikrofonu, Telefonu i SMS-u"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Ovoj aplikaciji će biti dozvoljeno da vam šalje obavještenja i dobit će pristup vašoj Kameri, Kontaktima, Fajlovima, Mikrofonu, Telefonu i SMS-u"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Aplikacije s ovim odobrenjem mogu pristupati svim fajlovima na ovom uređaju"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Informacije o radnim pravilima"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Postavkama upravlja vaš IT administrator"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Proširi i prikaži listu"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Suzi listu i sakrij postavke"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Lista. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Lista. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Potrebne su radnje. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Stavka liste. <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">"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 vidite još jedno upozorenje}one{Proširite i vidite još # upozorenje}few{Proširite i vidite još # upozorenja}other{Proširite i vidite još # upozorenja}}"</string>
+ <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 završena"</string>
+ <string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Provjerite postavke koje mogu dodatno zaštiti vaš 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">"Proširi i prikaži opcije"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Suzi"</string>
+ <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">"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-v34/strings.xml b/PermissionController/res/values-bs-v34/strings.xml
new file mode 100644
index 000000000..e2b8445df
--- /dev/null
+++ b/PermissionController/res/values-bs-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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 aplikacije zdravstvenim podacima"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Pristup lokaciji"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Za aplikacije i usluge. Ako je ova postavka isključena, podaci mikrofona se i dalje mogu dijeliti kada pozovete broj za hitne slučajeve"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Za aplikacije i usluge"</string>
+</resources>
diff --git a/PermissionController/res/values-bs/strings.xml b/PermissionController/res/values-bs/strings.xml
index 5c7a4ef58..069c6e418 100644
--- a/PermissionController/res/values-bs/strings.xml
+++ b/PermissionController/res/values-bs/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Nazad"</string>
<string name="available" msgid="6007778121920339498">"Dostupno"</string>
<string name="blocked" msgid="9195547604866033708">"Blokirano"</string>
+ <string name="on" msgid="280241003226755921">"Uključeno"</string>
+ <string name="off" msgid="1438489226422866263">"Isključi"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Deinstaliraj ili onemogući"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Aplikacija nije pronađena"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Nemoj dozvoliti"</string>
@@ -30,11 +32,16 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Zadrži “Kada se aplikacija koristi”"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Zadrži “Samo ovaj put”"</string>
<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_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>
@@ -107,9 +114,6 @@
<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="screen_overlay_title" msgid="6977038513913222078">"Otkriveno je preklapanje ekrana"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Da promijenite postavku ovog odobrenja, prvo morate isključiti element koji prekriva sadržaj ekrana u odjeljku Postavke i Aplikacije"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Otvori postavke"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Vremenski slijed korištenja odobrenja grupe <xliff:g id="PERMGROUP">%1$s</xliff:g> u posljednjih 7 dana"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Kada je ova aplikacija koristila vaše odobrenje za: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Saznajte više"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"<xliff:g id="PERMGROUP">%1$s</xliff:g> – saznajte više"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Kontrolirajte pristup aplikacije za: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 dan}one{# dan}few{# dana}other{# dana}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 h}one{# h}few{# h}other{# h}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}one{# min}few{# min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 s}one{# s}few{# s}other{# s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# dan}one{# dan}few{# dana}other{# dana}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# h}one{# h}few{# h}other{# h}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}one{# min}few{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}one{# s}few{# s}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Sva odobrenja"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Bilo kad"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Posljednjih 7 dana"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Posljednja 24 sata"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Posljednji sat"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Posljednjih 15 minuta"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Posljednja minuta"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Posljednji dan}one{Posljednji # dan}few{Posljednja # dana}other{Posljednjih # dana}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Posljednji sat}one{Posljednjih # h}few{Posljednja # h}other{Posljednjih # h}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Posljednja minuta}one{Posljednja # min}few{Posljednje # min}other{Posljednjih # min}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Odobrenje nije upotrijebljeno"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Najnoviji pristup u bilo koje vrijeme"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Najnoviji pristup u posljednjih 7 dana"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Korištena odobrenja u posljenji 1 sat"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Korištena odobrenja u posljednjih 15 minuta"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Korištena odobrenja u protekloj minuti"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Nije korišteno u posljednja 24 h"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Nije korišteno u posljednjih 7 dana"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Nije korišteno u proteklom danu}one{Nije korišteno u proteklom # danu}few{Nije korišteno u protekla # dana}other{Nije korišteno u proteklih # dana}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Nije korišteno u proteklom satu}one{Nije korišteno u protekli # h}few{Nije korišteno u protekla # h}other{Nije korišteno u proteklih # h}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Koristi 1 aplikacija}one{Koristi # aplikacija}few{Koriste # aplikacije}other{Koristi # aplikacija}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Prikaži sve na kontrolnoj tabli"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrirano prema: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Dozvoli pristup samo medijima"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Dozvoli sve vrijeme"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Dozvoli samo dok se aplikacija koristi"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Uvijek dozvoli sve"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Pitaj svaki put"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Nemoj dozvoliti"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Tačna lokacija"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Odobrenja <xliff:g id="PERM_0">%1$s</xliff:g> i <xliff:g id="PERM_1">%2$s</xliff:g> će se ukloniti."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Odobrenja koja će biti uklonjena: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Automatsko upravljanje odobrenjima"</string>
- <string name="off" msgid="1438489226422866263">"Isključi"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Uklonjeno je odobrenje za <xliff:g id="PERMISSION_NAME">%s</xliff:g>"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Uklonjena su odobrenja <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> i <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g>"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Uklonjeno je odobrenje <xliff:g id="PERMISSION_NAME">%1$s</xliff:g> i njih još <xliff:g id="NUMBER">%2$s</xliff:g>"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Nekorištene aplikacije"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Ako se aplikacija ne koristi nekoliko mjeseci:\n\n• odobrenja će se ukloniti radi zaštite vaših podataka\n• obavještenja će se zaustaviti radi uštede baterije\n• privremeni fajlovi će se ukloniti radi oslobađanja prostora\n\nDa ponovo dozvolite odobrenja i obavještenja, otvorite aplikaciju."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Ako se aplikacija ne koristi nekoliko mjeseci:\n\n• odobrenja će se ukloniti radi zaštite vaših podataka\n• privremeni fajlovi će se ukloniti radi oslobađanja prostora\n\nOtvorite aplikaciju da ponovo dozvolite odobrenja."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Posljednji put otvoreno prije više od <xliff:g id="NUMBER">%s</xliff:g> mj."</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Ako se aplikacija ne koristi jedan mjesec:\n\n• odobrenja se uklanjaju radi zaštite vaših podataka\n• privremeni fajlovi se uklanjaju radi oslobađanja prostora\n\nDa ponovo dozvolite odobrenja, otvorite aplikaciju."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Zadnji put otvoreno prije više od # mjesec}one{Zadnji put otvoreno prije više od # mjesec}few{Zadnji put otvoreno prije više od # mjeseca}other{Zadnji put otvoreno prije više od # mjeseci}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Aplikacija je posljednji put otvorena na dan <xliff:g id="DATE">%s</xliff:g>"</string>
<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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Nije dozvoljeno"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Pogledajte više aplikacija koje imaju pristup svim fajlovima"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 dan}one{# dan}few{# dana}other{# dana}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 h}one{# h}few{# h}other{# h}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 min}one{# min}few{# min}other{# min}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 s}one{# s}few{# s}other{# s}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# h}one{# h}few{# h}other{# h}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# min}one{# min}few{# min}other{# min}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# s}one{# s}few{# s}other{# s}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Podsjetnici odobrenja"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 nekorištena aplikacija"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"Broj nekorištenih aplikacija: <xliff:g id="NUMBER_OF_APPS">%s</xliff:g>"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Neke aplikacije nisu korištene nekoliko mjeseci. Dodirnite za pregled."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# nekorištena aplikacija}one{# nekorištena aplikacija}few{# nekorištene aplikacije}other{# nekorištenih aplikacija}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Odobrenja i privremeni fajlovi su uklonjeni, a obavještenja zaustavljena. Dodirnite da pregledate."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Pregledajte aplikacije čija odobrenja su uklonjena"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Za aplikacije koje duže vrijeme niste koristili odobrenja i privremeni fajlovi su uklonjeni, a obavještenja su zaustavljena."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Pregledajte aplikacije"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Provjerite nedavna odobrenja"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Prilikom vožnje dali ste aplikaciji <xliff:g id="APP">%1$s</xliff:g> pristup odobrenju <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Prilikom vožnje dali ste aplikaciji <xliff:g id="APP">%1$s</xliff:g> pristup odobrenjima <xliff:g id="PERMISSION_1">%2$s</xliff:g> i <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Odobrenja su uklonjena radi zaštite vaše privatnosti"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"Aplikacija <xliff:g id="APP_NAME">%s</xliff:g> pristupa vašoj lokaciji u pozadini"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Ova aplikacija uvijek može pristupiti vašoj lokaciji. Dodirnite da promijenite."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Pregledajte aplikaciju s pristupom vašim obavještenjima"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"Aplikacija <xliff:g id="APP_NAME">%s</xliff:g> može odbaciti sadržaj, reagirati na njega pristupiti mu unutar vaših obavještenja"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Ova aplikacija može odbaciti sadržaj, reagirati na njega i pristupiti mu unutar vaših obavještenja. Nekim aplikacijama treba taj pristup da ispravno funkcioniraju."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Ukloni pristup"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Prikaži više opcija"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Pristup je uklonjen"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Pregledajte aplikaciju s potpunim pristupom uređaju"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"Aplikacija <xliff:g id="APP_NAME">%s</xliff:g> može pregledati vaš ekran i izvršavati radnje na vašem uređaju. Aplikacijama za pristupačnost treba takav pristup da ispravno funkcioniraju."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Ova aplikacija može pregledati vaš ekran i izvršavati radnje na vašem uređaju. Aplikacijama za pristupačnost treba takav pristup da ispravno funkcioniraju, ali provjerite aplikaciju i vodite računa da je pouzdana."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Ukloni pristup"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Prikaži aplikacije s potpunim pristupom"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Pristup je uklonjen"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Sistem Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Uklonjena su odobrenja za aplikaciju zbog zaštite privatn."</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Aplikacija <xliff:g id="APP_NAME">%s</xliff:g> nije korištena nekoliko mjeseci. Dodirnite za pregled."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"Aplikacija <xliff:g id="APP_NAME">%s</xliff:g> i još jedna aplikacija nisu korištene nekoliko mjeseci. Dodirnite za pregled."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> će se dozvoliti da ostvari interakciju s vašim obavještenjima i pristupi odobrenjima za telefon, SMS, kontakte i kalendar."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> će se dozvoliti da ostvari interakciju s vašim obavještenjima i prenosi aplikacije na povezani uređaj."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Ova usluga dijeli vaše fotografije, medijske sadržaje i obavještenja s vašeg telefona na druge uređaje."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Zadana aplikacija za bilješke"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Kontrolirana odobrenja"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Lokaciji se može pristupiti"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Vaš IT administrator dozvoljava aplikaciji <xliff:g id="APP_NAME">%s</xliff:g> da pristupa vašoj lokaciji"</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>
<string name="other_permissions_label" msgid="8986184335503271992">"Ostala odobrenja"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Odobrenje koje koristi sistem"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Odobrenja koja koriste samo sistemske aplikacije."</string>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Za aplikacije i usluge"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Podaci mikrofona se i dalje mogu dijeliti kada pozovete broj za hitne slučajeve."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Promijeni"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Sigurnost i privatnost"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Skeniraj"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Sigurnost i privatnost"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Skeniraj uređaj"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Odbaci"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Odbaciti ovo upozorenje?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Pregledajte postavke sigurnosti i privatnosti u bilo kojem trenutku da dodate više zaštite"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Odbaci"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Otkaži"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Postavke"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Status sigurnosti i privatnosti. <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">"Postavke sigurnosti"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Odobrenja za senzore"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Kontrole privatnosti"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Odobrenja"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Sigurnost i privatnost"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Provjerite status"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Vaše kontrole privatnosti"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Više postavki"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Pristup kameri"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Pristup mikrofonu"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Uklonjeno je odobrenje"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Prikaži više informacija o korištenju kamere"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Prikaži više informacija o korištenju mikrofona"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Uklonite odobrenje za kameru"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Uklonite odobrenje za mikrofon"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Prikaži nedavno korištenje kamere"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Prikaži nedavno korištenje mikrofona"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Uklonite odobrenje za ovu aplikaciju"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Uklonite odobrenje za ovu aplikaciju"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Upravljajte uslugom"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Upravljajte odobrenjima"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Koristi telefonski poziv"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Nedavno je 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>
<string name="recent_app_usage_2_qs" msgid="3591205954235694403">"Nedavno je koristila 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>
- <string name="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Sigurnost i privatnost"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Provjerite status"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Potvrdi"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Nazad"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Bit će dozvoljen pristup i drugim fajlovima"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Ova aplikacija ne podržava najnoviju verziju Androida. Ako ova aplikacija ne može pristupiti muzičkim i audio fajlovima, neće joj biti dozvoljen pristup ni fotografijama i videozapisima."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Ova aplikacija ne podržava najnoviju verziju Androida. Ako ova aplikacija može pristupiti fotografijama i videozapisima, bit će joj također dozvoljen pristup muzičkim i audio fajlovima."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Ova aplikacija ne podržava najnoviju verziju Androida. Ako ova aplikacija ne može pristupiti muzičkim i audio fajlovima, neće joj biti dozvoljen pristup ni fotografijama i videozapisima."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Pregledajte aplikaciju s pristupom lokaciji u pozadini"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"Aplikacija <xliff:g id="APP_NAME">%s</xliff:g> može uvijek pristupiti vašoj lokaciji, čak i kada je zatvorena"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Pregledajte aplikaciju s pristupom lokaciji u pozadini"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Ova aplikacija uvijek može pristupiti vašoj lokaciji, čak i kada je zatvorena.\n\nNeke aplikacije za sigurnost i hitne slučajeve zahtijevaju pristup vašoj lokaciji u pozadini da mogu funkcionirati kako je predviđeno."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Pristup je promijenjen"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Prikaži nedavno korištenje lokacije"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Kontrole privatnosti"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Pristup kameri"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Pristup mikrofonu"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Za aplikacije i usluge"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Za aplikacije i usluge. Ako je ova postavka isključena, podaci mikrofona se i dalje mogu dijeliti kada pozovete broj za hitne slučajeve."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Vidite aplikacije i usluge koje imaju pristup lokaciji"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Prikaži pristup međumemoriji"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Vidite poruku kada aplikacije pristupe tekstu, slikama ili drugom sadržaju koji ste kopirali"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Prikaži lozinke"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Kratko prikazivanje znakova dok pišete"</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 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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Prakse u vezi s podacima se mogu razlikovati ovisno o verziji aplikacije, korištenju, regiji i dobi. "<annotation id="link">"Više o dijeljenju podataka"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Prakse u vezi s podacima se mogu razlikovati ovisno o verziji aplikacije, korištenju, regiji i dobi."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Vaši podaci o lokaciji"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Promijenite pristup aplikacije u "<annotation id="link">"postavkama privatnosti"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"funkcionalnost aplikacije"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"analitiku"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"komunikaciju s programerima"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"oglašavanje ili marketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"sprečavanje prevara, sigurnost i usklađenost"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"personalizaciju"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"upravljanje računom"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Programeri ovih aplikacija su naveli informacije o svojim praksama dijeljenja podataka u trgovini aplikacija. Mogu ih povremeno ažurirati.\n\nPrakse dijeljenja podataka se mogu razlikovati ovisno o verziji aplikacije, korištenju, regiji i dobi."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Saznajte više o dijeljenju podataka"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Vaši podaci o lokaciji se sada dijele s trećim stranama"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Vaši podaci o lokaciji se sada dijele s trećim stranama u svrhu oglašavanja ili marketinga"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Ažurirano tokom proteklog dana}=1{Ažurirano tokom proteklog dana}one{Ažurirano tokom # dana}few{Ažurirano tokom # dana}other{Ažurirano tokom # dana}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Trenutno nema promjena"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-ca-v33/strings.xml b/PermissionController/res/values-ca-v33/strings.xml
index 3f90628df..0526fffbc 100644
--- a/PermissionController/res/values-ca-v33/strings.xml
+++ b/PermissionController/res/values-ca-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Aquesta aplicació tindrà permís per enviar-te notificacions, i tindrà accés a la càmera, als contactes, al micròfon, al telèfon i als SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Aquesta aplicació tindrà permís per enviar-te notificacions, i tindrà accés a la càmera, als contactes, als fitxers, al micròfon, al telèfon i als SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Les aplicacions amb aquest permís poden accedir a tots els fitxers d\'aquest dispositiu"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Informació de la teva política de treball"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Configuració gestionada per l\'administrador de TI"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Desplega i mostra la llista"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Replega la llista i amaga la configuració"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Llista. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Llista. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Accions necessàries. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>."</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Element de llista. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Tanca"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Desplega i mostra opcions"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Replega"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Interruptor. <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">"Commutador"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Obre"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Revisa la configuració"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Configuració"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Informació"</string>
</resources>
diff --git a/PermissionController/res/values-ca-v34/strings.xml b/PermissionController/res/values-ca-v34/strings.xml
new file mode 100644
index 000000000..8aad7b657
--- /dev/null
+++ b/PermissionController/res/values-ca-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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 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. É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 b18a9e8c1..0187eabc6 100644
--- a/PermissionController/res/values-ca/strings.xml
+++ b/PermissionController/res/values-ca/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Enrere"</string>
<string name="available" msgid="6007778121920339498">"Disponible"</string>
<string name="blocked" msgid="9195547604866033708">"Bloquejat"</string>
+ <string name="on" msgid="280241003226755921">"Activat"</string>
+ <string name="off" msgid="1438489226422866263">"Desactiva"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Desinstal·la o Desactiva"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"No s\'ha trobat l\'aplicació"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"No permetis"</string>
@@ -30,11 +32,16 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Només mentre s\'utilitza l\'aplicació"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Mantén el permís Només aquesta vegada"</string>
<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_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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"S\'ha detectat una superposició de pantalla"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Per canviar la configuració de permisos, cal que desactivis la superposició de pantalla des de Configuració &gt; Aplicacions"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Obre la configuració"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Cronologia de l\'ús que han fet les aplicacions del permís <xliff:g id="PERMGROUP">%1$s</xliff:g> durant els 7 darrers dies"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Quan aquesta aplicació ha utilitzat el permís <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Més informació"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Més informació sobre <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Controla l\'accés de les aplicacions a: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 dia}many{# dies}other{# dies}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 hora}many{# hores}other{# hores}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}many{# min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 s}many{# s}other{# s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# dia}many{# dies}other{# dies}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# hora}many{# hores}other{# hores}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}many{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}many{# s}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Qualsevol permís"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"En qualsevol moment"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"7 darrers dies"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Darreres 24 hores"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Última hora"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Últims 15 minuts"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Últim minut"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Darrer dia}many{# darrers dies}other{# darrers dies}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Darrera hora}many{Darreres # hores}other{Darreres # hores}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Darrer minut}many{Darrers # minuts}other{Darrers # minuts}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Cap ús de permisos"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Accés més recents en qualsevol moment"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Accés més recents durant els 7 darrers dies"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Ús de permisos durant l\'última hora"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Ús de permisos durant els últims 15 minuts"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Ús de permisos durant l\'últim minut"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"No s\'ha utilitzat en les 24 darreres hores"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"No s\'ha utilitzat en els 7 darrers dies"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{No s\'ha utilitzat en el darrer dia}many{No s\'ha utilitzat en els darrers # dies}other{No s\'ha utilitzat en els darrers # dies}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{No s\'ha utilitzat en la darrera hora}many{No s\'ha utilitzat en les darreres # hores}other{No s\'ha utilitzat en les darreres # hores}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Utilitzat per 1 aplicació}many{Utilitzat per # aplicacions}other{Utilitzat per # aplicacions}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Mostra-ho tot al tauler"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrats per: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,9 +188,10 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Permet l\'accés només als fitxers multimèdia"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Permet sempre"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Permet només mentre s\'utilitza l\'aplicació"</string>
+ <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ó 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>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Se suprimiran els permisos <xliff:g id="PERM_0">%1$s</xliff:g> i <xliff:g id="PERM_1">%2$s</xliff:g>."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Permisos que se suprimiran: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Gestiona els permisos automàticament"</string>
- <string name="off" msgid="1438489226422866263">"Desactiva"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"S\'ha suprimit el permís <xliff:g id="PERMISSION_NAME">%s</xliff:g>"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Els permisos <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> i <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> s\'han suprimit"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"El permís <xliff:g id="PERMISSION_NAME">%1$s</xliff:g> i <xliff:g id="NUMBER">%2$s</xliff:g> permisos més s\'han suprimit"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Aplicacions no utilitzades"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Si una aplicació no s\'utilitza durant uns mesos:\n\n• Se suprimeixen els permisos per protegir les teves dades.\n• S\'aturen les notificacions per estalviar bateria.\n• Se suprimeixen els fitxers temporals per alliberar espai.\n\nPer tornar a permetre els permisos i les notificacions, obre l\'aplicació."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Si una aplicació no s\'utilitza durant uns mesos:\n\n• Se suprimeixen els permisos per protegir les teves dades.\n• Se suprimeixen els fitxers temporals per alliberar espai.\n\nPer tornar a concedir els permisos, obre l\'aplicació."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Obertes per darrera vegada fa més de <xliff:g id="NUMBER">%s</xliff:g> mesos"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Si una aplicació no s\'utilitza durant un mes:\n\n• Se suprimeixen els permisos per protegir les teves dades.\n• Se suprimeixen els fitxers temporals per alliberar espai.\n\nPer tornar a concedir els permisos, obre l\'aplicació."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Obertes per darrera vegada fa més d’# mes}many{Obertes per darrera vegada fa més de # mesos}other{Obertes per darrera vegada fa més de # mesos}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Aplicació oberta per darrera vegada el dia <xliff:g id="DATE">%s</xliff:g>"</string>
<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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Sense permís"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Mostra més aplicacions que poden accedir a tots els fitxers"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 dia}many{# dies}other{# dies}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 hora}many{# hores}other{# hores}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minut}many{# minuts}other{# minuts}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 segon}many{# segons}other{# segons}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# hora}many{# hores}other{# hores}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minut}many{# minuts}other{# minuts}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# segon}many{# segons}other{# segons}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Recordatoris de permisos"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 aplicació no utilitzada"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> aplicacions no utilitzades"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Durant els darrers mesos, no has utilitzat algunes aplicacions. Toca per revisar-ho."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# aplicació no utilitzada}many{# aplicacions no utilitzades}other{# aplicacions no utilitzades}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"S\'han suprimit els permisos i els fitxers temporals, i s\'han aturat les notificacions. Toca per revisar-ho."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Revisa les aplicacions amb permisos suprimits"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Els permisos i els fitxers temporals s\'han suprimit i les notificacions s\'han aturat per a les aplicacions que no has utilitzat en un temps."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Revisa les aplicacions"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Consulta els permisos recents"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Mentre conduïes, has concedit a <xliff:g id="APP">%1$s</xliff:g> accés a <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Mentre conduïes, has concedit a <xliff:g id="APP">%1$s</xliff:g> accés a <xliff:g id="PERMISSION_1">%2$s</xliff:g> i <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"S\'han suprimit els permisos per protegir la teva privadesa"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> ha obtingut la teva ubicació en segon pla"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Aquesta aplicació pot accedir a la teva ubicació en qualsevol moment. Toca per canviar-ho."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Revisa l\'aplicació amb accés a les notificacions"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> pot ignorar contingut dins de les teves notificacions, així com també accedir-hi o interaccionar-hi"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Aquesta aplicació pot ignorar contingut dins de les teves notificacions, així com també accedir-hi o interaccionar-hi. Algunes aplicacions requereixen aquest accés per funcionar de la manera prevista."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Suprimeix l\'accés"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Mostra més opcions"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"S\'ha suprimit l\'accés"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Revisa l\'aplicació amb accés complet al dispositiu"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> pot veure la pantalla i dur a terme accions al dispositiu. Les aplicacions d\'accessibilitat necessiten aquest tipus d\'accés perquè funcionin de la manera prevista."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Aquesta aplicació pot veure la pantalla i dur a terme accions al dispositiu. Les aplicacions d\'accessibilitat necessiten aquest tipus d\'accés perquè funcionin de la manera prevista, però comprova l\'aplicació i assegura\'t que sigui de confiança."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Suprimeix l\'accés"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Veure les aplicacions amb accés complet"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"S\'ha suprimit l\'accés"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Sistema Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"S\'han suprimit permisos d\'aplicació per protegir la privadesa"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Durant els darrers mesos, no has utilitzat <xliff:g id="APP_NAME">%s</xliff:g>. Toca per revisar-ho."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"Durant els darrers mesos, no has utilitzat <xliff:g id="APP_NAME">%s</xliff:g> ni 1 aplicació més. Toca per revisar-ho."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i accedir al telèfon, SMS, contactes i calendari."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i reproduir en continu les teves aplicacions al dispositiu connectat."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Aquest servei comparteix les fotos, el contingut multimèdia i les notificacions del telèfon amb altres dispositius."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"App de notes predeterminada"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Permisos controlats"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Es pot accedir a la ubicació"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"El teu administrador de TI permet que <xliff:g id="APP_NAME">%s</xliff:g> accedeixi a la teva ubicació"</string>
+ <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>
@@ -496,17 +520,28 @@
<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 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="7514620345152008005">"Seguretat i privadesa"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Cerca"</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>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Ignora"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Vols ignorar aquesta alerta?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Revisa la configuració de seguretat i privadesa en qualsevol moment per afegir més protecció"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Ignora"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Cancel·la"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Configuració"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Estat de privadesa i seguretat. <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">"Configuració de seguretat"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Permisos del sensor"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Controls de privadesa"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Permisos"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Seguretat i privadesa"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Comprova l\'estat"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Controls de privadesa"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Més opcions"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Accés a la càmera"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Accés al micròfon"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"El permís s\'ha suprimit"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Mostra més informació sobre l\'ús de la càmera"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Mostra més informació sobre l\'ús del micròfon"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Suprimeix el permís de la càmera"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Suprimeix el permís del micròfon"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Mostra l\'ús recent de la càmera"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Mostra l\'ús recent del micròfon"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Suprimeix el permís per a aquesta aplicació"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Suprimeix el permís per a aquesta aplicació"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Gestiona el servei"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Gestiona els permisos"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"En ús per una trucada"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Utilitzat recentment per <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">"En ús per <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">"Utilitzat recentment per <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Seguretat i privadesa"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Comprova l\'estat"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Confirma"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Enrere"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"També es permetrà l\'accés a altres fitxers"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Aquesta aplicació no és compatible amb la darrera versió d\'Android. Si aquesta aplicació no pot accedir a fitxers de música i d\'àudio, tampoc no podrà accedir a fotos i vídeos."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Aquesta aplicació no és compatible amb la darrera versió d\'Android. Si aquesta aplicació pot accedir a fotos i vídeos, també podrà accedir a fitxers de música i d\'àudio."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Aquesta aplicació no és compatible amb la darrera versió d\'Android. Si aquesta aplicació no pot accedir a fitxers de música i d\'àudio, tampoc no podrà accedir a fotos i vídeos."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Revisa l\'aplicació amb accés a la ubicació en segon pla"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> pot accedir sempre a la teva ubicació, encara que l\'aplicació estigui tancada"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Revisa l\'aplicació amb accés a la ubicació en segon pla"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Aquesta aplicació pot accedir sempre a la teva ubicació, encara que estigui tancada.\n\nAlgunes aplicacions de seguretat i d\'emergència necessiten accedir a la teva ubicació en segon pla per poder funcionar segons el previst."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"L\'accés s\'ha canviat"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Mostra l\'ús recent de la ubicació"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Controls de privadesa"</string>
+ <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. É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>
+ <string name="show_password_title" msgid="2877269286984684659">"Mostra les contrasenyes"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Mostra els caràcters breument mentre escrius"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Les pràctiques relacionades amb les dades poden variar segons la versió de l\'aplicació, l\'ús que se\'n fa, la regió i l\'edat. "<annotation id="link">"Més informació sobre la compartició de dades"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Les pràctiques relacionades amb les dades poden variar segons la versió de l\'aplicació, l\'ús que se\'n fa, la regió i l\'edat."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Les teves dades d\'ubicació"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Canvia l\'accés d\'aquesta aplicació a la "<annotation id="link">"configuració de privadesa"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Funcionalitat de l\'aplicació"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analítiques"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Comunicacions del desenvolupador"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Publicitat o màrqueting"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Prevenció de fraus, seguretat i compliment"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalització"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Gestió del compte"</string>
+ <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="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 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>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Les teves dades d\'ubicació ara es comparteixen amb tercers per a finalitats publicitàries o de màrqueting"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{S\'ha actualitzat durant el darrer dia}=1{S\'ha actualitzat durant el darrer dia}many{S\'ha actualitzat durant els # darrers dies}other{S\'ha actualitzat durant els # darrers dies}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"En aquest moment no hi ha cap actualització"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-cs-v33/strings.xml b/PermissionController/res/values-cs-v33/strings.xml
index 4b8afed81..2e30db000 100644
--- a/PermissionController/res/values-cs-v33/strings.xml
+++ b/PermissionController/res/values-cs-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Tato aplikace vám bude moci zasílat oznámení a bude mít přístup k fotoaparátu, kontaktům, mikrofonu, telefonu a SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Tato aplikace vám bude moci zasílat oznámení a bude mít přístup k fotoaparátu, kontaktům, souborům, mikrofonu, telefonu a SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Aplikace s tímto oprávněním mají přístup ke všem souborům v tomto zařízení"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Informace o vašich pracovních zásadách"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Nastavení spravuje administrátor IT"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Rozbalit a zobrazit seznam"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Sbalit seznam a skrýt nastavení"</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>
+ <string name="safety_center_entry_group_with_actions_needed_content_description" msgid="2708884606775932657">"Seznam. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Jsou vyžadovány akce. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Položka seznamu. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Zavřít"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Rozbalit a zobrazit možnosti"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Sbalit"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Přepnout. <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">"Přepnout"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Otevřít"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Zkontrolovat nastavení"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Nastavení"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Informace"</string>
</resources>
diff --git a/PermissionController/res/values-cs-v34/strings.xml b/PermissionController/res/values-cs-v34/strings.xml
new file mode 100644
index 000000000..b7e982b21
--- /dev/null
+++ b/PermissionController/res/values-cs-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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">"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í, 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 5646f710f..38faa7581 100644
--- a/PermissionController/res/values-cs/strings.xml
+++ b/PermissionController/res/values-cs/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Zpět"</string>
<string name="available" msgid="6007778121920339498">"Dostupné"</string>
<string name="blocked" msgid="9195547604866033708">"Blokováno"</string>
+ <string name="on" msgid="280241003226755921">"Zapnuto"</string>
+ <string name="off" msgid="1438489226422866263">"Vypnout"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Odinstalovat nebo deaktivovat"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Aplikace nebyla nalezena"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Nepovolovat"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Ponechat „Během používání aplikace“"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Ponechat možnost Pouze tentokrát"</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Přesto nepovolit"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Zavřít"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Byla zjištěna překryvná vrstva obrazovky"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Chcete-li změnit nastavení tohoto oprávnění, v Nastavení &gt; Aplikace je třeba nejprve vypnout překryvnou vrstvu obrazovky"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Otevřít nastavení"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"<xliff:g id="PERMGROUP">%1$s</xliff:g> – časový přehled využívání aplikacemi za posledních 7 dní"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Kdy tato aplikace použila oprávnění <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Další informace"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Další informace o oprávnění <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Ovládání přístupu aplikací ke skupině oprávnění <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 den}few{# dny}many{# dne}other{# dní}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 hodina}few{# hodiny}many{# hodiny}other{# hodin}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}few{# min}many{# min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 s}few{# s}many{# s}other{# s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# den}few{# dny}many{# dne}other{# dní}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# hodinu}few{# hodiny}many{# hodiny}other{# hodin}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}few{# min}many{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}few{# s}many{# s}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Všechna oprávnění"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Kdykoli"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Posledních 7 dní"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Posledních 24 hodin"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Poslední hodina"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Posledních 15 minut"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Poslední minuta"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Poslední den}few{Poslední # dny}many{Posledních # dne}other{Posledních # dní}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Poslední hodina}few{Poslední # hodiny}many{Posledních # hodiny}other{Posledních # hodin}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Poslední minuta}few{Poslední # minuty}many{Posledních # minuty}other{Posledních # minut}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Žádné využití oprávnění"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Poslední využití kdykoli"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Poslední použití za 7 dnů"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Využití oprávnění za poslední hodinu"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Využití oprávnění za posledních 15 minut"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Využití oprávnění za poslední minutu"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Během uplynulých 24 hodin nepoužito"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Během posledních 7 dní nepoužito"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Během uplynulého dne nepoužito}few{Během uplynulých # dní nepoužito}many{Během uplynulých # dne nepoužito}other{Během uplynulých # dní nepoužito}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Během uplynulé hodiny nepoužito}few{Během uplynulých # hodin nepoužito}many{Během uplynulých # hodiny nepoužito}other{Během uplynulých # hodin nepoužito}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Využíváno 1 aplikací}few{Využíváno # aplikacemi}many{Využíváno # aplikace}other{Využíváno # aplikacemi}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Zobrazit vše na panelu"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrováno podle: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Povolit pouze přístup k médiím"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Povolit vždy"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Povolit jen při používání aplikace"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Vždy povolit vše"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Pokaždé se zeptat"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Nepovolovat"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Přesná poloha"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Budou odebrána oprávnění <xliff:g id="PERM_0">%1$s</xliff:g> a <xliff:g id="PERM_1">%2$s</xliff:g>."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Oprávnění, která budou odebrána: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Automatická správa oprávnění"</string>
- <string name="off" msgid="1438489226422866263">"Vypnout"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Bylo odebráno oprávnění <xliff:g id="PERMISSION_NAME">%s</xliff:g>"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Byla odebrána oprávnění <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> a <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g>"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Bylo odebráno oprávnění <xliff:g id="PERMISSION_NAME">%1$s</xliff:g> a další oprávnění (<xliff:g id="NUMBER">%2$s</xliff:g>)"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Nepoužívané aplikace"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Když aplikaci několik měsíců nepoužíváte:\n\n• Oprávnění jsou odstraněna kvůli ochraně dat\n• Oznámení se přestanou zobrazovat kvůli úspoře baterie\n• Dočasné soubory jsou odstraněny kvůli uvolnění místa\n\nPokud chcete oprávnění a oznámení znovu povolit, otevřete aplikaci."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Když aplikaci několik měsíců nepoužíváte:\n\n• Oprávnění jsou odstraněna kvůli ochraně dat\n• Dočasné soubory jsou odstraněny kvůli uvolnění místa\n\nPokud chcete oprávnění znovu povolit, otevřete aplikaci."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Naposledy otevřeno před více než <xliff:g id="NUMBER">%s</xliff:g> měsíci"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Když nějakou aplikaci měsíc nepoužíváte:\n\n• Kvůli ochraně dat se odstraní oprávnění.\n• Kvůli uvolnění místa se odstraní dočasné soubory.\n\nPokud chcete oprávnění znovu povolit, otevřete aplikaci."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Naposledy otevřeno před více než # měsícem}few{Naposledy otevřeno před více než # měsíci}many{Naposledy otevřeno před více než # měsíce}other{Naposledy otevřeno před více než # měsíci}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Aplikace byla naposledy otevřena <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Naposledy otevřeno <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Pokud povolíte správu všech souborů, tato aplikace může číst, upravovat a mazat všechny soubory ve společném úložišti na tomto zařízení i na připojených úložných zařízeních. Aplikace se může dostat k souborům, aniž by se vás zeptala."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Nepovoleno"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Zobrazit další aplikace s přístupem ke všem souborům"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 den}few{# dny}many{# dne}other{# dní}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 hodina}few{# hodiny}many{# hodiny}other{# hodin}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minuta}few{# minuty}many{# minuty}other{# minut}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 sekunda}few{# sekundy}many{# sekundy}other{# sekund}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# hodinu}few{# hodiny}many{# hodiny}other{# hodin}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minuta}few{# minuty}many{# minuty}other{# minut}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# sekunda}few{# sekundy}many{# sekundy}other{# sekund}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Připomenutí o oprávněních"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"Nepoužívané aplikace: 1"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"Nepoužívané aplikace: <xliff:g id="NUMBER_OF_APPS">%s</xliff:g>"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Některé aplikace jste několik měsíců nepoužili. Klepnutím to zkontrolujete."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# nepoužívaná aplikace}few{# nepoužívané aplikace}many{# nepoužívané aplikace}other{# nepoužívaných aplikací}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Oprávnění a dočasné soubory byly odstraněny a oznámení byla zastavena. Klepnutím to zkontrolujete."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Zkontrolujte aplikace, kterým byla odebrána oprávnění"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Aplikacím, které jste nějakou dobu nepoužívali, byla odebrána oprávnění a byly odstraněny jejich dočasné soubory a pozastavena jejich oznámení."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Zkontrolovat aplikace"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Zkontrolujte si nedávno udělená oprávnění"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Při řízení jste aplikaci <xliff:g id="APP">%1$s</xliff:g> udělili přístup k: <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Při řízení jste aplikaci <xliff:g id="APP">%1$s</xliff:g> udělili přístup k: <xliff:g id="PERMISSION_1">%2$s</xliff:g> a <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Kvůli ochraně vašeho soukromí byla odebrána oprávnění"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> má přístup k poloze na pozadí"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Tato aplikace má neomezený přístup k poloze. Klepnutím to změníte."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Zkontrolujte aplikaci s přístupem k vašim oznámením"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"Aplikace <xliff:g id="APP_NAME">%s</xliff:g> může zavírat obsah v oznámeních, reagovat na něj a přistupovat k němu"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Tato aplikace může zavírat obsah uvnitř vašich oznámení, reagovat na něj a mít k němu přístup. Některé aplikace tento přístup k poskytování svých funkcí potřebují."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Odebrat přístup"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Zobrazit další možnosti"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Přístup byl odebrán"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Zkontrolujte aplikaci s plným přístupem k zařízení"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"Aplikace <xliff:g id="APP_NAME">%s</xliff:g> může zobrazit vaši obrazovku a provádět akce na vašem zařízení. Aplikace pro usnadnění potřebují tento typ přístupu, aby mohly fungovat, jak mají."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Tato aplikace může zobrazit vaši obrazovku a provádět akce na vašem zařízení. Aplikace pro usnadnění tento typ přístupu potřebují. Aplikaci však zkontrolujte a ujistěte se, že jí důvěřujete."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Odebrat přístup"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Zobrazení aplikací s plným přístupem"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Přístup byl odebrán"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Systém Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Oprávnění aplikace byla za účelem ochrany soukromí odebrána"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Aplikace <xliff:g id="APP_NAME">%s</xliff:g> nebyla několik měsíců použita. Klepnutím provedete kontrolu."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> a 1 další aplikace nebyly několik měsíců použity. Klepnutím provedete kontrolu."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> bude moci interagovat s vašimi oznámeními a získá přístup k telefonu, SMS, kontaktům a kalendáři."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> bude moci interagovat s vašimi oznámeními a streamovat vaše aplikace do připojeného zařízení."</string>
<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_search_keywords" msgid="7710756695666744631">"poznámky"</string>
<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>
@@ -408,7 +431,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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Spravovaná oprávnění"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Lze získat přístup k poloze"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Administrátor IT povolil aplikaci <xliff:g id="APP_NAME">%s</xliff:g> získat přístup k vaší poloze"</string>
+ <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>
@@ -496,17 +520,28 @@
<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>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Zabezpečení a ochrana soukromí"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Zkontrolovat"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Zabezpečení a ochrana soukromí"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Zkontrolovat zařízení"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Zavřít"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Zavřít upozornění?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Nastavení zabezpečení a soukromí můžete kdykoliv zkontrolovat a ochranu zvýšit"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Zavřít"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Zrušit"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Nastavení"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Stav ochrany soukromí a zabezpečení. <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">"Nastavení zabezpečení"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Oprávnění k senzoru"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Nastavení ochrany soukromí"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Oprávnění"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Zabezpečení a ochrana soukromí"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Zkontrolovat stav"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Nastavení ochrany soukromí"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Další nastavení"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Přístup k fotoaparátu"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Přístup k mikrofonu"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Bylo odebráno oprávnění"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Zobrazit další využití fotoaparátu"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Zobrazit další využití mikrofonu"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Odebrat oprávnění k fotoaparátu"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Odebrat oprávnění k mikrofonu"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Zobrazit nedávné využití fotoaparátu"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Zobrazit nedávné využití mikrofonu"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Odebrat oprávnění této aplikaci"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Odebrat oprávnění této aplikaci"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Spravovat službu"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Správa oprávnění"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Právě používá telefonní hovor"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Nedávno použila aplikace <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">"Právě používá aplikace <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">"Nedávno použila aplikace <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Zabezpečení a ochrana soukromí"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Zkontrolovat stav"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Potvrdit"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Zpět"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Bude povolen také přístup k dalším souborům"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Tato aplikace nepodporuje nejnovější verzi Androidu. Pokud tato aplikace nemá přístup k hudbě a zvukovým souborům, nebude mít přístup ani k fotografiím a videím."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Tato aplikace nepodporuje nejnovější verzi Androidu. Pokud má tato aplikace přístup k fotografiím a videím, bude mít přístup i k hudbě a zvukovým souborům."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Tato aplikace nepodporuje nejnovější verzi Androidu. Pokud tato aplikace nemá přístup k hudbě a zvukovým souborům, nebude mít přístup ani k fotografiím a videím."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Zkontrolujte aplikaci s přístupem k poloze na pozadí"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"Aplikace <xliff:g id="APP_NAME">%s</xliff:g> má vždy přístup k vaší poloze, i když je zavřená"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Zkontrolujte aplikaci s přístupem k poloze na pozadí"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Tato aplikace má vždy přístup k vaší poloze, i když je zavřená.\n\nNěkteré bezpečnostní a nouzové aplikace vyžadují přístup k vaší poloze na pozadí, aby fungovaly, jak mají."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Přístup změněn"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Zobrazit nedávné využití polohy"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Nastavení ochrany soukromí"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Přístup k fotoaparátu"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Přístup k mikrofonu"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Aplikace a služby"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Týká se aplikací a služeb. Pokud je toto nastavení vypnuté a zavoláte na číslo tísňového volání, data z mikrofonu se mohou stále sdílet."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Podívejte se, které aplikace a služby mají přístup k poloze"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Zobrazovat použití schránky"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Zobrazovat zprávu, když aplikace použijí text, obrázky nebo jiný obsah, který jste zkopírovali"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Zobrazovat hesla"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Při psaní se budou krátce zobrazovat zadané znaky"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Způsob nakládání s daty se může lišit podle verze aplikace, způsobu používání, oblasti a věku. "<annotation id="link">"Další informace o sdílení dat"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Způsob nakládání s daty se může lišit podle verze aplikace, způsobu používání, oblasti a věku."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Údaje o vaší poloze"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Přístup této aplikace můžete změnit v "<annotation id="link">"nastavení ochrany soukromí"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Funkce aplikace"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analýzy"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Komunikace vývojáře"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Reklama nebo marketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Prevence podvodů, zabezpečení a dodržování předpisů"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Přizpůsobení"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Správa účtu"</string>
+ <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="data_sharing_updates_title" msgid="7996933386875213859">"Aktualizace sdílení údajů o 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>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Údaje o vaší poloze jsou nyní sdíleny se třetími stranami"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Údaje o vaší poloze jsou nyní sdíleny se třetími stranami pro inzertní a marketingové účely"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Aktualizováno během posledního dne}=1{Aktualizováno během posledního dne}few{Aktualizováno během posledních # dnů}many{Aktualizováno během posledních # dne}other{Aktualizováno během posledních # dnů}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Aktuálně nejsou hlášeny žádné změny"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-da-v33/strings.xml b/PermissionController/res/values-da-v33/strings.xml
index 330094c64..3e532459f 100644
--- a/PermissionController/res/values-da-v33/strings.xml
+++ b/PermissionController/res/values-da-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Denne app får tilladelse til at sende dig notifikationer og får adgang til Kamera, Kontakter, Mikrofon, Telefon, og Sms"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Denne app får tilladelse til at sende dig notifikationer og får adgang til Kamera, Kontakter, Filer, Mikrofon, Telefon, og Sms"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Apps med denne tilladelse har adgang til alle filer på denne enhed"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Oplysninger om din arbejdspolitik"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Indstillinger, som administreres af din it-administrator"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Udvid og vis listen"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Skjul listen og indstillingerne"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Liste. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Liste. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Handling er påkrævet. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Listepunkt. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Luk"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Udvid og vis mulighederne"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Skjul"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Skift. <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">"Slå til/fra"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Åbn"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Gennemgå indstillinger"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Indstillinger"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Information"</string>
</resources>
diff --git a/PermissionController/res/values-da-v34/strings.xml b/PermissionController/res/values-da-v34/strings.xml
new file mode 100644
index 000000000..5777a6832
--- /dev/null
+++ b/PermissionController/res/values-da-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Sikkerhed og privatliv"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Styringselementer"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Administrer appadgang til sundhedsdata"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Lokationsadgang"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"For apps og tjenester. Hvis denne indstilling er deaktiveret, deles mikrofondata muligvis stadig, når du ringer til et alarmnummer"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"For apps og tjenester"</string>
+</resources>
diff --git a/PermissionController/res/values-da/strings.xml b/PermissionController/res/values-da/strings.xml
index 5293c8a9b..7fe9f9309 100644
--- a/PermissionController/res/values-da/strings.xml
+++ b/PermissionController/res/values-da/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Tilbage"</string>
<string name="available" msgid="6007778121920339498">"Tilgængelig"</string>
<string name="blocked" msgid="9195547604866033708">"Blokeret"</string>
+ <string name="on" msgid="280241003226755921">"Til"</string>
+ <string name="off" msgid="1438489226422866263">"Fra"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Afinstaller, eller deaktiver"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Appen blev ikke fundet"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Tillad ikke"</string>
@@ -30,6 +32,11 @@
<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_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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Tillad ikke alligevel"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Luk"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> ud af <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Der er registreret skærmoverlejring"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Hvis du vil ændre denne indstilling for tilladelser, skal du først deaktivere skærmoverlejringen i Indstillinger &gt; Apps"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Åbn indstillinger"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Tidslinje over, hvornår apps har anvendt <xliff:g id="PERMGROUP">%1$s</xliff:g> inden for de seneste 7 dage"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Da denne app brugte din tilladelse for <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Få flere oplysninger"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Få flere oplysninger om <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Administrer appadgang til din <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 dag}one{# dag}other{# dage}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 time}one{# time}other{# timer}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min.}one{# min.}other{# min.}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 sek.}one{# sek.}other{# sek.}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# dag}one{# dag}other{# dage}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# time}one{# time}other{# timer}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min.}one{# min.}other{# min.}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# sek.}one{# sek.}other{# sek.}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Alle tilladelser"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Nogensinde"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"De seneste 7 dage"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"De seneste 24 timer"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Den seneste time"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"De seneste 15 minutter"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Seneste minut"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Seneste dag}one{Seneste # dag}other{Seneste # dage}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Seneste time}one{Seneste # time}other{Seneste # timer}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Seneste minut}one{Seneste # minut}other{Seneste # minutter}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Ingen brug af tilladelsen"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Seneste adgang nogensinde"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Seneste adgang i de sidste 7 dage"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Anvendte tilladelser den seneste time"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Anvendte tilladelser i de sidste 15 minutter"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Anvendte tilladelser det seneste minut"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Ikke brugt i de seneste 24 timer"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Ikke brugt i de seneste 7 dage"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Ikke brugt i # dag}one{Ikke brugt i # dag}other{Ikke brugt i de seneste # dage}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Ikke brugt i # time}one{Ikke brugt i # time}other{Ikke brugt i de seneste # timer}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Anvendes af 1 app}one{Anvendes af # app}other{Anvendes af # apps}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Se alt i kontrolpanelet"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtreret efter: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Tillad kun adgang til mediefiler"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Tillad altid"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Tillad kun, mens appen er i brug"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Tillad altid alle"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Spørg hver gang"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Tillad ikke"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Præcis lokation"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Adgangen til <xliff:g id="PERM_0">%1$s</xliff:g> og <xliff:g id="PERM_1">%2$s</xliff:g> fjernes."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Tilladelser, der ikke fjernes: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Administrer automatisk tilladelser"</string>
- <string name="off" msgid="1438489226422866263">"Fra"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Tilladelsen <xliff:g id="PERMISSION_NAME">%s</xliff:g> blev fjernet"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Tilladelserne <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> og <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> blev fjernet"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> og <xliff:g id="NUMBER">%2$s</xliff:g> andre tilladelser blev fjernet"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Apps, du ikke bruger"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Hvis en app ikke bruges i et par måneder, sker følgende:\n\n• Tilladelser fjernes for at beskytte dine data\n• Notifikationer stoppes for at spare på batteriet\n• Midlertidige filer fjernes for at frigøre plads\n\nHvis du vil aktivere tilladelser og notifikationer igen, skal du åbne appen."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Hvis en app ikke bruges i et par måneder, sker følgende:\n\n• Tilladelser fjernes for at beskytte dine data\n• Midlertidige filer fjernes for at frigøre plads\n\nHvis du vil aktivere tilladelserne igen, skal du åbne appen."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Sidst åbnet for mere end <xliff:g id="NUMBER">%s</xliff:g> måneder siden"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Hvis en app ikke bruges i en måned, sker følgende:\n\n• Tilladelser fjernes for at beskytte dine data\n• Midlertidige filer fjernes for at frigøre plads\n\nHvis du vil aktivere tilladelserne igen, skal du åbne appen."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Sidst åbnet for mere end # måned siden}one{Sidst åbnet for mere end # måned siden}other{Sidst åbnet for mere end # måneder siden}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Appen blev sidst åbnet <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Sidst åbnet <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Hvis du tillader administration af alle filer, får denne app adgang og tilladelse til at ændre og slette alle filer på enhedens almindelige lagerplads og tilsluttede lagerenheder. Appen kan få adgang til filer uden at spørge dig først."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Ikke tilladt"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Se flere apps, som kan tilgå alle filer"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 dag}one{# dag}other{# dage}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 time}one{# time}other{# timer}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minut}one{# minut}other{# minutter}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 sekund}one{# sekund}other{# sekunder}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# time}one{# time}other{# timer}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minut}one{# minut}other{# minutter}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# sekund}one{# sekund}other{# sekunder}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Påmindelser om tilladelse"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 app, du ikke bruger"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> apps, du ikke bruger"</string>
@@ -262,6 +265,9 @@
<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_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>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Gennemgå apps"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Tjek seneste tilladelser"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Under kørsel gav du <xliff:g id="APP">%1$s</xliff:g> adgang til <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Under kørsel gav du <xliff:g id="APP">%1$s</xliff:g> adgang til <xliff:g id="PERMISSION_1">%2$s</xliff:g> og <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Nogle tilladelser blev fjernet for at beskytte dit privatliv"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> har din lokation i baggrunden"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Denne app kan altid få adgang til din lokation. Tryk for at ændre denne indstilling."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Gennemgå appen, der har adgang til dine notifikationer"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> kan lukke, interagere med og få adgang til indhold i dine notifikationer"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Denne app kan lukke, interagere med og få adgang til indhold i dine notifikationer. Nogle apps forudsætter denne type adgang for at fungere efter hensigten."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Fjern adgang"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Se flere muligheder"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Adgangen er blevet fjernet"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Gennemgå appen, der har fuld adgang til enheden"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> kan se din skærm og udføre handlinger på din enhed. Apps med hjælpefunktioner skal have denne type adgang for at fungere efter hensigten."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Denne app kan se din skærm og udføre handlinger på din enhed. Apps med hjælpefunktioner skal have denne type adgang for at fungere efter hensigten. Tjek dog appen for at sikre, at du kan stole på den."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Fjern adgang"</string>
+ <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 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>
@@ -354,7 +373,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>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tilladelse til at interagere med dine notifikationer og får adgang til dine tilladelser for Opkald, Sms, Kontakter og Kalender."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tilladelse til at interagere med dine notifikationer og streame dine apps til forbundne enheder."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Denne tjeneste deler dine billeder, medier og notifikationer fra din telefon til andre enheder."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Standardapp til notetagning"</string>
+ <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>
<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>
@@ -420,7 +443,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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Administrerede tilladelser"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Der er adgang til din lokation"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Din it-administrator har givet <xliff:g id="APP_NAME">%s</xliff:g> adgang til din lokation"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"For apps og tjenester"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Mikrofondata deles muligvis stadig, når du ringer til et alarmnummer."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Skift"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Sikkerhed og privatliv"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Scan"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Sikkerhed og privatliv"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Scan enhed"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Afvis"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Vil du afvise denne underretning?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Du kan altid gennemgå dine sikkerheds- og privatlivsindstillinger for at tilføje mere beskyttelse"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Afvis"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Annuller"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Indstillinger"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Status for sikkerhed og privatliv. <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">"Sikkerhedsindstillinger"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Sensortilladelser"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Privatlivsindstillinger"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Tilladelser"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Sikkerhed og privatliv"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Tjek status"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Dine privatlivsindstillinger"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Flere indstillinger"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Kameraadgang"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Mikrofonadgang"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Tilladelsen blev fjernet"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Se mere kamerabrug"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Se mere mikrofonbrug"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Fjern kameratilladelse"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Fjern mikrofontilladelse"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Se seneste kamerabrug"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Se seneste mikrofonbrug"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Fjern tilladelsen for denne app"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Fjern tilladelsen for denne app"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Administrer tjeneste"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Administrer tilladelser"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Anvendes i øjeblikket af telefonopkald"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Anvendt for nylig af <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">"Anvendes i øjeblikket af <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">"Anvendt for nylig af <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Sikkerhed og privatliv"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Tjek status"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Bekræft"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Tilbage"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Adgang til andre filer bliver også tilladt"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Denne app understøtter ikke den seneste version af Android. Hvis denne app ikke har adgang til musik og lydfiler, får den heller ikke adgang til billeder og videoer."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Denne app understøtter ikke den seneste version af Android. Hvis denne app har adgang til billeder og videoer, får den også adgang til musik og lydfiler."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Denne app understøtter ikke den seneste version af Android. Hvis denne app ikke har adgang til musik og lydfiler, får den heller ikke adgang til billeder og videoer."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Gennemgå appen, der har adgang til lokation i baggrunden"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> kan til enhver tid tilgå din lokation, selv når appen er lukket"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Gennemgå appen, der har adgang til lokation i baggrunden"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Denne app kan til enhver tid tilgå din lokation, selv når den er lukket.\n\nVisse apps til sikkerhed og nødsituationer kræver adgang til din lokation i baggrunden for at fungere efter hensigten."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Adgangen er ændret"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Se seneste brug af lokation"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Privatlivsindstillinger"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Kameraadgang"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Mikrofonadgang"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"For apps og tjenester"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"For apps og tjenester: Hvis denne indstilling er deaktiveret, deles mikrofondata muligvis stadig, når du ringer til et alarmnummer."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Se de apps og tjenester, der har adgang til lokation"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Vis adgang til udklipsholder"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Vis en meddelelse, når apps får adgang til tekst, billeder eller andet indhold, du har kopieret"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Vis adgangskoder"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Vis kort tegnene, mens du skriver"</string>
+ <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_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>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analysedata"</string>
+ <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">"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="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="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>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Opdateret inden for den seneste dag}=1{Opdateret inden for den seneste dag}one{Opdateret for maks. # dag siden}other{Opdateret inden for de seneste # dage}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Der er på nuværende tidspunkt ikke nogen opdateringer"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-de-v33/strings.xml b/PermissionController/res/values-de-v33/strings.xml
index a854f71c8..d82bd4619 100644
--- a/PermissionController/res/values-de-v33/strings.xml
+++ b/PermissionController/res/values-de-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Diese App erhält die Erlaubnis, dir Benachrichtigungen zu senden, und außerdem Zugriff auf Folgendes: Kamera, Kontakte, Mikrofon, Telefon und SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Diese App erhält die Erlaubnis, dir Benachrichtigungen zu senden, und außerdem Zugriff auf Folgendes: Kamera, Kontakte, Dateien, Mikrofon, Telefon und SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Apps mit dieser Berechtigung dürfen auf alle Dateien auf diesem Gerät zugreifen"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Informationen zu den Arbeitsrichtlinien"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Einstellungen, die von deinem IT-Administrator verwaltet werden"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Maximieren und Liste anzeigen"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Liste minimieren und Einstellungen ausblenden"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Liste. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Liste. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Wichtige Informationen. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Listeneintrag. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Schließen"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Optionen einblenden und maximieren"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Minimieren"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Schalter. <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">"Wechseln"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Öffnen"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Einstellungen prüfen"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Einstellungen"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Informationen"</string>
</resources>
diff --git a/PermissionController/res/values-de-v34/strings.xml b/PermissionController/res/values-de-v34/strings.xml
new file mode 100644
index 000000000..8b6f95055
--- /dev/null
+++ b/PermissionController/res/values-de-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Sicherheit &amp; Datenschutz"</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>
+ <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 ad8477d2e..e4f6c29ed 100644
--- a/PermissionController/res/values-de/strings.xml
+++ b/PermissionController/res/values-de/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Zurück"</string>
<string name="available" msgid="6007778121920339498">"Verfügbar"</string>
<string name="blocked" msgid="9195547604866033708">"Gesperrt"</string>
+ <string name="on" msgid="280241003226755921">"An"</string>
+ <string name="off" msgid="1438489226422866263">"Aus"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Deinstallieren oder deaktivieren"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"App nicht gefunden"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Nicht zulassen"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"„Wenn die App verwendet wird“ beibehalten"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"\"Nur dieses Mal\" aktiviert lassen"</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Trotzdem nicht zulassen"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Schließen"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> von <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -51,7 +58,7 @@
<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="no_unused_apps" msgid="12809387670415295">"Keine nicht verwendeten Apps"</string>
<string name="zero_unused_apps" msgid="9024448554157499748">"Keine nicht verwendeten Apps"</string>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Display-Overlay erkannt"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Wenn du diese Berechtigungseinstellung ändern möchtest, musst du zuerst das Display-Overlay in \"Einstellungen\" &gt; \"Apps\" deaktivieren"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Einstellungen öffnen"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Zeitachse, wann Apps in den letzten 7 Tagen die Berechtigungsgruppe „<xliff:g id="PERMGROUP">%1$s</xliff:g>“ verwendet haben"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Als diese App deine <xliff:g id="PERMGROUP">%1$s</xliff:g>-Berechtigung verwendet hat"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Weitere Informationen"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Weitere Informationen zur Berechtigungsgruppe „<xliff:g id="PERMGROUP">%1$s</xliff:g>“"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"App-Zugriff auf „<xliff:g id="PERMGROUP">%1$s</xliff:g>“ steuern"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 Tag}other{# Tage}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 Stunde}other{# Stunden}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 s}other{# s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# Tag}other{# Tage}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# Stunde}other{# Stunden}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Alle Berechtigungen"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Beliebiger Zeitraum"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Letzte 7 Tage"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Letzte 24 Stunden"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Letzte Stunde"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Letzte 15 Minuten"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Letzte Minute"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Letzter Tag}other{Letzte # Tage}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Letzte Stunde}other{Letzte # Stunden}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Letzte Minute}other{Letzte # Minuten}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Keine Berechtigungen verwendet"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Letzter Zugriff zu einem beliebigen Zeitpunkt"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Letzter Zugriff in den letzten 7 Tagen"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Berechtigungsnutzungen (letzte Stunde)"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Berechtigungsnutzungen (letzte 15 Minuten)"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Berechtigungsnutzungen (letzte Minute)"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"In den letzten 24 Stunden nicht verwendet"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"In den letzten 7 Tagen nicht verwendet"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Innerhalb des letzten Tages nicht verwendet}other{In den letzten # Tagen nicht verwendet}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Innerhalb der letzten Stunde nicht verwendet}other{In den letzten # Stunden nicht verwendet}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Von 1 App verwendet}other{Von # Apps verwendet}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Alle im Dashboard ansehen"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Gefiltert nach: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Zugriff nur auf Mediendateien zulassen"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Immer zulassen"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Zugriff nur während der Nutzung der App zulassen"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Immer vollen Zugriff erlauben"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Jedes Mal fragen"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Nicht zulassen"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Auf genauen Standort zugreifen"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Die Berechtigungen \"<xliff:g id="PERM_0">%1$s</xliff:g>\" und \"<xliff:g id="PERM_1">%2$s</xliff:g>\" werden entfernt."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Berechtigungen, die entfernt werden: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Berechtigungen automatisch verwalten"</string>
- <string name="off" msgid="1438489226422866263">"Aus"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Berechtigung für <xliff:g id="PERMISSION_NAME">%s</xliff:g> entfernt"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Berechtigungen für <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> und <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> entfernt"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Berechtigungen für <xliff:g id="PERMISSION_NAME">%1$s</xliff:g> und <xliff:g id="NUMBER">%2$s</xliff:g> weitere entfernt"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Nicht verwendete Apps"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Wenn du eine App seit einigen Monaten nicht mehr verwendet hast, geschieht Folgendes:\n\n• Zum Schutz deiner Daten werden die Berechtigungen entfernt.\n• Benachrichtigungen werden gestoppt, um den Akku zu schonen.\n• Temporäre Dateien werden gelöscht, um Speicherplatz freizugeben.\n\nÖffne die App, um Berechtigungen und Benachrichtigungen wieder zu aktivieren."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Wenn du eine App seit einigen Monaten nicht mehr verwendet hast, geschieht Folgendes:\n\n• Zum Schutz deiner Daten werden die Berechtigungen entfernt\n• Temporäre Dateien werden gelöscht, um Speicherplatz freizugeben\n\nWenn du Berechtigungen wieder aktivieren möchtest, öffne die App."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Zuletzt geöffnet vor mehr als <xliff:g id="NUMBER">%s</xliff:g> Monaten"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Wenn du eine App seit einem Monat nicht mehr verwendet hast, geschieht Folgendes:\n\n• Zum Schutz deiner Daten werden die Berechtigungen entfernt\n• Temporäre Dateien werden gelöscht, um Speicherplatz freizugeben\n\nWenn du die Berechtigungen wieder erteilen möchtest, öffne die App."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Zuletzt vor mehr als # Monat geöffnet}other{Zuletzt vor mehr als # Monaten geöffnet}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"App wurde zuletzt geöffnet am <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Zuletzt geöffnet am <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Wenn du die Verwaltung aller Dateien erlaubst, kann diese App auf sämtliche Dateien im gemeinsamen Speicher sowie auf angeschlossenen Speichergeräten zugreifen und sie ändern und löschen. Die App greift dann möglicherweise auf Dateien zu, ohne dass du vorher gefragt wirst."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Nicht zugelassen"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Weitere Apps anzeigen, die auf alle Dateien zugreifen können"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 Tag}other{# Tage}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 Stunde}other{# Stunden}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 Minute}other{# Minuten}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 Sekunde}other{# Sekunden}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# Stunde}other{# Stunden}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# Minute}other{# Minuten}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# Sekunde}other{# Sekunden}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Berechtigungserinnerungen"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 nicht verwendete App"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> nicht verwendete Apps"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Einige Apps wurden seit mehreren Monaten nicht genutzt. Zum Prüfen tippen."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# nicht verwendete App}other{# nicht verwendete Apps}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Berechtigungen und temporäre Dateien wurden entfernt und Benachrichtigungen wurden gestoppt. Zum Prüfen tippen."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Apps prüfen, für die Berechtigungen entfernt wurden"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Wenn du eine App einige Zeit lang nicht mehr verwendet hast, wurden Berechtigungen und temporäre Dateien entfernt und Benachrichtigungen pausiert."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Apps prüfen"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Zuletzt gewährte Berechtigungen prüfen"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Während der Fahrt hast du <xliff:g id="APP">%1$s</xliff:g> Zugriff auf die Berechtigung „<xliff:g id="PERMISSION">%2$s</xliff:g>“ gewährt"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Während der Fahrt hast du <xliff:g id="APP">%1$s</xliff:g> Zugriff auf die Berechtigungen „<xliff:g id="PERMISSION_1">%2$s</xliff:g>“ &amp; „<xliff:g id="PERMISSION_2">%3$s</xliff:g>“ gewährt"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Berechtigungen zum Schutz deiner Privatsphäre entfernt"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> greift im Hintergrund auf deinen Standort zu"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Diese App kann immer auf deinen Standort zugreifen. Zum Ändern hier tippen."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"App mit Zugriff auf deine Benachrichtigungen prüfen"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> kann deine Benachrichtigungen schließen, auf sie reagieren und auf deren Inhalte zugreifen"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Diese App kann deine Benachrichtigungen schließen, auf sie reagieren und auf deren Inhalte zugreifen. Einige Apps benötigen diesen Zugriff, um wie vorgesehen zu funktionieren."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Zugriff entfernen"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Weitere Optionen ansehen"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Zugriff entfernt"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"App mit vollständigem Gerätezugriff prüfen"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> kann deinen Bildschirm sehen und Aktionen auf deinem Gerät ausführen. Bedienungshilfen-Apps benötigen diesen Zugriff, um wie vorgesehen zu funktionieren."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Diese App kann deinen Bildschirm sehen und Aktionen auf deinem Gerät ausführen. Apps für Bedienungshilfen benötigen diesen Zugriff, um wie vorgesehen zu funktionieren – prüfe jedoch, ob die App vertrauenswürdig ist."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Zugriff entfernen"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Apps mit vollständigem Zugriff ansehen"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Zugriff entfernt"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android-System"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"App-Berechtigungen zum Schutz der Privatsphäre entfernt"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> ist seit einigen Monaten nicht genutzt worden. Zum Prüfen tippen."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> und 1 weitere App sind seit einigen Monaten nicht genutzt worden. Zum Prüfen tippen."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und auf die Berechtigungen „Telefon“, „SMS“, „Kontakte“ und „Kalender“ zugreifen."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und Apps auf deinen verbundenen Geräten streamen."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Dieser Dienst teilt die Fotos, Medien und Benachrichtigungen von deinem Smartphone mit anderen Geräten."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Standard-Notizen-App"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Erteilte Berechtigungen"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Standortzugriff möglich"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Dein IT-Administrator erlaubt der App \"<xliff:g id="APP_NAME">%s</xliff:g>\" den Zugriff auf deinen Standort"</string>
+ <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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"Sicherheit und Datenschutz"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Scannen"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Sicherheit &amp; Datenschutz"</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>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Du kannst jederzeit deine Sicherheits- und Datenschutzeinstellungen überprüfen, um deine Daten besser zu schützen"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Schließen"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Abbrechen"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Einstellungen"</string>
+ <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="4365989229426201877">"Sensorberechtigungen"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Datenschutzeinstellungen"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Berechtigungen"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Sicherheit &amp; Datenschutz"</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>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Kamerazugriff"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Mikrofonzugriff"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Berechtigung entfernt"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Weitere Informationen zur Kameranutzung sehen"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Weitere Informationen zur Mikrofonnutzung sehen"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Kameraberechtigung entfernen"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Mikrofonberechtigung entfernen"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Kürzliche Kameranutzung ansehen"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Kürzliche Mikrofonnutzung ansehen"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Berechtigung für diese App entfernen"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Berechtigung für diese App entfernen"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Dienst verwalten"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Berechtigungen verwalten"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Im Telefonanruf verwendet"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Kürzlich von <xliff:g id="APP_NAME">%1$s</xliff:g> verwendet (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>
<string name="active_app_usage_2_qs" msgid="6107866785243565283">"Von <xliff:g id="APP_NAME">%1$s</xliff:g> verwendet (<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">"Kürzlich von <xliff:g id="APP_NAME">%1$s</xliff:g> verwendet (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
- <string name="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Sicherheit &amp; Datenschutz"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Status prüfen"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Bestätigen"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Zurück"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Der Zugriff auf andere Dateien ist ebenfalls möglich"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Diese App unterstützt nicht die neueste Version von Android. Wenn diese App keinen Zugriff auf Musik- und Audiodateien hat, kann sie auch nicht auf Fotos und Videos zugreifen."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Diese App unterstützt nicht die neueste Version von Android. Wenn diese App Zugriff auf Fotos und Videos hat, kann sie auch auf Musik- und Audiodateien zugreifen."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Diese App unterstützt nicht die neueste Version von Android. Wenn diese App keinen Zugriff auf Musik- und Audiodateien hat, kann sie auch nicht auf Fotos und Videos zugreifen."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"App mit Zugriff auf die Standortermittlung im Hintergrund prüfen"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> kann auch dann auf deinen Standort zugreifen, wenn die App geschlossen ist"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"App mit Zugriff auf die Standortermittlung im Hintergrund prüfen"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Diese App kann auch dann auf deinen Standort zugreifen, wenn sie geschlossen ist.\n\nEinige Sicherheits- und Notfall-Apps benötigen Zugriff auf deinen Standort im Hintergrund, um wie vorgesehen zu funktionieren."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Zugriff geändert"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Kürzliche Standortnutzung ansehen"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Datenschutzeinstellungen"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Kamerazugriff"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Mikrofonzugriff"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Für Apps und Dienste"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Für Apps und Dienste. Wenn diese Einstellung deaktiviert ist, können Mikrofondaten dennoch freigegeben werden, wenn du den Notruf wählst."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Apps und Dienste sehen, die Zugriff auf diesen Standort haben"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Zugriff auf Zwischenablage anzeigen"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Eine Meldung wird angezeigt, wenn Apps auf Text, Bilder oder andere Inhalte zugreifen, die du kopiert hast"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Passwörter anzeigen"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Zeichen während der Eingabe kurz anzeigen"</string>
+ <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_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>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Werbung oder Marketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Betrugsprävention, Sicherheit und Compliance"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalisierung"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Kontoverwaltung"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Die Entwickler dieser Apps haben Informationen über ihre Praktiken zur Datenweitergabe an App-Shops zur Verfügung gestellt. Diese Praktiken können im Laufe der Zeit geändert werden.\n\nPraktiken zur Datenweitergabe können je nach App-Version, Verwendung, Region und Alter des Nutzers variieren."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Informationen zur Datenweitergabe"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Deine Standortdaten werden ab jetzt an Dritte weitergegeben"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Deine Standortdaten werden ab jetzt zu Werbe- oder Marketingzwecken an Dritte weitergegeben"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Innerhalb der letzten 24 Stunden geändert}=1{Innerhalb der letzten 24 Stunden geändert}other{Innerhalb von # Tagen geändert}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Aktuell keine Änderungen"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-el-v33/strings.xml b/PermissionController/res/values-el-v33/strings.xml
index fea961455..7d1cbfbac 100644
--- a/PermissionController/res/values-el-v33/strings.xml
+++ b/PermissionController/res/values-el-v33/strings.xml
@@ -19,4 +19,28 @@
<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="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>
+ <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>
+ <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{Αναπτύξτε και δείτε μία ακόμη ειδοποίηση}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Κλείσιμο"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Ανάπτυξη και εμφάνιση επιλογών"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Σύμπτυξη"</string>
+ <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_gear_label" msgid="5175877094379694098">"Ρυθμίσεις"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Πληροφορίες"</string>
</resources>
diff --git a/PermissionController/res/values-el-v34/strings.xml b/PermissionController/res/values-el-v34/strings.xml
new file mode 100644
index 000000000..0c8541787
--- /dev/null
+++ b/PermissionController/res/values-el-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-el/strings.xml b/PermissionController/res/values-el/strings.xml
index 545f3cf76..a28874ea9 100644
--- a/PermissionController/res/values-el/strings.xml
+++ b/PermissionController/res/values-el/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"Να επιτρέπονται πάντα όλα"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Εντοπίστηκε επικάλυψη οθόνης"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Για να αλλάξετε αυτήν τη ρύθμιση άδειας, θα πρέπει πρώτα να απενεργοποιήσετε την επικάλυψη οθόνης από τις Ρυθμίσεις &gt; Εφαρμογές"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Άνοιγμα ρυθμίσεων"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Χρονολόγιο των περιπτώσεων που οι εφαρμογές χρησιμοπ. την ομάδα αδειών \"<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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 ημέρα}other{# ημέρες}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 ώρα}other{# ώρες}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 λεπτό}other{# λεπτά}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 δευτ.}other{# δευτ.}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# ημέρα}other{# ημέρες}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# ώρα}other{# ώρες}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# λεπτό}other{# λεπτά}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# δευτερόλεπτο}other{# δευτερόλεπτα}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Οποιαδήποτε άδεια"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"οποιαδήποτε στιγμή"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"τελευταίες 7 ημέρες"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"τελευταίες 24 ώρες"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"τελευταία 1 ώρα"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"τελευταία 15 λεπτά"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"τελευταίο 1 λεπτό"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Τελευταία # ημέρα}other{Τελευταίες # ημέρες}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Τελευταία # ώρα}other{Τελευταίες # ώρες}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Τελευταίο # λεπτό}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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"Δεν έχει χρησιμοποιηθεί τις τελευταίες 24 ώρες"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Δεν έχει χρησιμοποιηθεί τις τελευταίες επτά ημέρες"</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_view_details" msgid="6675335735468752787">"Εμφάνιση όλων στον Πίνακα ελέγχου"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Φιλτράρισμα κατά: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"Να επιτρέπονται πάντα όλα"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Να ερωτώμαι κάθε φορά"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Να μην επιτρέπεται"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Ακριβής τοποθεσία"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> και <xliff:g id="PERM_1">%2$s</xliff:g> άδειες που θα καταργηθούν."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Άδειες που θα καταργηθούν: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Αυτόματη διαχείριση αδειών."</string>
- <string name="off" msgid="1438489226422866263">"Απενεργοποίηση"</string>
<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_tv_summary" msgid="3685907153054355671">"Εάν μια εφαρμογή δεν χρησιμοποιηθεί για λίγους μήνες:\n\n• Οι άδειες καταργούνται για την προστασία των δεδομένων σας\n• Τα προσωρινά αρχεία καταργούνται για την απελευθέρωση χώρου\n\nΓια να επιτρέψετε ξανά τις άδειες, ανοίξτε την εφαρμογή."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Τελευταίο άνοιγμα πάνω από <xliff:g id="NUMBER">%s</xliff:g> μήνες πριν"</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>
@@ -251,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 ώρα}other{# ώρες}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 λεπτό}other{# λεπτά}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 δευτερόλεπτο}other{# δευτερόλεπτα}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# ώρα}other{# ώρες}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<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_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_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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Σύστημα Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Οι άδειες εφαρμογών καταργήθηκαν για προστασία απορρήτου."</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Η εφαρμογή <xliff:g id="APP_NAME">%s</xliff:g> δεν έχει χρησιμοποιηθεί τους τελευταίους μήνες. Πατήστε για έλεγχο."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"Η εφαρμογή <xliff:g id="APP_NAME">%s</xliff:g> και 1 ακόμη εφαρμογή δεν έχουν χρησιμοποιηθεί τους τελευταίους μήνες. Πατήστε για έλεγχο."</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"σημειώσεις"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"Ελεγχόμενες άδειες"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Είναι δυνατή η πρόσβαση στην τοποθεσία."</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Ο διαχειριστής σας επιτρέπει στην εφαρμογή <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"Ασφάλεια και Απόρρητο"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Σάρωση"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"Άδειες αισθητήρων"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Στοιχεία ελέγχου απορρήτου"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"Η άδεια καταργήθηκε"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Δείτε περισσότερα για τη χρήση της κάμερας"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Δείτε περισσότερα για τη χρήση του μικροφώνου"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Κατάργηση άδειας για την κάμερα"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Κατάργηση άδειας για το μικρόφωνο"</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="manage_service_qs" msgid="7862555549364153805">"Διαχείριση υπηρεσίας"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Διαχείριση αδειών"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Χρησιμοποιείται από την τηλεφωνική κλήση"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Ασφάλεια και Απόρρητο"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Έλεγχος κατάστασης"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Επικοινωνία προγραμματιστών"</string>
+ <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="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="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">"Οι προγραμματιστές αυτών των εφαρμογών έχουν καταχωρίσει πληροφορίες σχετικά με τις πρακτικές κοινοποίησης δεδομένων σε ένα app store. Ενδέχεται να τις ενημερώσουν με την πάροδο του χρόνου.\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="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>
</resources>
diff --git a/PermissionController/res/values-en-rAU-v33/strings.xml b/PermissionController/res/values-en-rAU-v33/strings.xml
index 643c0db3d..498c090f3 100644
--- a/PermissionController/res/values-en-rAU-v33/strings.xml
+++ b/PermissionController/res/values-en-rAU-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"This app will be allowed to send you notifications, and will be given access to your camera, contacts, microphone, phone and SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"This app will be allowed to send you notifications, and will be given access to your camera, contacts, files, microphone, phone and SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Apps with this permission can access all files on this device"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Your work policy info"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Settings managed by your IT admin"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Expand and show list"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Collapse list and hide settings"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"List. <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_with_actions_needed_content_description" msgid="2708884606775932657">"List. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Actions needed. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"List item. <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">"More alerts"</string>
+ <string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Dismissed alerts"</string>
+ <string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Expand and see one more alert}other{Expand and see # more alerts}}"</string>
+ <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">"Action complete"</string>
+ <string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Check settings that can add protection to your device"</string>
+ <string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Security and privacy quick settings"</string>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Close"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Expand and show options"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Collapse"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Switch. <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">"Toggle"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Open"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Review settings"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Settings"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Information"</string>
</resources>
diff --git a/PermissionController/res/values-en-rAU-v34/strings.xml b/PermissionController/res/values-en-rAU-v34/strings.xml
new file mode 100644
index 000000000..4800f8a91
--- /dev/null
+++ b/PermissionController/res/values-en-rAU-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Security and privacy"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Controls"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Manage app access to health data"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Location access"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"For apps and services. If this setting is off, microphone data may still be shared when you call an emergency number"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"For apps and services"</string>
+</resources>
diff --git a/PermissionController/res/values-en-rAU/strings.xml b/PermissionController/res/values-en-rAU/strings.xml
index 3b644b5d3..77c6837ad 100644
--- a/PermissionController/res/values-en-rAU/strings.xml
+++ b/PermissionController/res/values-en-rAU/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Back"</string>
<string name="available" msgid="6007778121920339498">"Available"</string>
<string name="blocked" msgid="9195547604866033708">"Blocked"</string>
+ <string name="on" msgid="280241003226755921">"On"</string>
+ <string name="off" msgid="1438489226422866263">"Off"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Uninstall or disable"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"App not found"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Don\'t allow"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Keep \'While the app is in use\'"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Keep \'Only this time\'"</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Don’t allow anyway"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Dismiss"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> of <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Screen overlay detected"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"To change this permission setting, you have to turn off the screen overlay first from Settings &gt; Apps"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Open settings"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Timeline of when apps used your <xliff:g id="PERMGROUP">%1$s</xliff:g> in the past 7 days"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"When this app used your <xliff:g id="PERMGROUP">%1$s</xliff:g> permission"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Learn more"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Learn more about <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Control app access to your <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 day}other{# days}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 hour}other{# hours}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}other{# mins}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 sec}other{# secs}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# day}other{# days}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# hour}other{# hours}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}other{# mins}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# sec}other{# secs}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Any permission"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Any time"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Last 7 days"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Last 24 hours"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Last 1 hour"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Last 15 minutes"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Last 1 minute"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Last # day}other{Last # days}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Last # hour}other{Last # hours}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Last # minute}other{Last # minutes}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"No permission usages"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Most recent access at any time"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Most recent access in last 7 days"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Permission usage in last 1 hour"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Permission usage in last 15 minutes"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Permission usage in last 1 minute"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Not used in past 24 hours"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Not used in past 7 days"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Not used in past # day}other{Not used in past # days}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Not used in past # hour}other{Not used in past # hours}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Used by 1 app}other{Used by # apps}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"See all in Dashboard"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtered by: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Allow access to media only"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Allow all the time"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Allow only while using the app"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Always allow all"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Ask every time"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Don\'t allow"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Precise location"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> and <xliff:g id="PERM_1">%2$s</xliff:g> permissions will be removed."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Permissions that will be removed: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Manage permissions automatically"</string>
- <string name="off" msgid="1438489226422866263">"Off"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"<xliff:g id="PERMISSION_NAME">%s</xliff:g> permission removed"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> and <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> permissions removed"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> and <xliff:g id="NUMBER">%2$s</xliff:g> other permissions removed"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Unused apps"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"If an app is unused for a few months:\n\n• Permissions are removed to protect your data\n• Notifications are stopped to save battery\n• Temporary files are removed to free up space\n\nTo allow permissions and notifications again, open the app."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"If an app is unused for a few months:\n\n• Permissions are removed to protect your data\n• Temporary files are removed to free up space\n\nTo allow permissions again, open the app."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Last opened more than <xliff:g id="NUMBER">%s</xliff:g> months ago"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"If an app is unused for a month:\n\n• Permissions are removed to protect your data\n• Temporary files are removed to free up space\n\nTo allow permissions again, open the app."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Last opened more than # month ago}other{Last opened more than # months ago}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"App last opened on <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Last opened <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"If you allow management of all files, this app can access, modify and delete any files in common storage on this device or connected storage devices. The app may access files without asking you."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Not allowed"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"See more apps that can access all files"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 day}other{# days}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 hour}other{# hours}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minute}other{# minutes}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 second}other{# seconds}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# hour}other{# hours}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minute}other{# minutes}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# second}other{# seconds}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Permission reminders"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 unused app"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> unused apps"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Some apps haven’t been used for a few months. Tap to review."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# unused app}other{# unused apps}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Permissions and temporary files have been removed and notifications were stopped. Tap to review."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Review apps with permissions removed"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"For apps that you haven’t used in a while, permissions and temporary files were removed and notifications were stopped."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Review apps"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Check recent permissions"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"While driving, you gave <xliff:g id="APP">%1$s</xliff:g> access to <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"While driving, you gave <xliff:g id="APP">%1$s</xliff:g> access to <xliff:g id="PERMISSION_1">%2$s</xliff:g> &amp; <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Permissions removed to protect your privacy"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> got your location in the background"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"This app can always access your location. Tap to change."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Review app with access to your notifications"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> can dismiss, act on and access content inside your notifications"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"This app can dismiss, act on and access content inside your notifications. Some apps require this access to function as intended."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Remove access"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"See more options"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Access removed"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Review app with full device access"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> can view your screen and perform actions on your device. Accessibility apps need this type of access to function as intended."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"This app can view your screen and perform actions on your device. Accessibility apps need this type of access to function as intended, but check the app and make sure that you trust it."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Remove access"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"View apps with full access"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Access removed"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android system"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"App permissions removed to protect privacy"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> hasn’t been used for a few months. Tap to review."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> and one other app haven’t been used for a few months. Tap to review."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and stream your apps to the connected device."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"This service shares your photos, media and notifications from your phone to other devices."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Default notes app"</string>
+ <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="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>
@@ -452,6 +475,7 @@
<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_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 more photos and videos on this device?"</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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Controlled permissions"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Location can be accessed"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Your IT admin is allowing <xliff:g id="APP_NAME">%s</xliff:g> to access your location"</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>
<string name="other_permissions_label" msgid="8986184335503271992">"Other permissions"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Permission used by the system"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Permissions used only by the system applications."</string>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"Security and privacy"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Scan"</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>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Review your security and privacy settings at any time to add more protection"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Dismiss"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Cancel"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Settings"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Security and privacy status. <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">"Security settings"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Sensor permissions"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Privacy controls"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Permissions"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Security &amp; privacy"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Check status"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Your privacy controls"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"More settings"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Camera access"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Mic access"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Permission removed"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"See more camera usage"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"See more microphone usage"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Remove camera permission"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Remove microphone permission"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"See recent camera usage"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"See recent mic usage"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Remove permission for this app"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Remove permission for this app"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Manage service"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Manage permissions"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Being used by phone call"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Recently used by <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">"Being used by <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">"Recently used by <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Security and privacy"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Check status"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Confirm"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Back"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Access to other files will also be allowed"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"This app doesn’t support the latest version of Android. If this app can’t access music and audio files, it also won’t be allowed to access photos and videos."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"This app doesn’t support the latest version of Android. If this app can access photos and videos, it will also be allowed to access music and audio files."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"This app doesn’t support the latest version of Android. If this app can’t access music and audio files, it also won’t be allowed to access photos and videos."</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">"Review app with background location access"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"This app can always access your location, even when it\'s closed.\n\nSome safety and emergency apps require access to your location in the background to work as intended."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Access changed"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"See recent location usage"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Privacy controls"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Camera access"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Microphone access"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"For apps and services"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"For apps and services. If this setting is off, microphone data may still be shared when you call an emergency number."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"See apps and services that have access to location"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Show clipboard access"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Show a message when apps access text, images or other content that you’ve copied"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Show passwords"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Display characters briefly as you type"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Data practices may vary based on your app version, use, region and age. "<annotation id="link">"More about data sharing"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Data practices may vary based on your app version, use, region and age."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Your location data"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Change this app’s access in "<annotation id="link">"privacy settings"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"App functionality"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analytics"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Developer communications"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Advertising or marketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Fraud prevention, security and compliance"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalisation"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Account management"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"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."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Learn about data sharing"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Your location data is now shared with third parties"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Your location data is now shared with third parties for advertising or marketing"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Updated within the last day}=1{Updated within the last day}other{Updated within # days}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"No updates at this time"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-en-rCA-v33/strings.xml b/PermissionController/res/values-en-rCA-v33/strings.xml
index 5c58c7918..84fda13e2 100644
--- a/PermissionController/res/values-en-rCA-v33/strings.xml
+++ b/PermissionController/res/values-en-rCA-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"This app will be allowed to send you Notifications, and will be given access to your Camera, Contacts, Microphone, Phone, and SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"This app will be allowed to send you Notifications, and will be given access to your Camera, Contacts, Files, Microphone, Phone, and SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Apps with this permission can access all files on this device"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Your work policy info"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Settings managed by your IT admin"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Expand and show list"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Collapse list and hide settings"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"List. <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_with_actions_needed_content_description" msgid="2708884606775932657">"List. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Actions needed. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"List item. <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">"More alerts"</string>
+ <string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Dismissed alerts"</string>
+ <string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Expand and see one more alert}other{Expand and see # more alerts}}"</string>
+ <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">"Action complete"</string>
+ <string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Check settings that can add protection to your device"</string>
+ <string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Security and privacy quick settings"</string>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Close"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Expand and show options"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Collapse"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Switch. <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">"Toggle"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Open"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Review settings"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Settings"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Information"</string>
</resources>
diff --git a/PermissionController/res/values-en-rCA-v34/strings.xml b/PermissionController/res/values-en-rCA-v34/strings.xml
new file mode 100644
index 000000000..4800f8a91
--- /dev/null
+++ b/PermissionController/res/values-en-rCA-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Security and privacy"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Controls"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Manage app access to health data"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Location access"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"For apps and services. If this setting is off, microphone data may still be shared when you call an emergency number"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"For apps and services"</string>
+</resources>
diff --git a/PermissionController/res/values-en-rCA/strings.xml b/PermissionController/res/values-en-rCA/strings.xml
index e1c257e9f..ef5fb9086 100644
--- a/PermissionController/res/values-en-rCA/strings.xml
+++ b/PermissionController/res/values-en-rCA/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Back"</string>
<string name="available" msgid="6007778121920339498">"Available"</string>
<string name="blocked" msgid="9195547604866033708">"Blocked"</string>
+ <string name="on" msgid="280241003226755921">"On"</string>
+ <string name="off" msgid="1438489226422866263">"Off"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Uninstall or disable"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"App not found"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Don\'t allow"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Keep “While the app is in use”"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Keep “Only this time”"</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Don’t allow anyway"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Dismiss"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> of <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Screen overlay detected"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"To change this permission setting, you first have to turn off the screen overlay from Settings &gt; Apps"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Open settings"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Timeline of when apps used your <xliff:g id="PERMGROUP">%1$s</xliff:g> in the past 7 days"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"When this app used your <xliff:g id="PERMGROUP">%1$s</xliff:g> permission"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Learn more"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Learn more about <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Control app access to your <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 day}other{# days}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 hour}other{# hours}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}other{# mins}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 sec}other{# secs}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# day}other{# days}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# hour}other{# hours}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}other{# mins}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# sec}other{# secs}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Any permission"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Any time"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Last 7 days"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Last 24 hours"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Last 1 hour"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Last 15 minutes"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Last 1 minute"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Last # day}other{Last # days}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Last # hour}other{Last # hours}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Last # minute}other{Last # minutes}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"No permission usages"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Most recent access at any time"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Most recent access in last 7 days"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Permission usage in last 1 hour"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Permission usage in last 15 minutes"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Permission usage in last 1 minute"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Not used in past 24 hours"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Not used in past 7 days"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Not used in past # day}other{Not used in past # days}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Not used in past # hour}other{Not used in past # hours}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Used by 1 app}other{Used by # apps}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"See all in Dashboard"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtered by: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Allow access to media only"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Allow all the time"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Allow only while using the app"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Always allow all"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Ask every time"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Don\'t allow"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Precise location"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> and <xliff:g id="PERM_1">%2$s</xliff:g> permissions will be removed."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Permissions that will be removed: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Manage permissions automatically"</string>
- <string name="off" msgid="1438489226422866263">"Off"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"<xliff:g id="PERMISSION_NAME">%s</xliff:g> permission removed"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> and <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> permissions removed"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> and <xliff:g id="NUMBER">%2$s</xliff:g> other permissions removed"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Unused apps"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"If an app is unused for a few months:\n\n• Permissions are removed to protect your data\n• Notifications are stopped to save battery\n• Temporary files are removed to free up space\n\nTo allow permissions and notifications again, open the app."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"If an app is unused for a few months:\n\n• Permissions are removed to protect your data\n• Temporary files are removed to free up space\n\nTo allow permissions again, open the app."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Last opened more than <xliff:g id="NUMBER">%s</xliff:g> months ago"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"If an app is unused for a month:\n\n• Permissions are removed to protect your data\n• Temporary files are removed to free up space\n\nTo allow permissions again, open the app."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Last opened more than # month ago}other{Last opened more than # months ago}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"App last opened on <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Last opened <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"If you allow management of all files, this app can access, modify, and delete any files in common storage on this device or connected storage devices. The app may access files without asking you."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Not allowed"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"See more apps that can access all files"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 day}other{# days}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 hour}other{# hours}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minute}other{# minutes}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 second}other{# seconds}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# hour}other{# hours}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minute}other{# minutes}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# second}other{# seconds}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Permission reminders"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 unused app"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> unused apps"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Some apps haven’t been used in a few months. Tap to review."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# unused app}other{# unused apps}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Permissions and temporary files have been removed and notifications were stopped. Tap to review."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Review apps with permissions removed"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"For apps that you haven’t used in a while, permissions and temporary files were removed and notifications were stopped."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Review apps"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Check recent permissions"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"While driving, you gave <xliff:g id="APP">%1$s</xliff:g> access to <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"While driving, you gave <xliff:g id="APP">%1$s</xliff:g> access to <xliff:g id="PERMISSION_1">%2$s</xliff:g> &amp; <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Permissions removed to protect your privacy"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> got your location in the background"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"This app can always access your location. Tap to change."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Review app with access to your notifications"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> can dismiss, act on, and access content inside your notifications"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"This app can dismiss, act on, and access content inside your notifications. Some apps require this access to function as intended."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Remove access"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"See more options"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Access removed"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Review app with full device access"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> can view your screen and perform actions on your device. Accessibility apps need this type of access to function as intended."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"This app can view your screen and perform actions on your device. Accessibility apps need this type of access to function as intended, but check the app and make sure you trust it."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Remove access"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"View apps with full access"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Access removed"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android System"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"App permissions removed to protect privacy"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> hasn’t been used in a few months. Tap to review."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> and 1 other app haven’t been used in a few months. Tap to review."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and stream your apps to the connected device."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"This service shares your photos, media, and notifications from your phone to other devices."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Default notes app"</string>
+ <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="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>
@@ -452,6 +475,7 @@
<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_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 more photos and videos on this device?"</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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Controlled permissions"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Location can be accessed"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Your IT admin is allowing <xliff:g id="APP_NAME">%s</xliff:g> to access your location"</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>
<string name="other_permissions_label" msgid="8986184335503271992">"Other permissions"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Permission used by the system"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Permissions used only by the system applications."</string>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"Security and privacy"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Scan"</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>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Review your security and privacy settings any time to add more protection"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Dismiss"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Cancel"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Settings"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Security and privacy status. <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">"Security Settings"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Sensor Permissions"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Privacy Controls"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Permissions"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Security and privacy"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Check status"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Your privacy controls"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"More settings"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Camera access"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Mic access"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Permission removed"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"See more camera usage"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"See more microphone usage"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Remove camera permission"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Remove microphone permission"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"See recent camera usage"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"See recent mic usage"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Remove permission for this app"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Remove permission for this app"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Manage service"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Manage permissions"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Being used by phone call"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Recently used by <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">"Being used by <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">"Recently used by <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Security and privacy"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Check status"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Confirm"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Back"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Access to other files will also be allowed"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"This app doesn’t support the latest version of Android. If this app can’t access music and audio files, it also won’t be allowed to access photos and videos."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"This app doesn’t support the latest version of Android. If this app can access photos and videos, it will also be allowed to access music and audio files."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"This app doesn’t support the latest version of Android. If this app can’t access music and audio files, it also won’t be allowed to access photos and videos."</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">"Review app with background location access"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"This app can always access your location, even when it’s closed.\n\nSome safety and emergency apps require access to your location in the background to work as intended."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Access changed"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"See recent location usage"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Privacy controls"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Camera access"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Microphone access"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"For apps and services"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"For apps and services. If this setting is off, microphone data may still be shared when you call an emergency number."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"See apps and services that have access to location"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Show clipboard access"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Show a message when apps access text, images, or other content you’ve copied"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Show passwords"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Display characters briefly as you type"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Data practices may vary based on your app version, use, region, and age. "<annotation id="link">"More about data sharing"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Data practices may vary based on your app version, use, region, and age."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Your location data"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Change this app’s access in "<annotation id="link">"privacy settings"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"App functionality"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analytics"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Developer communications"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Advertising or marketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Fraud prevention, security, and compliance"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalization"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Account management"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"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."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Learn about data sharing"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Your location data is now shared with third parties"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Your location data is now shared with third parties for advertising or marketing"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Updated within the last day}=1{Updated within the last day}other{Updated within # days}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"No updates at this time"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-en-rGB-v33/strings.xml b/PermissionController/res/values-en-rGB-v33/strings.xml
index 643c0db3d..498c090f3 100644
--- a/PermissionController/res/values-en-rGB-v33/strings.xml
+++ b/PermissionController/res/values-en-rGB-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"This app will be allowed to send you notifications, and will be given access to your camera, contacts, microphone, phone and SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"This app will be allowed to send you notifications, and will be given access to your camera, contacts, files, microphone, phone and SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Apps with this permission can access all files on this device"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Your work policy info"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Settings managed by your IT admin"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Expand and show list"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Collapse list and hide settings"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"List. <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_with_actions_needed_content_description" msgid="2708884606775932657">"List. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Actions needed. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"List item. <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">"More alerts"</string>
+ <string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Dismissed alerts"</string>
+ <string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Expand and see one more alert}other{Expand and see # more alerts}}"</string>
+ <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">"Action complete"</string>
+ <string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Check settings that can add protection to your device"</string>
+ <string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Security and privacy quick settings"</string>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Close"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Expand and show options"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Collapse"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Switch. <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">"Toggle"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Open"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Review settings"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Settings"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Information"</string>
</resources>
diff --git a/PermissionController/res/values-en-rGB-v34/strings.xml b/PermissionController/res/values-en-rGB-v34/strings.xml
new file mode 100644
index 000000000..4800f8a91
--- /dev/null
+++ b/PermissionController/res/values-en-rGB-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Security and privacy"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Controls"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Manage app access to health data"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Location access"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"For apps and services. If this setting is off, microphone data may still be shared when you call an emergency number"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"For apps and services"</string>
+</resources>
diff --git a/PermissionController/res/values-en-rGB/strings.xml b/PermissionController/res/values-en-rGB/strings.xml
index ecc01752f..9feaad707 100644
--- a/PermissionController/res/values-en-rGB/strings.xml
+++ b/PermissionController/res/values-en-rGB/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Back"</string>
<string name="available" msgid="6007778121920339498">"Available"</string>
<string name="blocked" msgid="9195547604866033708">"Blocked"</string>
+ <string name="on" msgid="280241003226755921">"On"</string>
+ <string name="off" msgid="1438489226422866263">"Off"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Uninstall or disable"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"App not found"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Don\'t allow"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Keep \'While the app is in use\'"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Keep \'Only this time\'"</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Don’t allow anyway"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Dismiss"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> of <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Screen overlay detected"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"To change this permission setting, you have to turn off the screen overlay first from Settings &gt; Apps"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Open settings"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Timeline of when apps used your <xliff:g id="PERMGROUP">%1$s</xliff:g> in the past 7 days"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"When this app used your <xliff:g id="PERMGROUP">%1$s</xliff:g> permission"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Learn more"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Learn more about <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Control app access to your <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 day}other{# days}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 hour}other{# hours}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}other{# mins}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 sec}other{# secs}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# day}other{# days}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# hour}other{# hours}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}other{# mins}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# sec}other{# secs}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Any permission"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Any time"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Last 7 days"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Last 24 hours"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Last 1 hour"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Last 15 minutes"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Last 1 minute"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Last # day}other{Last # days}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Last # hour}other{Last # hours}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Last # minute}other{Last # minutes}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"No permission usages"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Most recent access at any time"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Most recent access in last 7 days"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Permission usage in last 1 hour"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Permission usage in last 15 minutes"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Permission usage in last 1 minute"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Not used in past 24 hours"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Not used in past 7 days"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Not used in past # day}other{Not used in past # days}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Not used in past # hour}other{Not used in past # hours}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Used by 1 app}other{Used by # apps}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"See all in Dashboard"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtered by: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Allow access to media only"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Allow all the time"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Allow only while using the app"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Always allow all"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Ask every time"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Don\'t allow"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Precise location"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> and <xliff:g id="PERM_1">%2$s</xliff:g> permissions will be removed."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Permissions that will be removed: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Manage permissions automatically"</string>
- <string name="off" msgid="1438489226422866263">"Off"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"<xliff:g id="PERMISSION_NAME">%s</xliff:g> permission removed"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> and <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> permissions removed"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> and <xliff:g id="NUMBER">%2$s</xliff:g> other permissions removed"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Unused apps"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"If an app is unused for a few months:\n\n• Permissions are removed to protect your data\n• Notifications are stopped to save battery\n• Temporary files are removed to free up space\n\nTo allow permissions and notifications again, open the app."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"If an app is unused for a few months:\n\n• Permissions are removed to protect your data\n• Temporary files are removed to free up space\n\nTo allow permissions again, open the app."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Last opened more than <xliff:g id="NUMBER">%s</xliff:g> months ago"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"If an app is unused for a month:\n\n• Permissions are removed to protect your data\n• Temporary files are removed to free up space\n\nTo allow permissions again, open the app."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Last opened more than # month ago}other{Last opened more than # months ago}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"App last opened on <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Last opened <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"If you allow management of all files, this app can access, modify and delete any files in common storage on this device or connected storage devices. The app may access files without asking you."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Not allowed"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"See more apps that can access all files"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 day}other{# days}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 hour}other{# hours}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minute}other{# minutes}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 second}other{# seconds}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# hour}other{# hours}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minute}other{# minutes}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# second}other{# seconds}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Permission reminders"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 unused app"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> unused apps"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Some apps haven’t been used for a few months. Tap to review."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# unused app}other{# unused apps}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Permissions and temporary files have been removed and notifications were stopped. Tap to review."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Review apps with permissions removed"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"For apps that you haven’t used in a while, permissions and temporary files were removed and notifications were stopped."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Review apps"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Check recent permissions"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"While driving, you gave <xliff:g id="APP">%1$s</xliff:g> access to <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"While driving, you gave <xliff:g id="APP">%1$s</xliff:g> access to <xliff:g id="PERMISSION_1">%2$s</xliff:g> &amp; <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Permissions removed to protect your privacy"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> got your location in the background"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"This app can always access your location. Tap to change."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Review app with access to your notifications"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> can dismiss, act on and access content inside your notifications"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"This app can dismiss, act on and access content inside your notifications. Some apps require this access to function as intended."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Remove access"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"See more options"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Access removed"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Review app with full device access"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> can view your screen and perform actions on your device. Accessibility apps need this type of access to function as intended."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"This app can view your screen and perform actions on your device. Accessibility apps need this type of access to function as intended, but check the app and make sure that you trust it."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Remove access"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"View apps with full access"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Access removed"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android system"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"App permissions removed to protect privacy"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> hasn’t been used for a few months. Tap to review."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> and one other app haven’t been used for a few months. Tap to review."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and stream your apps to the connected device."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"This service shares your photos, media and notifications from your phone to other devices."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Default notes app"</string>
+ <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="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>
@@ -452,6 +475,7 @@
<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_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 more photos and videos on this device?"</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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Controlled permissions"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Location can be accessed"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Your IT admin is allowing <xliff:g id="APP_NAME">%s</xliff:g> to access your location"</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>
<string name="other_permissions_label" msgid="8986184335503271992">"Other permissions"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Permission used by the system"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Permissions used only by the system applications."</string>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"Security and privacy"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Scan"</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>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Review your security and privacy settings at any time to add more protection"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Dismiss"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Cancel"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Settings"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Security and privacy status. <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">"Security settings"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Sensor permissions"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Privacy controls"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Permissions"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Security &amp; privacy"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Check status"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Your privacy controls"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"More settings"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Camera access"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Mic access"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Permission removed"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"See more camera usage"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"See more microphone usage"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Remove camera permission"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Remove microphone permission"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"See recent camera usage"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"See recent mic usage"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Remove permission for this app"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Remove permission for this app"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Manage service"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Manage permissions"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Being used by phone call"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Recently used by <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">"Being used by <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">"Recently used by <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Security and privacy"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Check status"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Confirm"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Back"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Access to other files will also be allowed"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"This app doesn’t support the latest version of Android. If this app can’t access music and audio files, it also won’t be allowed to access photos and videos."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"This app doesn’t support the latest version of Android. If this app can access photos and videos, it will also be allowed to access music and audio files."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"This app doesn’t support the latest version of Android. If this app can’t access music and audio files, it also won’t be allowed to access photos and videos."</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">"Review app with background location access"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"This app can always access your location, even when it\'s closed.\n\nSome safety and emergency apps require access to your location in the background to work as intended."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Access changed"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"See recent location usage"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Privacy controls"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Camera access"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Microphone access"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"For apps and services"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"For apps and services. If this setting is off, microphone data may still be shared when you call an emergency number."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"See apps and services that have access to location"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Show clipboard access"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Show a message when apps access text, images or other content that you’ve copied"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Show passwords"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Display characters briefly as you type"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Data practices may vary based on your app version, use, region and age. "<annotation id="link">"More about data sharing"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Data practices may vary based on your app version, use, region and age."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Your location data"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Change this app’s access in "<annotation id="link">"privacy settings"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"App functionality"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analytics"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Developer communications"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Advertising or marketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Fraud prevention, security and compliance"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalisation"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Account management"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"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."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Learn about data sharing"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Your location data is now shared with third parties"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Your location data is now shared with third parties for advertising or marketing"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Updated within the last day}=1{Updated within the last day}other{Updated within # days}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"No updates at this time"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-en-rIN-v33/strings.xml b/PermissionController/res/values-en-rIN-v33/strings.xml
index 643c0db3d..498c090f3 100644
--- a/PermissionController/res/values-en-rIN-v33/strings.xml
+++ b/PermissionController/res/values-en-rIN-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"This app will be allowed to send you notifications, and will be given access to your camera, contacts, microphone, phone and SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"This app will be allowed to send you notifications, and will be given access to your camera, contacts, files, microphone, phone and SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Apps with this permission can access all files on this device"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Your work policy info"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Settings managed by your IT admin"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Expand and show list"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Collapse list and hide settings"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"List. <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_with_actions_needed_content_description" msgid="2708884606775932657">"List. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Actions needed. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"List item. <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">"More alerts"</string>
+ <string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Dismissed alerts"</string>
+ <string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Expand and see one more alert}other{Expand and see # more alerts}}"</string>
+ <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">"Action complete"</string>
+ <string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Check settings that can add protection to your device"</string>
+ <string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Security and privacy quick settings"</string>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Close"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Expand and show options"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Collapse"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Switch. <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">"Toggle"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Open"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Review settings"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Settings"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Information"</string>
</resources>
diff --git a/PermissionController/res/values-en-rIN-v34/strings.xml b/PermissionController/res/values-en-rIN-v34/strings.xml
new file mode 100644
index 000000000..4800f8a91
--- /dev/null
+++ b/PermissionController/res/values-en-rIN-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Security and privacy"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Controls"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Manage app access to health data"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Location access"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"For apps and services. If this setting is off, microphone data may still be shared when you call an emergency number"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"For apps and services"</string>
+</resources>
diff --git a/PermissionController/res/values-en-rIN/strings.xml b/PermissionController/res/values-en-rIN/strings.xml
index ecc01752f..9feaad707 100644
--- a/PermissionController/res/values-en-rIN/strings.xml
+++ b/PermissionController/res/values-en-rIN/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Back"</string>
<string name="available" msgid="6007778121920339498">"Available"</string>
<string name="blocked" msgid="9195547604866033708">"Blocked"</string>
+ <string name="on" msgid="280241003226755921">"On"</string>
+ <string name="off" msgid="1438489226422866263">"Off"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Uninstall or disable"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"App not found"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Don\'t allow"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Keep \'While the app is in use\'"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Keep \'Only this time\'"</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Don’t allow anyway"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Dismiss"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> of <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Screen overlay detected"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"To change this permission setting, you have to turn off the screen overlay first from Settings &gt; Apps"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Open settings"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Timeline of when apps used your <xliff:g id="PERMGROUP">%1$s</xliff:g> in the past 7 days"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"When this app used your <xliff:g id="PERMGROUP">%1$s</xliff:g> permission"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Learn more"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Learn more about <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Control app access to your <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 day}other{# days}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 hour}other{# hours}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}other{# mins}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 sec}other{# secs}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# day}other{# days}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# hour}other{# hours}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}other{# mins}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# sec}other{# secs}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Any permission"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Any time"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Last 7 days"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Last 24 hours"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Last 1 hour"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Last 15 minutes"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Last 1 minute"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Last # day}other{Last # days}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Last # hour}other{Last # hours}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Last # minute}other{Last # minutes}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"No permission usages"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Most recent access at any time"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Most recent access in last 7 days"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Permission usage in last 1 hour"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Permission usage in last 15 minutes"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Permission usage in last 1 minute"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Not used in past 24 hours"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Not used in past 7 days"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Not used in past # day}other{Not used in past # days}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Not used in past # hour}other{Not used in past # hours}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Used by 1 app}other{Used by # apps}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"See all in Dashboard"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtered by: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Allow access to media only"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Allow all the time"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Allow only while using the app"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Always allow all"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Ask every time"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Don\'t allow"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Precise location"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> and <xliff:g id="PERM_1">%2$s</xliff:g> permissions will be removed."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Permissions that will be removed: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Manage permissions automatically"</string>
- <string name="off" msgid="1438489226422866263">"Off"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"<xliff:g id="PERMISSION_NAME">%s</xliff:g> permission removed"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> and <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> permissions removed"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> and <xliff:g id="NUMBER">%2$s</xliff:g> other permissions removed"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Unused apps"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"If an app is unused for a few months:\n\n• Permissions are removed to protect your data\n• Notifications are stopped to save battery\n• Temporary files are removed to free up space\n\nTo allow permissions and notifications again, open the app."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"If an app is unused for a few months:\n\n• Permissions are removed to protect your data\n• Temporary files are removed to free up space\n\nTo allow permissions again, open the app."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Last opened more than <xliff:g id="NUMBER">%s</xliff:g> months ago"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"If an app is unused for a month:\n\n• Permissions are removed to protect your data\n• Temporary files are removed to free up space\n\nTo allow permissions again, open the app."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Last opened more than # month ago}other{Last opened more than # months ago}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"App last opened on <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Last opened <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"If you allow management of all files, this app can access, modify and delete any files in common storage on this device or connected storage devices. The app may access files without asking you."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Not allowed"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"See more apps that can access all files"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 day}other{# days}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 hour}other{# hours}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minute}other{# minutes}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 second}other{# seconds}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# hour}other{# hours}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minute}other{# minutes}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# second}other{# seconds}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Permission reminders"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 unused app"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> unused apps"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Some apps haven’t been used for a few months. Tap to review."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# unused app}other{# unused apps}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Permissions and temporary files have been removed and notifications were stopped. Tap to review."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Review apps with permissions removed"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"For apps that you haven’t used in a while, permissions and temporary files were removed and notifications were stopped."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Review apps"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Check recent permissions"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"While driving, you gave <xliff:g id="APP">%1$s</xliff:g> access to <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"While driving, you gave <xliff:g id="APP">%1$s</xliff:g> access to <xliff:g id="PERMISSION_1">%2$s</xliff:g> &amp; <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Permissions removed to protect your privacy"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> got your location in the background"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"This app can always access your location. Tap to change."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Review app with access to your notifications"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> can dismiss, act on and access content inside your notifications"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"This app can dismiss, act on and access content inside your notifications. Some apps require this access to function as intended."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Remove access"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"See more options"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Access removed"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Review app with full device access"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> can view your screen and perform actions on your device. Accessibility apps need this type of access to function as intended."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"This app can view your screen and perform actions on your device. Accessibility apps need this type of access to function as intended, but check the app and make sure that you trust it."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Remove access"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"View apps with full access"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Access removed"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android system"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"App permissions removed to protect privacy"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> hasn’t been used for a few months. Tap to review."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> and one other app haven’t been used for a few months. Tap to review."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and stream your apps to the connected device."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"This service shares your photos, media and notifications from your phone to other devices."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Default notes app"</string>
+ <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="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>
@@ -452,6 +475,7 @@
<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_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 more photos and videos on this device?"</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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Controlled permissions"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Location can be accessed"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Your IT admin is allowing <xliff:g id="APP_NAME">%s</xliff:g> to access your location"</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>
<string name="other_permissions_label" msgid="8986184335503271992">"Other permissions"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Permission used by the system"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Permissions used only by the system applications."</string>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"Security and privacy"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Scan"</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>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Review your security and privacy settings at any time to add more protection"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Dismiss"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Cancel"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Settings"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Security and privacy status. <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">"Security settings"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Sensor permissions"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Privacy controls"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Permissions"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Security &amp; privacy"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Check status"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Your privacy controls"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"More settings"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Camera access"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Mic access"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Permission removed"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"See more camera usage"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"See more microphone usage"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Remove camera permission"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Remove microphone permission"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"See recent camera usage"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"See recent mic usage"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Remove permission for this app"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Remove permission for this app"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Manage service"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Manage permissions"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Being used by phone call"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Recently used by <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">"Being used by <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">"Recently used by <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Security and privacy"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Check status"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Confirm"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Back"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Access to other files will also be allowed"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"This app doesn’t support the latest version of Android. If this app can’t access music and audio files, it also won’t be allowed to access photos and videos."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"This app doesn’t support the latest version of Android. If this app can access photos and videos, it will also be allowed to access music and audio files."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"This app doesn’t support the latest version of Android. If this app can’t access music and audio files, it also won’t be allowed to access photos and videos."</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">"Review app with background location access"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"This app can always access your location, even when it\'s closed.\n\nSome safety and emergency apps require access to your location in the background to work as intended."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Access changed"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"See recent location usage"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Privacy controls"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Camera access"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Microphone access"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"For apps and services"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"For apps and services. If this setting is off, microphone data may still be shared when you call an emergency number."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"See apps and services that have access to location"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Show clipboard access"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Show a message when apps access text, images or other content that you’ve copied"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Show passwords"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Display characters briefly as you type"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Data practices may vary based on your app version, use, region and age. "<annotation id="link">"More about data sharing"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Data practices may vary based on your app version, use, region and age."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Your location data"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Change this app’s access in "<annotation id="link">"privacy settings"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"App functionality"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analytics"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Developer communications"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Advertising or marketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Fraud prevention, security and compliance"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalisation"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Account management"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"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."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Learn about data sharing"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Your location data is now shared with third parties"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Your location data is now shared with third parties for advertising or marketing"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Updated within the last day}=1{Updated within the last day}other{Updated within # days}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"No updates at this time"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-en-rXC-v33/strings.xml b/PermissionController/res/values-en-rXC-v33/strings.xml
index 855462c6d..af0471700 100644
--- a/PermissionController/res/values-en-rXC-v33/strings.xml
+++ b/PermissionController/res/values-en-rXC-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‎‎‎‏‎‏‏‎‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‏‏‎This app will be allowed to send you Notifications, and will be given access to your Camera, Contacts, Microphone, Phone, and SMS‎‏‎‎‏‎"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‎‏‎‎‏‏‏‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‏‏‎‏‎‎‏‏‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎This app will be allowed to send you Notifications, and will be given access to your Camera, Contacts, Files, Microphone, Phone, and SMS‎‏‎‎‏‎"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‏‎‏‎‏‏‎‎‏‏‏‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎‎‏‏‏‏‎‎‎‏‎‎‏‎‎‏‎‎Apps with this permission can access all files on this device‎‏‎‎‏‎"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‏‏‏‏‎‏‎‎‏‎‏‏‏‏‎‎‏‎‎‎‏‎‎‎‎‏‏‎‏‏‎‎‏‎‎‎‏‏‎‎‎‎‏‎‎‏‏‎‎‎‎‏‎Your work policy info‎‏‎‎‏‎"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‏‏‏‎‎‏‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎Settings managed by your IT admin‎‏‎‎‏‎"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‏‎‎‎‎‏‎‏‎‏‎‏‏‎‎‏‏‎‏‏‎‎‎‏‎‎‎Expand and show list‎‏‎‎‏‎"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‏‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‏‏‎‎‎‎‏‎‎‏‎‏‏‎‎‏‏‎‎‎‎Collapse list and hide settings‎‏‎‎‏‎"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎‏‏‏‎‎‎‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‎‏‎‎‎‏‎‏‎List. ‎‏‎‎‏‏‎<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_with_actions_needed_content_description" msgid="2708884606775932657">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‏‎‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‎‎‏‏‎‏‏‎‏‏‏‏‎‎‎‏‎List. ‎‏‎‎‏‏‎<xliff:g id="ENTRY_TITLE">%1$s</xliff:g>‎‏‎‎‏‏‏‎. Actions needed. ‎‏‎‎‏‏‎<xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎‎‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‎List item. ‎‏‎‎‏‏‎<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">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‏‏‎‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‎‎‏‏‎‎‏‎‎‎‎‎‎‎More alerts‎‏‎‎‏‎"</string>
+ <string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‏‏‎‎‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‎‏‎‎‎‎‏‎‏‎Dismissed alerts‎‏‎‎‏‎"</string>
+ <string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‎‎‎‏‏‎‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎‏‏‎‏‏‎‏‏‎‎‏‏‎‏‎‎‏‏‎‎‏‎‎Expand and see one more alert‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‎‎‎‏‏‎‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎‏‏‎‏‏‎‏‏‎‎‏‏‎‏‎‎‏‏‎‎‏‎‎Expand and see # more alerts‎‏‎‎‏‎}}"</string>
+ <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">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‏‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‎‎‏‏‎‎‎‎‏‎‏‏‎‎‏‏‏‎‏‏‎Action complete‎‏‎‎‏‎"</string>
+ <string name="safety_center_qs_status_summary" msgid="5193925895830451177">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‎‏‎‎‏‎‎‎‏‎‎‎‎‎‎‏‎‏‎‏‎‏‏‎‏‎‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‎‏‏‏‏‏‎‏‎‎‏‎Check settings that can add protection to your device‎‏‎‎‏‎"</string>
+ <string name="safety_center_qs_page_landing" msgid="1717368301679228128">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‎‏‏‎‏‏‎‎‏‏‎‏‎‎‏‏‏‎‎‎‎‎‎Security and privacy quick settings‎‏‎‎‏‎"</string>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‎‏‎‎‎‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‎‎‎‎‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎Close‎‏‎‎‏‎"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‎‏‏‎‏‎‎‏‎‎‏‎Expand and show options‎‏‎‎‏‎"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‎‎‎‎‎‎‎‏‏‎‎‏‎‏‎‎‏‏‎‏‏‎‏‏‏‎‏‎‏‎‏‎‎‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‏‏‏‎Collapse‎‏‎‎‏‎"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‎‏‏‎‏‏‏‎‎‏‎‎‏‎‏‎‏‏‎‏‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‎‎‎‏‎‏‏‎‎‎‏‎‎‏‎Switch. ‎‏‎‎‏‏‎<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">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‏‏‏‎‎‎‎‎‏‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‎‏‎‏‏‏‎Toggle‎‏‎‎‏‎"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‏‏‏‎‎‎‏‏‎‏‎‎‎‎‎‎‎‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎‏‎‏‏‎‎‎‏‏‏‎‏‎‎‏‏‎‎‎‎‎Open‎‏‎‎‏‎"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‏‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‎‎Review settings‎‏‎‎‏‎"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‏‎‎‎‏‏‎‎‏‎‏‏‎‏‎‏‏‎‏‏‏‎‎‏‎‏‎‏‎‎‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎Settings‎‏‎‎‏‎"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‎‏‏‎‎‏‏‎‎‎‎‎‎‎‎‏‎‏‏‎‏‏‎‏‎‎‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‎‎‎‏‎‎‎Information‎‏‎‎‏‎"</string>
</resources>
diff --git a/PermissionController/res/values-en-rXC-v34/strings.xml b/PermissionController/res/values-en-rXC-v34/strings.xml
new file mode 100644
index 000000000..525a410b1
--- /dev/null
+++ b/PermissionController/res/values-en-rXC-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‏‏‎‏‏‏‎‏‎‏‏‎‏‎‏‎‎‎‏‎‏‎‏‏‎‎‏‎‎‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‎‎‎Security &amp; privacy‎‏‎‎‏‎"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‏‏‎‎‎‎‏‏‎‎‏‏‎‎‏‎‏‏‎‏‏‎‏‏‎‏‏‏‎‏‎‎‏‏‎‏‎‎‏‎‏‎‎Controls‎‏‎‎‏‎"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‎‏‏‏‎‎‏‏‎‏‏‏‎‏‏‎‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‏‏‏‎Health Connect‎‏‎‎‏‎"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‎‎‏‏‎‏‎‏‏‏‎‎‎‏‏‎‎‎‎‏‏‎‏‎‎‏‎‎‏‎‎‎‏‎‎‏‏‏‏‎‎‎‎Manage app access to health data‎‏‎‎‏‎"</string>
+ <string name="location_settings" msgid="8863940440881290182">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‎‏‏‎‎‎‎‏‎‏‎‏‏‎‏‏‏‏‎‎‎‏‎‏‎‎‎‏‏‏‏‎‎‏‎‏‏‎‏‏‎‏‏‏‏‎‎‎‏‏‎‎Location access‎‏‎‎‏‎"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‏‎‏‎‎‎‏‎‏‎‎‏‏‎‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎For apps and services. If this setting is off, microphone data may still be shared when you call an emergency number‎‏‎‎‏‎"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‏‎‏‎‏‎‎‏‏‎‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‏‏‎For apps and services‎‏‎‎‏‎"</string>
+</resources>
diff --git a/PermissionController/res/values-en-rXC/strings.xml b/PermissionController/res/values-en-rXC/strings.xml
index be407dba2..c712a6f2d 100644
--- a/PermissionController/res/values-en-rXC/strings.xml
+++ b/PermissionController/res/values-en-rXC/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‎‏‎‎‏‎‎‎‎‎‎‏‎‏‏‎‎‎‎‎‏‎‎‎‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‎‎‎‎‎‎Back‎‏‎‎‏‎"</string>
<string name="available" msgid="6007778121920339498">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‏‏‏‎‎‎‎‏‏‏‎‎‏‏‎‏‏‎‎‏‏‎‏‏‏‏‎‎‎‏‎‏‎‏‎‎Available‎‏‎‎‏‎"</string>
<string name="blocked" msgid="9195547604866033708">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‎‎‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‏‏‏‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‏‎‎‎Blocked‎‏‎‎‏‎"</string>
+ <string name="on" msgid="280241003226755921">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‏‏‏‎‎‏‏‏‎‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‎‎‏‏‎‏‎‏‎‎‎‏‏‏‎‎‏‏‎‏‎‏‎‎‎‏‎On‎‏‎‎‏‎"</string>
+ <string name="off" msgid="1438489226422866263">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎‏‏‏‏‎‏‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎‏‎‏‎‏‎‏‏‏‎Off‎‏‎‎‏‎"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‎‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‏‎‎‎‏‏‎‏‎‏‎Uninstall or disable‎‏‎‎‏‎"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‏‏‎‏‎‎‎‎‎‏‏‎‏‏‎‎‎‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‎‏‎‏‏‎‎‎App not found‎‏‎‎‏‎"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‎‎‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‎‏‎‎‎‎Don’t allow‎‏‎‎‏‎"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‏‎‎‎‎‎‏‎‎‏‏‏‎‏‏‎‎‎‏‎Keep “While the app is in use”‎‏‎‎‏‎"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‏‎‎‎‏‎‏‏‎‏‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‎‏‏‎‏‏‏‎‎‎‏‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‎‎Keep “Only this time”‎‏‎‎‏‎"</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‎‎‏‏‏‏‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‎‏‏‎‎‏‏‎‏‎‎‎‎‏‎‏‏‎‎‎‎‏‏‏‎‎‏‏‏‏‎Don’t allow anyway‎‏‎‎‏‎"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‏‎‏‎‎‎‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‏‎‎‏‎Dismiss‎‏‎‎‏‎"</string>
<string name="current_permission_template" msgid="7452035392573329375">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‏‏‏‎‎‏‎‏‎‏‏‎‏‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>‎‏‎‎‏‏‏‎ of ‎‏‎‎‏‏‎<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‏‏‎‏‎‏‏‏‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‎‎‏‎‏‎‎‏‏‏‎‏‏‏‏‏‎‎Screen overlay detected‎‏‎‎‏‎"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‎‏‏‏‎‏‎‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‎‎‎‏‎‎‎‎‎‏‏‎‏‎‏‎‏‏‎‏‎‎‎‏‎‏‎‏‏‎‎To change this permission setting, you first have to turn off the screen overlay from Settings &gt; Apps‎‏‎‎‏‎"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‏‏‎‎‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‎‏‎‎Open settings‎‏‎‎‏‎"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‎‏‏‏‏‎‏‎‏‎‏‏‎‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‏‏‎‎‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‏‏‏‎‎Timeline of when apps used your ‎‏‎‎‏‏‎<xliff:g id="PERMGROUP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ in the past 7 days‎‏‎‎‏‎"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‎‏‎‏‎‎‎‏‏‏‎‏‎‏‎‎‎‎‏‏‎‏‏‎‏‎‎‏‎‏‏‎‎‏‏‎‎‏‎‎‎‎‎‎‎‏‏‎‏‎‎‏‎When this app used your ‎‏‎‎‏‏‎<xliff:g id="PERMGROUP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ permission‎‏‎‎‏‎"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‎‏‎‎‏‎‎‎‏‎‎‏‏‏‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‎‎‏‎‎‏‏‏‎‎‎‎‏‏‎‎‏‎‏‎Learn more‎‏‎‎‏‎"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‏‏‏‏‎‎‏‎‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‎‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‏‏‎‎‎‎‏‎‏‏‎Learn more about ‎‏‎‎‏‏‎<xliff:g id="PERMGROUP">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‏‎‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎Control app access to your ‎‏‎‎‏‏‎<xliff:g id="PERMGROUP">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‏‎‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="ACCESS_TIME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ • ‎‏‎‎‏‏‎<xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‏‏‏‏‎‎‏‏‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‎‏‏‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ • ‎‏‎‎‏‏‎<xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‎‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ • ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎ • ‎‏‎‎‏‏‎<xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‏‏‎‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‏‎1 day‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‏‏‎‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‏‎# days‎‏‎‎‏‎}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‎‎‏‎‏‏‎‏‎‎‏‎‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‏‎‎‎‎‎‎‏‏‎‎‏‏‎‎‎‎1 hour‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‎‎‏‎‏‏‎‏‎‎‏‎‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‏‎‎‎‎‎‎‏‏‎‎‏‏‎‎‎‎# hours‎‏‎‎‏‎}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‏‏‎‎‏‎‏‎‎‏‏‏‏‏‎‎‎‎‏‏‎‎‏‎‎‎‎‏‎‎‎‏‎‎‏‏‎‏‏‎‏‎‎‎‏‎‏‏‎‏‏‏‎1 min‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‏‏‎‎‏‎‏‎‎‏‏‏‏‏‎‎‎‎‏‏‎‎‏‎‎‎‎‏‎‎‎‏‎‎‏‏‎‏‏‎‏‎‎‎‏‎‏‏‎‏‏‏‎# mins‎‏‎‎‏‎}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‎‎‎‎‎‎‎‎‏‏‏‎‏‎‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎1 sec‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‎‎‎‎‎‎‎‎‏‏‏‎‏‎‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎# secs‎‏‎‎‏‎}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‏‎‎‎‎‏‎‎‏‎‏‏‏‎‎‎‎‏‏‎‎‎‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‏‎‏‏‎‏‏‏‎‏‎# day‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‏‎‎‎‎‏‎‎‏‎‏‏‏‎‎‎‎‏‏‎‎‎‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‏‎‏‏‎‏‏‏‎‏‎# days‎‏‎‎‏‎}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎‎‏‎‎‎‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‎‎# hour‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎‎‏‎‎‎‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‎‎# hours‎‏‎‎‏‎}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‎‎‏‏‏‎‏‎‏‎‎‏‎‏‏‎‏‎‏‎‎‏‏‎‏‎‎‏‏‎‏‏‎‎‎‎‎‎‏‎‏‎‏‏‎# min‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‎‎‏‏‏‎‏‎‏‎‎‏‎‏‏‎‏‎‏‎‎‏‏‎‏‎‎‏‏‎‏‏‎‎‎‎‎‎‏‎‏‎‏‏‎# mins‎‏‎‎‏‎}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‏‎‎‎‏‏‏‎‎‏‎‏‎‎‏‏‎‏‏‏‏‎‎‏‎‎‏‎‎‏‎‎‏‎‏‎‎‎‏‏‎# sec‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‏‎‎‎‏‏‏‎‎‏‎‏‎‎‏‏‎‏‏‏‏‎‎‏‎‎‏‎‎‏‎‎‏‎‏‎‎‎‏‏‎# secs‎‏‎‎‏‎}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‏‎‎‏‏‎‏‏‎‏‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‏‏‎‎‎‏‏‏‎‏‎‏‎Any permission‎‏‎‎‏‎"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‏‎‏‏‏‎‏‎‎‎‎‎‎‎‎‏‏‏‎‎‏‎‏‏‎‏‏‎‏‏‏‏‎‏‎‎‎‏‏‏‎‏‎‏‎‎‏‏‎Any time‎‏‎‎‏‎"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‎‎‎‏‏‎‎‎‎‎‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‎‏‎‎‎‏‏‏‎‎‏‎‎‎‏‎Last 7 days‎‏‎‎‏‎"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‎‏‎‎‏‏‏‎‏‎‏‎‏‎‎‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‏‏‎‏‏‎Last 24 hours‎‏‎‎‏‎"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‎‎‏‏‎‏‏‎‎‏‏‏‏‎‏‎‎‎‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‏‎‎‎‎Last 1 hour‎‏‎‎‏‎"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‎‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‎Last 15 minutes‎‏‎‎‏‎"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎‎‏‎‎‎‏‎‏‏‎‎‏‏‎‏‏‏‏‎‏‏‎‏‎‎‏‏‏‎‎‏‎‏‎‎‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‏‎‎Last 1 minute‎‏‎‎‏‎"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‏‎‎‏‎‏‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‎‏‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‏‏‎‏‏‎‎‎‎‏‎Last # day‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‏‎‎‏‎‏‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‎‏‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‏‏‎‏‏‎‎‎‎‏‎Last # days‎‏‎‎‏‎}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‎‎‎‎‏‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‏‎‎‏‏‎‎‏‎‎‎‎‎‎‎‎‎‎‎‏‎‎‏‎‏‎‎‏‎‎Last # hour‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‎‎‎‎‏‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‏‎‎‏‏‎‎‏‎‎‎‎‎‎‎‎‎‎‎‏‎‎‏‎‏‎‎‏‎‎Last # hours‎‏‎‎‏‎}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎‎‎‎‏‏‎‎‎‏‎‏‎‎‏‎‎‎‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‏‏‏‏‏‏‎Last # minute‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎‎‎‎‏‏‎‎‎‏‎‏‎‎‏‎‎‎‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‏‏‏‏‏‏‎Last # minutes‎‏‎‎‏‎}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‎‎‏‎‎‎‏‏‎‎‏‏‏‎‏‎‏‎‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‎‎‎‏‏‏‎‎‏‏‎No permission usages‎‏‎‎‏‎"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‏‎‎‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‏‎‎‎‎‎‎‎‎‏‎‏‎‏‎‏‏‏‎Most recent access at any time‎‏‎‎‏‎"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‏‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‎‎‏‏‏‎‏‏‏‎Most recent access in last 7 days‎‏‎‎‏‎"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‎‎‏‏‎‎‏‎‏‏‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‎‏‎‎‏‎‏‏‏‎‏‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎Permission usage in last 1 hour‎‏‎‎‏‎"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‏‎‎‎‏‏‎‎‏‏‎‏‎‏‎‏‎‎‎‏‏‏‎‎‏‎‏‎‎‏‏‎‏‎‏‏‏‎‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎Permission usage in last 15 minutes‎‏‎‎‏‎"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‎‎‏‎‏‏‎‏‎‎‏‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‎‎‎‏‎‎‎‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‏‏‏‎Permission usage in last 1 minute‎‏‎‎‏‎"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎‎‎‎‎‎‏‎‎‏‏‏‏‏‎‏‎‏‏‎‏‎‎‏‎‏‏‎‏‎‎‏‏‏‏‎‎‎‏‏‎‏‎‏‎‎‎‏‎Not used in past 24 hours‎‏‎‎‏‎"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‏‎‎‎‎‏‏‎‏‏‎‎‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‎‎Not used in past 7 days‎‏‎‎‏‎"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‏‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‎‎‏‏‎Not used in past # day‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‏‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‎‎‏‏‎Not used in past # days‎‏‎‎‏‎}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‎‏‏‏‏‎‏‏‎‏‎‏‏‎‎‏‎‏‏‏‎‎‏‎‏‏‏‏‎‎Not used in past # hour‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‎‏‏‏‏‎‏‏‎‏‎‏‏‎‎‏‎‏‏‏‎‎‏‎‏‏‏‏‎‎Not used in past # hours‎‏‎‎‏‎}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‎‎‎‏‏‏‎‎‎‏‏‎‎‎‎‏‎‎‏‎‎‏‎‎‏‎‏‏‎‎‏‎‏‏‎‏‎‎‎‎‏‏‎‎‎‎‏‏‎‏‎‎Used by 1 app‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‎‎‎‏‏‏‎‎‎‏‏‎‎‎‎‏‎‎‏‎‎‏‎‎‏‎‏‏‎‎‏‎‏‏‎‏‎‎‎‎‏‏‎‎‎‎‏‏‎‏‎‎Used by # apps‎‏‎‎‏‎}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‎‏‎‎‎‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎See all in Dashboard‎‏‎‎‏‎"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‏‏‏‎‏‎‏‎‎‏‏‎‎‎‏‎‏‎‎‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‎‎‎‎‎‏‎‎‏‎‎‏‏‏‏‏‏‎‎Filtered by: ‎‏‎‎‏‏‎<xliff:g id="PERM">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‏‎‏‎‏‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‎‎‎‎‏‏‎‏‏‎‏‎‏‏‎‎‏‎‏‎‎Allow access to media only‎‏‎‎‏‎"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‏‏‏‎‏‎‎‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‎‏‏‏‎‏‎‎‏‎‎‎‏‏‎Allow all the time‎‏‎‎‏‎"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‎‎‏‏‎‏‏‏‏‎‏‎‏‏‎‎‎‏‏‎‎‎‎‏‏‎‏‎‏‏‎‎‎‎‏‎‎‏‎‎‎‎‏‎‏‏‏‎‎‏‏‏‎Allow only while using the app‎‏‎‎‏‎"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‎‏‎‏‎‎‏‎‎‎‏‎‏‏‎‏‏‏‏‏‎‎‎‎‏‎‎‎‏‎‎‎‏‎‎‏‎‏‏‏‏‎‏‎‏‏‏‎‏‏‎‏‏‏‎Always allow all‎‏‎‎‏‎"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‎‎‏‎‏‏‏‏‏‎‎‎‎‎‎‏‏‎‎‏‎‏‎‏‎‏‏‎‏‎‏‎‎‎‎‏‎‎‏‏‎‏‎‎‎‎‎‎‏‏‎‎‏‏‎Ask every time‎‏‎‎‏‎"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‎‏‏‎‎‏‏‎‎‏‎‏‏‏‏‏‎‎‏‎‏‎‏‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‎Don’t allow‎‏‎‎‏‎"</string>
<string name="precise_image_description" msgid="6349638632303619872">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‏‏‎‎‎‏‏‎‏‏‏‎‏‎‏‎‎‎‏‏‎‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‎‎‎Precise location‎‏‎‎‏‎"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‏‎‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="PERM_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎ and ‎‏‎‎‏‏‎<xliff:g id="PERM_1">%2$s</xliff:g>‎‏‎‎‏‏‏‎ permissions will be removed.‎‏‎‎‏‎"</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‎‏‏‎‎‎‎‎‎Permissions that will be removed: ‎‏‎‎‏‏‎<xliff:g id="PERMS">%1$s</xliff:g>‎‏‎‎‏‏‏‎.‎‏‎‎‏‎"</string>
<string name="auto_manage_title" msgid="7693181026874842935">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‏‏‎‏‎‏‎‏‏‎‏‏‎‎‎‏‎‎‎‏‏‏‎‏‏‏‎‏‎‎‏‏‎‎‏‎‏‏‏‏‏‎‎‏‏‎‏‏‏‎Manage permissions automatically‎‏‎‎‏‎"</string>
- <string name="off" msgid="1438489226422866263">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎‏‏‏‏‎‏‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎‏‎‏‎‏‎‏‏‏‎Off‎‏‎‎‏‎"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‎‎‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‏‎‎‏‏‎‏‏‏‏‎‎‎‎‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="PERMISSION_NAME">%s</xliff:g>‎‏‎‎‏‏‏‎ permission removed‎‏‎‎‏‎"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‏‎‏‎‏‏‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎ and ‎‏‎‎‏‏‎<xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g>‎‏‎‎‏‏‏‎ permissions removed‎‏‎‎‏‎"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="PERMISSION_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ and ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%2$s</xliff:g>‎‏‎‎‏‏‏‎ other permissions removed‎‏‎‎‏‎"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‎‏‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‎‎‎‎‏‎‏‏‏‎‎‏‏‏‏‎Unused apps‎‏‎‎‏‎"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‏‏‎‎‎‎‎‏‏‎‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‏‏‎‏‏‎If an app is unused for a few months:‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎• Permissions are removed to protect your data‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎• Notifications are stopped to save battery‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎• Temporary files are removed to free up space‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎To allow permissions and notifications again, open the app.‎‏‎‎‏‎"</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‎‎‎‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‏‎If an app is unused for a few months:‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎• Permissions are removed to protect your data‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎• Temporary files are removed to free up space‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎To allow permissions again, open the app.‎‏‎‎‏‎"</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎‎‎‎‎‏‏‎‏‏‎‏‎‏‎‎‏‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‏‎‎‎‏‏‎Last opened more than ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%s</xliff:g>‎‏‎‎‏‏‏‎ months ago‎‏‎‎‏‎"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‎‎‏‏‎‎‏‏‎‏‏‎‎‎‎‏‎‎‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‎‎‎‎‏‎‎‎If an app is unused for a month:‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎• Permissions are removed to protect your data‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎• Temporary files are removed to free up space‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎To allow permissions again, open the app.‎‏‎‎‏‎"</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‏‏‎‏‎‎‏‏‎‏‏‎‎‏‏‎‎‏‎‎‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‎‏‏‏‏‏‎‎‎‎‎‎Last opened more than # month ago‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‏‏‎‏‎‎‏‏‎‏‏‎‎‏‏‎‎‏‎‎‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‎‏‏‏‏‏‎‎‎‎‎‎Last opened more than # months ago‎‏‎‎‏‎}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‏‏‎‎‎‎‎‏‎‎‎‏‏‎‎‏‎‏‎‏‎‎‎‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‎‏‎‏‎‏‎‎‏‏‎‏‎‎‎‎App last opened on ‎‏‎‎‏‏‎<xliff:g id="DATE">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎‎‏‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‎‏‏‎‏‎‎‏‎‎‎‏‏‏‏‎‎‏‎Last opened ‎‏‎‎‏‏‎<xliff:g id="DATE">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‎‎‏‏‏‏‏‏‎‎‏‎‏‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‎‎‏‏‏‏‎‎‎If you allow management of all files, this app can access, modify, and delete any files in common storage on this device or connected storage devices. The app may access files without asking you.‎‏‎‎‏‎"</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‎‎‎‏‎‎‎‏‏‎‏‏‎‎‎‎‏‎‏‏‎‏‎‎‏‏‏‎‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‏‏‎‏‏‏‎‏‏‎‎Not allowed‎‏‎‎‏‎"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‎‎‎‎‎‏‎‏‎‎‎‎‎‏‎‎‏‏‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‎‎See more apps that can access all files‎‏‎‎‏‎"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‎‏‎‏‏‎‎‏‏‎‏‎‎‏‎‏‎‏‏‎‏‎‎‎‎‏‏‎‎‎‎‎‏‏‏‏‎‎‎‏‏‎‎‎‎‏‎‎‎‎‎‏‎1 day‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‎‏‎‏‏‎‎‏‏‎‏‎‎‏‎‏‎‏‏‎‏‎‎‎‎‏‏‎‎‎‎‎‏‏‏‏‎‎‎‏‏‎‎‎‎‏‎‎‎‎‎‏‎# days‎‏‎‎‏‎}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‏‏‏‎‏‎‏‎‎‎‎‏‏‎‎‎‏‎‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‏‎‎1 hour‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‏‏‏‎‏‎‏‎‎‎‎‏‏‎‎‎‏‎‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‏‎‎# hours‎‏‎‎‏‎}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‏‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‎‎‏‎‎‏‏‏‎‏‎‏‎1 minute‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‏‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‎‎‏‎‎‏‏‏‎‏‎‏‎# minutes‎‏‎‎‏‎}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‏‎‎‏‎‎1 second‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‏‎‎‏‎‎# seconds‎‏‎‎‏‎}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‏‏‎‎‎‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‎‎‏‏‏‎‏‎‏‏‎‎‏‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‏‎‎# hour‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‏‏‎‎‎‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‎‎‏‏‏‎‏‎‏‏‎‎‏‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‏‎‎# hours‎‏‎‎‏‎}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎‏‏‎‎‎‎‏‎‎‎‏‎‏‏‏‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‎‎‎‏‎‎‏‎# minute‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎‏‏‎‎‎‎‏‎‎‎‏‎‏‏‏‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‎‎‎‏‎‎‏‎# minutes‎‏‎‎‏‎}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‏‎‏‏‏‎‏‏‏‏‎‏‎‎‏‏‎‎‏‎‏‎‏‎‏‏‏‏‎‎‎‏‏‏‎‎‏‎‏‎‏‏‏‎‎# second‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‏‎‏‏‏‎‏‏‏‏‎‏‎‎‏‏‎‎‏‎‏‎‏‎‏‏‏‏‎‎‎‏‏‏‎‎‏‎‏‎‏‏‏‎‎# seconds‎‏‎‎‏‎}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‎‎‎‎‏‎‎‎‎‎‎‎‎‏‏‎‎‎‏‏‏‎‎‎‏‎‏‏‏‎‏‎‏‎‏‏‏‏‎‎‎‏‏‏‏‏‎‎‎Permission reminders‎‏‎‎‏‎"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‎‏‎‎‏‏‏‎‎‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‎‎‎‎‏‏‏‏‎‎‏‎1 unused app‎‏‎‎‏‎"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‎‏‏‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎‏‎‎‎‏‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="NUMBER_OF_APPS">%s</xliff:g>‎‏‎‎‏‏‏‎ unused apps‎‏‎‎‏‎"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‎‏‏‎‎‎‏‏‎‏‎‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‎‏‏‏‏‎Some apps haven’t been used in a few months. Tap to review.‎‏‎‎‏‎"</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎‎‏‏‎‏‏‎‏‏‏‎‎‎‎‏‎‎‏‏‎‏‏‎‏‏‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‎# unused app‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎‎‏‏‎‏‏‎‏‏‏‎‎‎‎‏‎‎‏‏‎‏‏‎‏‏‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‎# unused apps‎‏‎‎‏‎}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‎‎‎‏‎‎‎‎‎‎‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‏‎‏‎‏‏‏‏‏‏‎‎Permissions and temporary files have been removed and notifications were stopped. Tap to review.‎‏‎‎‏‎"</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‎‏‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎Review apps with permissions removed‎‏‎‎‏‎"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‏‏‎‏‏‎‏‎‏‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‏‎‎‎‎‎‎‎‏‎‏‏‏‎‏‎‏‎‏‏‏‏‏‏‎‏‏‎‎‎For apps that you haven’t used in a while, permissions and temporary files were removed and notifications were stopped.‎‏‎‎‏‎"</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‎‎‎‎‎‏‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‏‎‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‏‎‎Review apps‎‏‎‎‏‎"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‎‏‎‏‏‏‏‎‏‎‎‏‏‎‏‎‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎‏‎‎‎‎Check recent permissions‎‏‎‎‏‎"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‎‎‏‏‏‎‎‎‏‎‏‎‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎‎‎‏‎‏‎‏‎‏‏‎‎‎‏‏‏‏‎‎‏‎‎‏‏‏‎While driving, you gave ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ access to ‎‏‎‎‏‏‎<xliff:g id="PERMISSION">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‏‎‏‎‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎While driving, you gave ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ access to ‎‏‎‎‏‏‎<xliff:g id="PERMISSION_1">%2$s</xliff:g>‎‏‎‎‏‏‏‎ &amp; ‎‏‎‎‏‏‎<xliff:g id="PERMISSION_2">%3$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‏‏‎‏‏‏‎‎‏‏‏‎‏‏‏‏‎‎‎‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‎‏‎‎‏‎‎‎‏‏‏‏‎‎‏‎Permissions removed to protect your privacy‎‏‎‎‏‎"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‏‎‏‏‎‏‎‏‎‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%s</xliff:g>‎‏‎‎‏‏‏‎ got your location in the background‎‏‎‎‏‎"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‎‎‏‎‏‎‎‏‎‎‎‎‏‎‎‏‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‏‎‏‏‏‏‏‎‎‏‏‏‏‏‎‎‎‏‎‏‎This app can always access your location. Tap to change.‎‏‎‎‏‎"</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‏‎‎‎‎‎‎‏‏‏‏‎‏‎‏‏‎‏‎‎‎‎‏‏‎‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‎‏‏‎Review app with access to your notifications‎‏‎‎‏‎"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‏‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‏‏‎‎‏‏‎‏‏‏‎‏‎‎‏‎‎‎‎‏‎‎‎‏‏‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%s</xliff:g>‎‏‎‎‏‏‏‎ can dismiss, act on, and access content inside your notifications‎‏‎‎‏‎"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‎‎‎‏‎‏‏‏‎‏‏‏‎‏‏‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‎‏‎‏‏‏‎‏‏‏‎‏‏‎‏‎‏‎This app can dismiss, act on, and access content inside your notifications. Some apps require this access to function as intended.‎‏‎‎‏‎"</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‎‏‏‏‏‎‎‎‎‎‎‏‏‎‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎‏‏‎‎‏‎‏‏‎‎‎‎‏‏‏‎‎‎‎‎‏‎‎‏‎Remove access‎‏‎‎‏‎"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‏‏‎‎‏‏‏‏‏‎‏‎‏‏‎‏‏‏‎‏‏‏‎‏‎‎‎‎‎‎‏‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎See more options‎‏‎‎‏‎"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‏‎‎‎‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‏‏‏‎‎‏‏‎‏‎‎‏‏‎‎‎‏‏‎‎‏‏‏‏‎‏‎‎‏‏‎Access removed‎‏‎‎‏‎"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‎‏‎‎‏‎‏‏‎‎‎‏‏‏‎‎Review app with full device access‎‏‎‎‏‎"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‎‎‏‎‎‏‏‏‎‏‎‏‏‎‎‏‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%s</xliff:g>‎‏‎‎‏‏‏‎ can view your screen and perform actions on your device. Accessibility apps need this type of access to function as intended.‎‏‎‎‏‎"</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‏‏‎‏‎‎‎‎‏‎‏‎‏‏‎‏‏‎‎‏‎‏‏‎‎‎‏‏‎‏‎‏‎‎‎‏‎‎‎‎‎‎‎‎‏‎‎‏‏‏‎‎This app can view your screen and perform actions on your device. Accessibility apps need this type of access to function as intended, but check the app and make sure you trust it.‎‏‎‎‏‎"</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‎‏‎‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‏‎‎‎‏‎‏‎‏‎‏‎‏‏‎‎‎‎Remove access‎‏‎‎‏‎"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎‎‏‎‎‏‏‏‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‎‎‎‎‎‎‏‏‏‏‎‏‏‎‎‎‎View apps with full access‎‏‎‎‏‎"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‏‏‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‏‎‎‎‎‏‏‏‎‎‏‎‎‎‎‎‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‏‏‎‎Access removed‎‏‎‎‏‎"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‎‏‏‏‎‎‏‎‎‏‏‏‏‏‎‎‎‎‎‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‏‎‎‏‏‎‎‎‎‏‎‎‎‎‏‏‎‎Android System‎‏‎‎‏‎"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‏‎‎‏‏‎‎‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‎‎‏‎‎‏‏‏‎‎‎‏‏‏‎App permissions removed to protect privacy‎‏‎‎‏‎"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎‏‏‏‏‎‎‏‎‎‎‏‎‎‏‎‏‏‎‎‎‏‎‎‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%s</xliff:g>‎‏‎‎‏‏‏‎ hasn’t been used in a few months. Tap to review.‎‏‎‎‏‎"</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‎‏‎‎‎‏‏‎‏‎‎‎‏‎‏‎‏‏‎‎‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%s</xliff:g>‎‏‎‎‏‏‏‎ and 1 other app haven’t been used in a few months. Tap to review.‎‏‎‎‏‎"</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‏‎‏‎‎‏‎‎‏‎‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎‎‏‏‎‏‎‏‏‎‎‎‏‏‎‏‎‎‎‎‏‏‎‏‏‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions.‎‏‎‎‏‎"</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‎‎‎‏‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‏‏‎‎‏‎‏‏‎‏‎‏‎‎‎‏‎‎‎‎‏‎‏‎‏‏‎‎‏‏‏‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ will be allowed to interact with your notifications and stream your apps to the connected device.‎‏‎‎‏‎"</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‎‎‏‎‎‏‎‎‎‏‎‏‎‎‎‏‎‏‎‏‏‎‎‏‏‏‏‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‎‎‎‏‎‎‏‎This service shares your photos, media, and notifications from your phone to other devices.‎‏‎‎‏‎"</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‎‎Default notes app‎‏‎‎‏‎"</string>
+ <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="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>
@@ -452,6 +475,7 @@
<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_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 more photos and videos on this device?‎‏‎‎‏‎"</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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‎‎‏‎‏‏‏‎‏‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎‏‎‎‎Controlled permissions‎‏‎‎‏‎"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‎‏‎‎‎‏‎‎‏‎‏‏‏‎‎‏‎‎‎‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‏‎Location can be accessed‎‏‎‎‏‎"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‎‎‎‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‏‎‏‎‏‎‏‏‏‏‎Your IT admin is allowing ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%s</xliff:g>‎‏‎‎‏‏‏‎ to access your location‎‏‎‎‏‎"</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>
<string name="other_permissions_label" msgid="8986184335503271992">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎‏‎‏‎‏‏‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‎‎‎‎‎‏‏‏‎‎‎‎Other permissions‎‏‎‎‏‎"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‏‎‏‏‎‏‎‎‎‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‏‏‏‎‎‏‏‎‏‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎Permission used by the system‎‏‎‎‏‎"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‎‎‏‎‏‏‎‎‎‎‎‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‏‏‎‏‎‏‎‎‎‏‏‏‏‎‏‎‏‎‏‎‏‏‏‎‎Permissions used only by the system applications.‎‏‎‎‏‎"</string>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‎‏‎‏‎‎‏‎‏‏‎‏‏‎‎‎‏‏‏‏‎‎‎‏‏‎‏‎‏‏‎‏‎‏‎‏‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎Security &amp; Privacy‎‏‎‎‏‎"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‏‎‎‎‏‎‏‎‏‏‏‎‎‎‏‏‎‏‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎‎‎Scan‎‏‎‎‏‎"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‎‎‎‎‏‏‏‏‎‎‎‎‎‎‎‎‏‎‎‎‏‏‎‎‏‏‏‎‎‎‎‏‎‎‎‎‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‏‎‎Security &amp; 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>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎‎‎‏‎‎‏‏‏‎‎‏‏‎‎‏‏‏‎‏‏‎Review your security and privacy settings any time to add more protection‎‏‎‎‏‎"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‏‎‎‎‏‎‏‎‏‎‎‎‎‎‏‏‎‎‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‏‏‎‏‏‏‎‎‏‏‏‎‏‏‏‏‏‎‎‎Dismiss‎‏‎‎‏‎"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎Cancel‎‏‎‎‏‎"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‎‎‏‎‏‏‎‏‏‏‎‏‏‏‎‏‏‎Settings‎‏‎‎‏‎"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‏‏‎‏‎‏‏‏‎‎‏‏‏‎‏‎‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‎‎‏‎‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‎‎‎‎Security and privacy status. ‎‏‎‎‏‏‎<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">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‏‏‎‏‎‎‎‏‎‎‎‏‏‎‎‎‏‏‏‏‎‏‎‏‏‎‏‏‏‏‎‎‎‏‏‏‏‎‎‏‎‏‎‏‎Security Settings‎‏‎‎‏‎"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‏‎‏‏‏‎‎‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‏‏‏‏‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‎Sensor Permissions‎‏‎‎‏‎"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‎‎‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‏‏‎‏‎‎‏‎Privacy Controls‎‏‎‎‏‎"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‏‎‎‏‏‎‏‎‏‏‎‏‎‏‏‏‏‎‎‎‎‎‎Permissions‎‏‎‎‏‎"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‏‎‎‏‏‎‎‎‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‏‎‎‎‎‎‏‎‏‎‎‏‎‎‎Security &amp; privacy‎‏‎‎‏‎"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‎‏‎‎‏‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‎‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‎‏‎Check status‎‏‎‎‏‎"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‏‏‏‎‎‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎‏‏‎‏‎‎‎‎‎‏‎Your privacy controls‎‏‎‎‏‎"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‎‎‎‏‎‎‎‏‎‏‎‏‏‎‏‎‎More settings‎‏‎‎‏‎"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‎‎‏‎‏‏‏‎‏‎‏‎‎‏‏‏‎‏‏‏‎‏‎‏‎‎‏‏‎‏‎‎‏‏‎‎‎‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎Camera access‎‏‎‎‏‎"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‏‎‏‏‏‏‎‏‎‎‎‏‏‎‎‏‏‎‏‎‎‏‎‎‎‎‎‏‎‎‏‎‎‏‎‏‎‎‎‎‏‎‎‎‏‎‎‏‎‎‎‎Mic access‎‏‎‎‏‎"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‎Permission removed‎‏‎‎‏‎"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‏‎‎‎‏‏‏‎‎‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎See more camera usage‎‏‎‎‏‎"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‏‏‎‎‏‎‏‎‏‎‎‏‎‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‎‎See more microphone usage‎‏‎‎‏‎"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‏‎‏‎‎‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‎‎‏‎‎‎‏‎‏‎‎Remove camera permission‎‏‎‎‏‎"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‎‎‎‎‎‏‏‏‎‎‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‎‎‏‏‏‎‏‏‏‎Remove microphone permission‎‏‎‎‏‎"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‎‎‏‎‎‏‎‏‏‎‎‎‏‏‏‎‏‎‏‏‎‎‎‏‏‎‎‏‎‏‏‏‎‎‎‎‏‎‏‎‎See recent camera usage‎‏‎‎‏‎"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‎‎‏‎‏‏‎‏‏‏‎‏‎‏‎‏‎‎‏‏‏‏‎‎‏‏‎‎‏‎‎‎‏‎‏‎‏‎‏‏‏‏‎‏‏‎‎‎‏‎See recent mic usage‎‏‎‎‏‎"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‎‎‎‏‎‏‎‏‏‏‎‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‎‎‏‎‎‎‏‎‏‏‎‎Remove permission for this app‎‏‎‎‏‎"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‎‎‏‎‏‏‏‎‎‏‏‏‏‏‎‏‎‏‏‏‎‎Remove permission for this app‎‏‎‎‏‎"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‎‎‏‎‎‏‏‏‎‏‎‏‎‏‎‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎‏‏‎‏‏‏‎‎‏‏‎‏‎Manage service‎‏‎‎‏‎"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‏‏‎‏‏‏‎‎‏‎‏‏‏‎‏‏‎‎‎‎‎‏‎‏‎‎‎‎‎‏‏‎‎‎‎‎‏‎‏‏‎‎‎‎‏‏‏‏‏‎‏‎‏‎‎Manage permissions‎‏‎‎‏‎"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎‎‏‏‎‏‎‏‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‏‏‏‏‏‏‎Being used by phone call‎‏‎‎‏‎"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‏‎‏‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‎‏‏‎‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‏‎‎‎‏‎‏‎‏‎Recently used by ‎‏‎‎‏‏‎<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">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‎‎‎‏‏‏‎‎‎‎‎‎‎‎‏‏‏‏‎‏‎‏‏‏‏‎‏‎‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‎‎‏‏‏‎‎‎‏‏‎Being used by ‎‏‎‎‏‏‎<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">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‎‎‎‏‏‎‏‏‎‎‏‎‎‏‏‏‎‏‎‎‎‏‎‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‎Recently used by ‎‏‎‎‏‏‎<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‎‏‎‏‎‎‎‎‏‎‎‎‎‏‎‎‎‎‏‎‎‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‎‎‏‎‎‏‏‎‏‏‎Security &amp; Privacy‎‏‎‎‏‎"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‎‏‎‎‏‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‎‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‎‏‎Check status‎‏‎‎‏‎"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎Confirm‎‏‎‎‏‎"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎‏‎‎‎‏‎‎‎‏‎‎‏‎‎‎‎‏‏‎‏‎‏‎‏‎‎‏‎‏‎‏‎‏‏‎‎‏‎Back‎‏‎‎‏‎"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‏‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‏‏‏‏‏‏‏‏‎Access to other files will also be allowed‎‏‎‎‏‎"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎‏‎‎‏‎‏‎‎‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎This app doesn’t support the latest version of Android. If this app can’t access music and audio files, it also won’t be allowed to access photos and videos.‎‏‎‎‏‎"</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‎‎‏‎‏‎‏‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‏‎‎‎‏‏‏‏‏‎‎‎‎‎This app doesn’t support the latest version of Android. If this app can access photos and videos, it will also be allowed to access music and audio files.‎‏‎‎‏‎"</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‏‎‎‎‎This app doesn’t support the latest version of Android. If this app can’t access music and audio files, it also won’t be allowed to access photos and videos.‎‏‎‎‏‎"</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">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‎‎‎‎‎‎‏‏‎‏‏‎‏‎‎‎‎‏‎‎‎‏‎‎‎‏‏‎Review app with background location access‎‏‎‎‏‎"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎‎‏‏‎‏‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‎‏‎‎‎‏‏‎‏‏‎‎‏‏‎‏‏‏‎‏‎‎This app can always access your location, even when it’s closed.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Some safety and emergency apps require access to your location in the background to work as intended.‎‏‎‎‏‎"</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‎‏‎‎‏‏‏‏‏‏‏‎‎‎‏‏‏‏‎‏‏‎‎‏‎‏‎‎‏‎‏‎‏‏‏‏‎‏‏‏‎‎‏‎‎‏‎‎‏‎‏‎Access changed‎‏‎‎‏‎"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‏‎‎‏‏‎‏‏‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‏‏‏‎‎‎‏‏‎See recent location usage‎‏‎‎‏‎"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‎‎‎‎‎‎‏‏‎‎‎‎‎‏‏‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‏‏‏‏‏‏‎Privacy controls‎‏‎‎‏‎"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‎‏‎‏‏‏‎‏‎‎‏‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‏‏‎‏‎‎‎‏‏‎‎‏‎‏‏‎‏‎‎‎‏‏‏‏‏‎‎‎‏‎‎Camera access‎‏‎‎‏‎"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‎‏‎‎‎‏‏‎‏‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‏‎‏‏‏‎‎‎‏‎‏‎‎‏‎‎Microphone access‎‏‎‎‏‎"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‎‏‎‎‎‏‏‏‎‎‏‏‎For apps and services‎‏‎‎‏‎"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‏‏‏‎‎‎‏‎‏‏‎‏‎‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎‏‎‎‏‎‏‎For apps and services. If this setting is off, microphone data may still be shared when you call an emergency number.‎‏‎‎‏‎"</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‏‏‎‏‏‏‏‎‏‎‎‏‏‏‎See apps and services that have access to location‎‏‎‎‏‎"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‎‏‎‏‏‎‏‎‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‎‎‎‎Show clipboard access‎‏‎‎‏‎"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‎‎‎‎‏‏‎‏‎‎‏‎‎‏‎‎‎‏‏‏‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‏‏‏‎‏‎‏‏‏‏‎Show a message when apps access text, images, or other content you’ve copied‎‏‎‎‏‎"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‏‎‏‏‎‎‎‎‎‎‏‏‎‏‏‏‎‏‏‏‎‏‎‎‎‏‎‏‎‎‎‏‏‏‎‎‏‏‎Show passwords‎‏‎‎‏‎"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‏‎‏‎‎‎‏‎‏‎‎‎‏‎‏‎‏‎‎‏‏‎‎‏‏‎‎‏‎‎‎‏‎‎‏‎‏‎‏‎‏‎‎Display characters briefly as you type‎‏‎‎‏‎"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‏‎‏‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‏‎‎‎‎‎‎‏‏‎‎Data practices may vary based on your app version, use, region, and age. ‎‏‎‎‏‏‎"<annotation id="link">"‎‏‎‎‏‏‏‎More about data sharing‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‏‎‏‏‎‏‏‎‏‎‎‏‎‎‏‎‎‏‏‏‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‏‏‏‎‎‎‏‏‎‎Data practices may vary based on your app version, use, region, and age.‎‏‎‎‏‎"</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‎‏‏‎‎‏‏‏‎‏‎‎‏‎‎‎‎‎‎‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‎‏‎Your location data‎‏‎‎‏‎"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‎‎‏‎‏‏‎‎‎‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‎‏‏‏‏‎‏‎‏‏‎Change this app’s access in ‎‏‎‎‏‏‎"<annotation id="link">"‎‏‎‎‏‏‏‎privacy settings‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‎‏‎‏‏‎‎‎‎‎‏‎‎‎‎‎‏‎‎‏‎‏‏‎‎‎‎‎‎‏‏‎‎‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‏‎‏‎App functionality‎‏‎‎‏‎"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‎‏‏‎‎‎‎‏‎‏‎‏‏‎‎‏‎‎‏‎‎‎‎‏‏‎‏‏‏‎‏‏‎‎‏‏‏‏‏‎‏‎‎‎‎Analytics‎‏‎‎‏‎"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‎‏‏‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‏‏‎‏‎‏‎‎‏‏‎‎Developer communications‎‏‎‎‏‎"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‏‎‎‏‎‏‎‏‎‎‏‏‏‎‎‎‎‏‏‎‎‎‏‎‏‎‏‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‎‎‏‎‏‎‎‏‏‎‎‎Advertising or marketing‎‏‎‎‏‎"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‏‎‎‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‎‏‎‏‎‎‎‎‎‎‎‎‏‎‏‎‎‎‎‎‏‏‏‏‎‎‏‏‏‏‎‏‏‏‏‎‎Fraud prevention, security, and compliance‎‏‎‎‏‎"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‎‎‏‎‏‏‎‏‎‎‎‎‏‏‎‎‎‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎‎Personalization‎‏‎‎‏‎"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‎‏‏‎‎‏‎‏‏‎‎‏‏‏‎‎‏‎‎‏‎‏‎‎‏‎‎‎‏‎‏‎‏‏‎‏‏‏‏‎Account management‎‏‎‎‏‎"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‏‏‎‎‏‏‎‏‏‎‎‏‎‏‏‏‎‎‏‎‏‏‎The developers of these apps provided info about their data sharing practices to an app store. They may update it over time.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Data sharing practices may vary based on your app version, use, region, and age.‎‏‎‎‏‎"</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‎‎‏‎‏‏‎‎‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‎‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‎‏‎Learn about data sharing‎‏‎‎‏‎"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‏‏‏‎Your location data is now shared with third parties‎‏‎‎‏‎"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‎‏‏‎‎‎‏‏‎‏‎‏‏‎‏‏‏‎‏‏‎‎‏‏‏‏‎‎‎‏‏‎‎‏‏‎‏‎‎‏‎‎‎‎‎‎‏‎Your location data is now shared with third parties for advertising or marketing‎‏‎‎‏‎"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‏‎‎‏‏‎‏‎‎‏‏‏‎‎‎‎‏‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‏‎‏‏‏‎‎‏‎‎‏‎‎Updated within the last day‎‏‎‎‏‎}=1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‏‎‎‏‏‎‏‎‎‏‏‏‎‎‎‎‏‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‏‎‏‏‏‎‎‏‎‎‏‎‎Updated within the last day‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‏‎‎‏‏‎‏‎‎‏‏‏‎‎‎‎‏‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‏‎‏‏‏‎‎‏‎‎‏‎‎Updated within # days‎‏‎‎‏‎}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‎‎‎‏‎‎‏‎‏‏‏‎‎‏‏‎‏‏‎‏‏‏‏‎‎‏‎‏‎‏‏‏‏‎‏‎‏‏‏‎No updates at this time‎‏‎‎‏‎"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-es-rUS-v33/strings.xml b/PermissionController/res/values-es-rUS-v33/strings.xml
index 2b4982f31..0205fca80 100644
--- a/PermissionController/res/values-es-rUS-v33/strings.xml
+++ b/PermissionController/res/values-es-rUS-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Esta app podrá enviarte notificaciones y obtendrá acceso tus contactos, cámara, micrófono, teléfono y SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Esta app podrá enviarte notificaciones y obtendrá acceso tus contactos, cámara, archivos, micrófono, teléfono y SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Las apps con este permiso pueden acceder a todos los archivos en este dispositivo"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Información sobre la política de tu trabajo"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Configuración gestionada por tu administrador de TI"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Expandir y mostrar lista"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Contraer lista y ocultar configuración"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Lista. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Lista. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Se requieren acciones. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Elemento de la lista. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Cerrar"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Expandir y mostrar opciones"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Contraer"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Cambiar. <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">"Activar o desactivar"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Abrir"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Revisar la configuración"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Configuración"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Información"</string>
</resources>
diff --git a/PermissionController/res/values-es-rUS-v34/strings.xml b/PermissionController/res/values-es-rUS-v34/strings.xml
new file mode 100644
index 000000000..e180c0b7c
--- /dev/null
+++ b/PermissionController/res/values-es-rUS-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Seguridad y privacidad"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Controles"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Administra el acceso de las apps a Health Connect"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Acceso a la ubicación"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"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="6846532794702613851">"Para apps y servicios"</string>
+</resources>
diff --git a/PermissionController/res/values-es-rUS/strings.xml b/PermissionController/res/values-es-rUS/strings.xml
index 86c0134d7..a59575bd3 100644
--- a/PermissionController/res/values-es-rUS/strings.xml
+++ b/PermissionController/res/values-es-rUS/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Atrás"</string>
<string name="available" msgid="6007778121920339498">"Disponible"</string>
<string name="blocked" msgid="9195547604866033708">"Bloqueado"</string>
+ <string name="on" msgid="280241003226755921">"Activada"</string>
+ <string name="off" msgid="1438489226422866263">"No"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Desinstalar o inhabilitar"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"No se encontró la app"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"No permitir"</string>
@@ -30,11 +32,16 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Mantener en \"Mientras la app está en uso\""</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Mantener \"Solo esta vez\""</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"No permitir igualmente"</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 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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Se detectó una pantalla superpuesta"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Para cambiar esta configuración de permisos, primero debes desactivar la pantalla superpuesta en Configuración &gt; Apps"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Abrir configuración"</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>
@@ -130,21 +134,20 @@
<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>
<string name="manage_permission_summary" msgid="4117555482684114317">"Controla el acceso de las apps a <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 día}many{# días}other{# días}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 hora}many{# horas}other{# horas}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}many{# min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 s}many{# s}other{# s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# día}many{# días}other{# días}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# hora}many{# horas}other{# horas}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# minuto}many{# minutos}other{# minutos}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# segundo}many{# segundos}other{# segundos}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Cualquier permiso"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Cualquier momento"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Últimos 7 días"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Últimas 24 horas"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Última hora"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Últimos 15 minutos"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Último minuto"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Último día (#)}many{Últimos # días}other{Últimos # días}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Última hora (#)}many{Últimas # horas}other{Últimas # horas}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Último minuto (#)}many{Últimos # minutos}other{Últimos # minutos}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Ningún uso de permisos"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Acceso más reciente en cualquier momento"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Acceso más reciente en los últimos 7 días"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Uso de permisos en la última hora"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Uso de permisos en los últimos 15 minutos"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Uso de permisos en el último minuto"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Sin uso en las últimas 24 horas"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"No se usó en los últimos 7 días"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{No se usó en el último día (#)}many{No se usó en los últimos # días}other{No se usó en los últimos # días}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{No se usó en la última hora (#)}many{No se usó en las últimas # horas}other{No se usó en las últimas # horas}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{En uso por parte de 1 app}many{En uso por parte de # apps}other{En uso por parte de # apps}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Ver todo en el panel"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrado por: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Solo permitir acceso al contenido multimedia"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Permitir todo el tiempo"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Permitir solo con la app en uso"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Permitir todo siempre"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Preguntar siempre"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"No permitir"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Ubicación precisa"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Se quitarán los permisos <xliff:g id="PERM_0">%1$s</xliff:g> y <xliff:g id="PERM_1">%2$s</xliff:g>."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Permisos que se quitarán: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Administrar permisos automáticamente"</string>
- <string name="off" msgid="1438489226422866263">"No"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Se quitó el permiso <xliff:g id="PERMISSION_NAME">%s</xliff:g>"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Se quitaron los permisos <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> y <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g>"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Se quitaron <xliff:g id="PERMISSION_NAME">%1$s</xliff:g> y <xliff:g id="NUMBER">%2$s</xliff:g> otros permisos"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Apps que no usas"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Si una app permanece en desuso algunos meses, ocurre lo siguiente:\n\n• Se quitan los permisos para proteger tus datos.\n• Se detienen las notificaciones para ahorrar batería.\n• Se quitan los archivos temporales para liberar espacio.\n\nPara volver a habilitar los permisos y las notificaciones, abre la app."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Si no usas una app durante algunos meses, ocurre lo siguiente:\n\n• Se quitan los permisos para proteger tus datos.\n• Se quitan los archivos temporales para liberar espacio.\n\nPara volver a habilitar los permisos, abre la app."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Se abrió por última vez hace más de <xliff:g id="NUMBER">%s</xliff:g> meses"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Si no usas una app durante un mes, ocurre lo siguiente:\n\n• Se quitan los permisos para proteger tus datos.\n• Se quitan los archivos temporales para liberar espacio.\n\nPara volver a habilitar los permisos, abre la app."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Se abrió por última vez hace más de # mes}many{Se abrió por última vez hace más de # de meses}other{Se abrió por última vez hace más de # meses}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"App abierta por última vez el <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Abierta por última vez el <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Si permites que se administren todos los archivos, esta app podrá consultar, modificar y borrar los archivos que haya en el almacenamiento común de este dispositivo o en los dispositivos de almacenamiento conectados. Podrá acceder a los archivos sin consultarte."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Sin permiso"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Ver más apps 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="3447767892295843282">"{count,plural, =1{1 hora}many{# horas}other{# horas}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minuto}many{# minutos}other{# minutos}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 segundo}many{# segundos}other{# segundos}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# hora}many{# horas}other{# horas}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minuto}many{# minutos}other{# minutos}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# segundo}many{# segundos}other{# segundos}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Recordatorios de permisos"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 app en desuso"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> apps que no usas"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Hace varios meses que no usas algunas apps. Presiona para verlas."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# app en desuso}many{# apps en desuso}other{# apps en desuso}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Se quitaron los permisos y archivos temporales, y se detuvieron las notificaciones. Presiona para revisar estas opciones."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Revisar apps a las que se les quitaron permisos"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Se quitaron los permisos y los archivos temporales, y se detuvieron las notificaciones de las apps que no usaste durante un tiempo."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Revisar apps"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Consulta los permisos recientes"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Mientras conducías, le otorgaste acceso a <xliff:g id="APP">%1$s</xliff:g> a <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Mientras conducías, le otorgaste acceso a <xliff:g id="APP">%1$s</xliff:g> a <xliff:g id="PERMISSION_1">%2$s</xliff:g> y <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Se quitaron los permisos para proteger tu privacidad"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> accedió a tu ubicación en segundo plano"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Esta app puede acceder a tu ubicación en todo momento. Presiona para cambiar el permiso."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Revisa la app con acceso a tus notificaciones"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> puede acceder al contenido de tus notificaciones, realizar acciones con él y descartarlo"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Esta app puede acceder al contenido de tus notificaciones, realizar acciones con él y descartarlo. Algunas apps requieren este tipo de acceso para funcionar de la manera esperada."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Quitar acceso"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Ver más opciones"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Se quitó el acceso"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Revisar app con acceso total a dispositivos"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> puede ver tu pantalla y realizar acciones en tu dispositivo. Las apps de accesibilidad necesitan este tipo de acceso para funcionar de la manera esperada."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Esta app puede ver tu pantalla y realizar acciones en tu dispositivo. Las apps de accesibilidad necesitan este tipo de acceso para funcionar de la manera esperada, pero verifícala y asegúrate de confiar en ella."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Quitar acceso"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Ver apps con acceso total"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Se quitó el acceso"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Sistema Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Permisos de la app eliminados para proteger la privacidad"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> no se usa hace varios meses. Presiona para revisar el cambio."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"Hace varios meses que no se usan <xliff:g id="APP_NAME">%s</xliff:g> y otra app. Presiona para revisar el cambio."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a los permisos de 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 transmitir tus apps al 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_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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Permisos controlados"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Se puede acceder a la ubicación"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Tu administrador de TI permite que <xliff:g id="APP_NAME">%s</xliff:g> acceda a tu ubicación"</string>
+ <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>
@@ -489,24 +513,35 @@
<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>
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Para apps y servicios"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Es posible que se sigan compartiendo los datos del micrófono cuando llames a un número de emergencia."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Cambiar"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Seguridad y privacidad"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Escanear"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Seguridad y privacidad"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Analizar dispositivo"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Descartar"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"¿Quieres descartar esta alerta?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Revisa la configuración de seguridad y privacidad en cualquier momento para tomar medidas adicionales de protección."</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Descartar"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Cancelar"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Configuración"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Estado de la seguridad y la privacidad. <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">"Configuración de seguridad"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Permisos de uso de sensores"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Controles de privacidad"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Permisos"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Seguridad y privacidad"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Comprobar estado"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Tus controles de privacidad"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Más parámetros"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Acceso a la cámara"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Acceso al micrófono"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Se quitó el permiso"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Ver más usos de la cámara"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Ver más usos del micrófono"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Quitar el permiso de la cámara"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Quitar el permiso del micrófono"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Ver uso reciente de la cámara"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Ver uso reciente del micrófono"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Quitar el permiso para esta app"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Quitar el permiso para esta app"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Administrar servicio"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Administrar permisos"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"En uso en una llamada telefónica"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Uso reciente en <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">"En uso en <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">"Uso reciente en <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Seguridad y privacidad"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Comprobar estado"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Confirmar"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Atrás"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"También se permitirá el acceso a otros archivos"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Esta app no es compatible con la versión más reciente de Android. Si esta app no puede acceder a archivos de música ni audio, tampoco podrá acceder a fotos y videos."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Esta app no es compatible con la versión más reciente de Android. Si esta app puede acceder a fotos y videos, también podrá acceder a archivos de música y audio."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Esta app no es compatible con la versión más reciente de Android. Si esta app no puede acceder a archivos de música o audio, tampoco podrá acceder a fotos y videos."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Revisa la app con acceso a la ubicación en segundo plano"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> puede acceder a tu ubicación en todo momento, incluso cuando la app está cerrada"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Revisa la app con acceso a la ubicación en segundo plano"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Esta app puede acceder a tu ubicación en todo momento, incluso cuando está cerrada.\n\nAlgunas apps de seguridad y emergencias requieren acceso a tu ubicación en segundo plano para funcionar correctamente."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Se cambió el acceso"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Ver uso reciente de la ubicación"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Controles de privacidad"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Acceso a la cámara"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Acceso al micrófono"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Para apps y servicios"</string>
+ <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">"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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Las prácticas de datos pueden variar en función de la versión de la app, el uso, la región y la edad. "<annotation id="link">"Más información sobre el uso compartido de datos"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Las prácticas de datos pueden variar según la versión de la app, el uso, la región y la edad."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Tus datos de ubicación"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Puedes cambiar el acceso de esta app en la "<annotation id="link">"configuración de privacidad"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Funciones de la app"</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">"Seguridad, cumplimiento y prevención de fraudes"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalización"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Administración de la cuenta"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Los desarrolladores de estas apps brindaron información sobre sus prácticas de uso compartido de datos a una tienda de aplicaciones. Podrían actualizarla con el tiempo.\n\nLas prácticas de uso compartido de datos pueden variar según la versión de la app, el uso, la región y la edad."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Más información sobre el uso compartido de datos"</string>
+ <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="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>
</resources>
diff --git a/PermissionController/res/values-es-v33/strings.xml b/PermissionController/res/values-es-v33/strings.xml
index ff95c93e1..69b1ce6f5 100644
--- a/PermissionController/res/values-es-v33/strings.xml
+++ b/PermissionController/res/values-es-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Esta aplicación podrá enviarte notificaciones, y tendrá acceso a la cámara, a los contactos, al micrófono, al teléfono y a los SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Esta aplicación podrá enviarte notificaciones, y tendrá acceso a la cámara, a los contactos, a los archivos, al micrófono, al teléfono y a los SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Las aplicaciones que tienen este permiso pueden acceder a todos los archivos de este dispositivo"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Información de tu política de trabajo"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Ajustes gestionados por tu administrador de TI"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Desplegar y mostrar lista"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Contraer lista y ocultar ajustes"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Lista. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Lista. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Acciones necesarias. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>."</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Elemento de lista. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Cerrar"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Desplegar y mostrar opciones"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Contraer"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Interruptor. <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 ajustes"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Configuración"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Información"</string>
</resources>
diff --git a/PermissionController/res/values-es-v34/strings.xml b/PermissionController/res/values-es-v34/strings.xml
new file mode 100644
index 000000000..8253d9b47
--- /dev/null
+++ b/PermissionController/res/values-es-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Seguridad y privacidad"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Controles"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Salud conectada"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Gestiona el acceso de las aplicaciones a tus datos de salud"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Acceso a la ubicación"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Para aplicaciones y servicios. Aunque este ajuste esté desactivado, se pueden compartir datos del micrófono si llamas a un número de emergencia."</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Para aplicaciones y servicios"</string>
+</resources>
diff --git a/PermissionController/res/values-es/strings.xml b/PermissionController/res/values-es/strings.xml
index 39078c634..cb76d3560 100644
--- a/PermissionController/res/values-es/strings.xml
+++ b/PermissionController/res/values-es/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Atrás"</string>
<string name="available" msgid="6007778121920339498">"Disponible"</string>
<string name="blocked" msgid="9195547604866033708">"Bloqueado"</string>
+ <string name="on" msgid="280241003226755921">"Activado"</string>
+ <string name="off" msgid="1438489226422866263">"No"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Desinstalar o inhabilitar"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Aplicación no encontrada"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"No permitir"</string>
@@ -30,11 +32,16 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Mantener \"Mientras la aplicación se esté usando\""</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Mantener \"Solo esta vez\""</string>
<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_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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Superposición de pantalla detectada"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Para cambiar la configuración de este permiso, desactiva la superposición de pantalla en Ajustes &gt; Aplicaciones"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Abrir ajustes"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Cronología de cuándo han usado las aplicaciones el permiso <xliff:g id="PERMGROUP">%1$s</xliff:g> en los últimos 7 días"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Cuándo ha utilizado esta aplicación 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>
<string name="manage_permission_summary" msgid="4117555482684114317">"Controla el acceso de la aplicación a tu <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 día}many{# días}other{# días}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 hora}many{# horas}other{# horas}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}many{# min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 s}many{# s}other{# s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# día}many{# días}other{# días}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# hora}many{# horas}other{# horas}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}many{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}many{# s}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Cualquier permiso"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Cualquier fecha"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Últimos 7 días"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Últimas 24 horas"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Última hora"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Últimos 15 minutos"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Último minuto"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Último día}many{Últimos # días}other{Últimos # días}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Última hora}many{Últimas # horas}other{Últimas # horas}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Último minuto}many{Últimos # minutos}other{Últimos # minutos}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"No se han usado los permisos"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Acceso más reciente en cualquier momento"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Acceso más reciente en los últimos 7 días"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Uso de permisos en la última hora"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Uso de permisos en los últimos 15 minutos"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Uso de permisos en el último minuto"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"No se ha usado en las últimas 24 horas"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"No se ha usado en los últimos 7 días"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{No se ha usado en el último día}many{No se ha usado en los últimos # días}other{No se ha usado en los últimos # días}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{No se ha usado en la última hora}many{No se ha usado en las últimas # horas}other{No se ha usado en las últimas # horas}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Usado por 1 aplicación}many{Usado por # aplicaciones}other{Usado por # aplicaciones}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Ver todo en el panel de control"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrados por: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Permitir acceso solo al contenido multimedia"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Permitir siempre"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Permitir solo mientras se usa la aplicación"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Permitir todo siempre"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Preguntar siempre"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"No permitir"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Ubicación precisa"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Se quitarán los permisos de <xliff:g id="PERM_0">%1$s</xliff:g> y <xliff:g id="PERM_1">%2$s</xliff:g>."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Permisos que se quitarán: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Gestionar permisos automáticamente"</string>
- <string name="off" msgid="1438489226422866263">"No"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Permiso <xliff:g id="PERMISSION_NAME">%s</xliff:g> quitado"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Permisos <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> y <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> quitados"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Permisos <xliff:g id="PERMISSION_NAME">%1$s</xliff:g> y <xliff:g id="NUMBER">%2$s</xliff:g> más quitados"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Aplicaciones no usadas"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Si una aplicación lleva varios meses sin usarse:\n\n• Se le quitan los permisos para proteger tus datos\n• Se detienen sus notificaciones para ahorrar batería\n• Se eliminan sus archivos temporales para liberar espacio\n\nSi quieres volver a dar permisos a la aplicación y activar de nuevo sus notificaciones, ábrela."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Si una aplicación lleva varios meses sin usarse:\n\n• Se le quitan los permisos para proteger tus datos\n• Se eliminan sus archivos temporales para liberar espacio\n\nSi quieres volver a dar permisos a la aplicación, ábrela."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Abiertas por última vez hace más de <xliff:g id="NUMBER">%s</xliff:g> meses"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Si una aplicación lleva un mes sin usarse:\n\n• Se le quitan los permisos para proteger tus datos\n• Se eliminan sus archivos temporales para liberar espacio\n\nSi quieres volver a dar permisos a la aplicación, ábrela."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Abiertas por última vez hace más de # mes}many{Abiertas por última vez hace más de # meses}other{Abiertas por última vez hace más de # meses}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"La aplicación se abrió por última vez el <xliff:g id="DATE">%s</xliff:g>"</string>
<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>
@@ -251,9 +254,9 @@
<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="3447767892295843282">"{count,plural, =1{1 hora}many{# horas}other{# horas}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minuto}many{# minutos}other{# minutos}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 segundo}many{# segundos}other{# segundos}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# hora}many{# horas}other{# horas}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minuto}many{# minutos}other{# minutos}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# segundo}many{# segundos}other{# segundos}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Recordatorios de permisos"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 aplicación no usada"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> aplicaciones no usadas"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Hay varias aplicaciones que llevan meses sin usarse. Toca para revisarlas."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# aplicación no usada}many{# aplicaciones no usadas}other{# aplicaciones no usadas}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Se han retirado permisos, se han eliminado archivos temporales y se han detenido notificaciones. Toca para revisarlo."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Revisar aplicaciones con permisos eliminados"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Se han eliminado los permisos y los archivos temporales, y se han detenido las notificaciones de las aplicaciones que no has usado en un tiempo."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Revisar aplicaciones"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Consultar los permisos recientes"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Durante la conducción, has dado a <xliff:g id="APP">%1$s</xliff:g> acceso a: <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Durante la conducción, has dado a <xliff:g id="APP">%1$s</xliff:g> acceso a: <xliff:g id="PERMISSION_1">%2$s</xliff:g> y <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Permisos quitados para proteger tu privacidad"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> ha obtenido tu ubicación en segundo plano"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Esta aplicación puede acceder siempre a tu ubicación. Toca para cambiarlo."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Revisa la aplicación con acceso a tus notificaciones"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> puede descartar, acceder o interactuar con el contenido de tus notificaciones"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Esta aplicación puede descartar, actuar de acuerdo a o acceder al contenido de tus notificaciones. Algunas aplicaciones requieren este acceso para funcionar según lo previsto."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Quitar acceso"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Ver más opciones"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Acceso retirado"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Revisa la aplicación con acceso total al dispositivo"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> puede ver tu pantalla y llevar a cabo acciones en tu dispositivo. Las aplicaciones de accesibilidad necesitan este tipo de acceso para funcionar según lo previsto."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Esta aplicación puede ver tu pantalla y llevar a cabo acciones en tu dispositivo. Las aplicaciones de accesibilidad necesitan este tipo de acceso para funcionar según lo previsto. No obstante, comprueba la aplicación y asegúrate de que confías en ella."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Quitar acceso"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Ver aplicaciones con acceso total"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Acceso retirado"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Sistema Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Permisos de aplicación quitados para proteger la privacidad"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> no se ha utilizado desde hace algunos meses. Toca para revisarlo."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> y otra aplicación no se han utilizado desde hace algunos meses. Toca para revisarlo."</string>
@@ -328,7 +347,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>
@@ -378,6 +397,10 @@
<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">"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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Permisos controlados"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Se puede acceder a tu ubicación"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Tu administrador de TI permite que <xliff:g id="APP_NAME">%s</xliff:g> acceda a tu ubicación"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Para aplicaciones y servicios"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Aun así, pueden compartirse datos del micrófono cuando llamas a un número de emergencia."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Cambiar"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Seguridad y privacidad"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Analizar"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Seguridad y privacidad"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Analizar dispositivo"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Cerrar"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"¿Cerrar esta alerta?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Revisa tu configuración de seguridad y privacidad en cualquier momento para aumentar tu protección"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Cerrar"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Cancelar"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Ajustes"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Estado de la seguridad y la privacidad. <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">"Ajustes de seguridad"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Permisos del sensor"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Controles de privacidad"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Permisos"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Seguridad y privacidad"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Comprobar estado"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Tus controles de privacidad"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Más ajustes"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Acceso a la cámara"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Acceso al micrófono"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Permiso retirado"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Ver más sobre el uso de la cámara"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Ver más sobre el uso del micrófono"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Retirar el permiso de la cámara"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Retirar el permiso del micrófono"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Ver el uso reciente de la cámara"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Ver el uso reciente del micrófono"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Quitar permiso para esta aplicación"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Quitar permiso para esta aplicación"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Gestionar servicio"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Gestionar permisos"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Se está usando en llamada telefónica"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Uso reciente en <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">"Se está usando en <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">"Uso reciente en <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Seguridad y privacidad"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Comprobar estado"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Confirmar"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Atrás"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"También se permitirá el acceso a otros archivos"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Esta aplicación no es compatible con la última versión de Android. Si esta aplicación no puede acceder a archivos de música y de audio, tampoco podrá acceder a fotos y vídeos."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Esta aplicación no es compatible con la última versión de Android. Si esta aplicación puede acceder a fotos y vídeos, también podrá acceder a archivos de música y de audio."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Esta aplicación no es compatible con la última versión de Android. Si esta aplicación no puede acceder a archivos de música y de audio, tampoco podrá acceder a fotos y vídeos."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Revisa las aplicaciones con acceso a la ubicación en segundo plano"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> puede acceder siempre a tu ubicación, aunque la aplicación esté cerrada"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Revisa las aplicaciones con acceso a la ubicación en segundo plano"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Esta aplicación puede acceder a tu ubicación siempre, aunque esté cerrada.\n\nAlgunas aplicaciones de seguridad y emergencias requieren acceso a tu ubicación en segundo plano para funcionar según lo previsto."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Acceso cambiado"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Ver el uso reciente de la ubicación"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Controles de privacidad"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Acceso a la cámara"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Acceso al micrófono"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Para aplicaciones y servicios"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Para aplicaciones y servicios. Aunque este ajuste esté desactivado, se pueden compartir datos del micrófono si llamas a un número de emergencia."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Consulta las aplicaciones y servicios que tienen acceso a tu ubicación"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Mostrar acceso al portapapeles"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Muestra un mensaje cuando las aplicaciones acceden a texto, imágenes u otro contenido que has copiado"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Mostrar contraseñas"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Muestra los caracteres brevemente mientras escribes"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Las prácticas relacionadas con datos pueden variar según la versión de la aplicación, el modo en que la utilices, la región donde la uses y tu edad. "<annotation id="link">"Más información sobre cómo se comparten los datos"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Las prácticas relacionadas con datos pueden variar según la versión de la aplicación, el modo en que la utilices, el país donde la uses y tu edad."</string>
+ <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_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>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalización"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Gestión de cuentas"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Los desarrolladores de estas aplicaciones han proporcionado información a una tienda de aplicaciones sobre sus formas de compartir datos. Es posible que la actualicen con el tiempo.\n\nLas formas en que se comparten los datos pueden variar en función de la versión de la aplicación, el modo en que la utilices, el país donde la uses y tu edad."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Más información sobre cómo se comparten los datos"</string>
+ <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="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>
</resources>
diff --git a/PermissionController/res/values-et-v33/strings.xml b/PermissionController/res/values-et-v33/strings.xml
index d1b9f047b..e5a6edf90 100644
--- a/PermissionController/res/values-et-v33/strings.xml
+++ b/PermissionController/res/values-et-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Sellel rakendusel lubatakse teile märguandeid saata ja sellele antakse juurdepääs teie kaamerale, kontaktidele, mikrofonile, telefonile ja SMS-idele"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Sellel rakendusel lubatakse teile märguandeid saata ja sellele antakse juurdepääs teie kaamerale, kontaktidele, failidele, mikrofonile, telefonile ja SMS-idele"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Selle loaga rakendused pääsevad selles seadmes juurde kõikidele failidele"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Teie tööeeskirjade teave"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Seadeid haldab teie IT-administraator"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Laienda ja kuva loend"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Ahenda loend ja peida seaded"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Loend. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Loend. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Nõutavad on toimingud. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Loendiüksus. <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">"Rohkem teavitusi"</string>
+ <string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Hoiatused, millest on loobutud"</string>
+ <string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Laiendage ja vaadake veel ühte hoiatust}other{Laiendage ja vaadake veel # hoiatust}}"</string>
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Hoiatus. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
+ <string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Toiming on lõpetatud"</string>
+ <string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Kontrollige seadeid, mis võivad teie seadme kaitset tõhusamaks muuta"</string>
+ <string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Turvalisuse ja privaatsuse kiirseaded"</string>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Sule"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Laienda ja kuva valikud"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Ahenda"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Lüliti. <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">"Lüliti"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Ava"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Vaadake seaded üle"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Seaded"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Teave"</string>
</resources>
diff --git a/PermissionController/res/values-et-v34/strings.xml b/PermissionController/res/values-et-v34/strings.xml
new file mode 100644
index 000000000..4476aecdd
--- /dev/null
+++ b/PermissionController/res/values-et-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Turvalisus ja privaatsus"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Juhtelemendid"</string>
+ <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="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 3b915927a..027b554e0 100644
--- a/PermissionController/res/values-et/strings.xml
+++ b/PermissionController/res/values-et/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Tagasi"</string>
<string name="available" msgid="6007778121920339498">"Saadaval"</string>
<string name="blocked" msgid="9195547604866033708">"Blokeeritud"</string>
+ <string name="on" msgid="280241003226755921">"Sees"</string>
+ <string name="off" msgid="1438489226422866263">"Väljas"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Desinstalli või keela"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Rakendust ei leitud"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Ära luba"</string>
@@ -30,11 +32,16 @@
<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">"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_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>
@@ -107,9 +114,6 @@
<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="screen_overlay_title" msgid="6977038513913222078">"Tuvastati ekraani ülekate"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Selle loaseade muutmiseks peate esmalt välja lülitama ekraani ülekatte menüüs Seaded &gt; Rakendused"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Ava seaded"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Ajaskaala, mis näitab, millal rakendused viimase 7 päeva jooksul teie luba <xliff:g id="PERMGROUP">%1$s</xliff:g> kasutasid."</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Kui see rakendus kasutas teie luba <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Lisateave"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Lisateave lubade grupi <xliff:g id="PERMGROUP">%1$s</xliff:g> kohta"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Hallake rakenduse juurdepääsu grupile <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 päev}other{# päeva}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 tund}other{# tundi}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 s}other{# s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# päev}other{# päeva}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# tund}other{# tundi}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Mis tahes luba"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Mis tahes ajal"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Viimased seitse päeva"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Viimased 24 tundi"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Viimane tund"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Viimased 15 minutit"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Viimane 1 minut"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Viimane päev}other{Viimased # päeva}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Viimane tund}other{Viimased # tundi}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Viimane minut}other{Viimased # minutit}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Lube pole kasutatud"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Hiljutisim juurdepääs mis tahes ajal"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Hiljutisim juurdepääs viimase 7 päeva jooksul"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Lubade kasutus viimase 1 tunni jooksul"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Lubade kasutus viimase 15 minuti jooksul"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Lubade kasutus viimase 1 minuti jooksul"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Pole viimase 24 tunni jooksul kasutatud"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Pole viimase 7 päeva jooksul kasutatud"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Pole viimase # päeva jooksul kasutatud}other{Pole viimase # päeva jooksul kasutatud}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Pole viimase # tunni jooksul kasutatud}other{Pole viimase # tunni jooksul kasutatud}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Kasutab 1 rakendus}other{Kasutavad # rakendust}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Kuva kõik juhtpaneelil"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtreerimisalus: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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 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>
<string name="precise_image_description" msgid="6349638632303619872">"Täpne asukoht"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Load <xliff:g id="PERM_0">%1$s</xliff:g> ja <xliff:g id="PERM_1">%2$s</xliff:g> eemaldatakse."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Eemaldatavad load: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Lubade automaatne haldamine"</string>
- <string name="off" msgid="1438489226422866263">"Väljas"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Luba <xliff:g id="PERMISSION_NAME">%s</xliff:g> eemaldati"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Load <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> ja <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> eemaldati"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> ja veel <xliff:g id="NUMBER">%2$s</xliff:g> luba eemaldati"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Kasutamata rakendused"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Kui rakendust mõne kuu vältel ei kasutata, toimub järgmine.\n\n• Load eemaldatakse, et teie andmeid kaitsta.\n• Märguanded peatatakse, et akut säästa.\n• Ajutised failid eemaldatakse, et ruumi vabastada.\n\nKui soovite uuesti lubasid anda ja märguandeid lubada, avage rakendus."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Kui rakendust mõne kuu vältel ei kasutata, toimub järgmine.\n\n• Load eemaldatakse, et teie andmeid kaitsta.\n• Ajutised failid eemaldatakse, et ruumi vabastada.\n\nKui soovite uuesti lubasid anda, avage rakendus."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Viimati avatud rohkem kui <xliff:g id="NUMBER">%s</xliff:g> kuud tagasi"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Kui rakendust kuu vältel ei kasutata, toimub järgmine.\n\n• Load eemaldatakse, et teie andmeid kaitsta.\n• Ajutised failid eemaldatakse, et ruumi vabastada.\n\nKui soovite uuesti lubasid anda, avage rakendus."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Viimati avatud rohkem kui # kuu tagasi}other{Viimati avatud rohkem kui # kuud tagasi}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Rakendus avati viimati <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Viimati avatud <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Kui lubate kõikide failide haldamise, pääseb see rakendus selle seadme või ühendatud salvestusseadme ühises salvestusruumis juurde mis tahes failidele ning saab neid muuta ja kustutada. Rakendus võib failidele juurde pääseda teilt luba küsimata."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Pole lubatud"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Kuva rohkem rakendusi, mis kõigile failidele juurde pääsevad"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 päev}other{# päeva}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 tund}other{# tundi}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minut}other{# minutit}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 sekund}other{# sekundit}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# tund}other{# tundi}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minut}other{# minutit}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# sekund}other{# sekundit}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Loa meeldetuletused"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 kasutamata rakendus"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> kasutamata rakendust"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Mõningaid rakendusi ei ole mõne kuu jooksul kasutatud. Puudutage ülevaatamiseks."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# kasutamata rakendus}other{# kasutamata rakendust}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Load ja ajutised failid eemaldati ning märguanded peatati. Puudutage ülevaatamiseks."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Vaadake üle rakendused, mille load eemaldati"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Rakenduste puhul, mida te pole mõnda aega kasutanud, eemaldati load ja ajutised failid ning märguanded peatati."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Vaadake rakendused üle"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Vaadake hiljutisi lube"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Andsite sõidu ajal rakendusele <xliff:g id="APP">%1$s</xliff:g> juurdepääsu loale <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Andsite sõidu ajal rakendusele <xliff:g id="APP">%1$s</xliff:g> juurdepääsu lubadele <xliff:g id="PERMISSION_1">%2$s</xliff:g> ja <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Load eemaldati, et teie privaatsust kaitsta"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> sai taustal teie asukoha"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"See rakendus pääseb teie asukohale alati juurde. Puudutage muutmiseks."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Vaadake üle rakendus, millel on juurdepääs märguannetele"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> saab teie märguannetest loobuda, nende alusel toiminguid teha ja nendes olevale sisule juurde pääseda"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"See rakendus saab teie märguannetest loobuda, nende alusel toiminguid teha ja nendes olevale sisule juurde pääseda. Mõni rakendus vajab seda juurdepääsu eesmärgipäraseks toimimiseks."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Eemalda juurdepääs"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Kuva rohkem valikuid"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Juurdepääs eemaldati"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Vaadake üle rakendus, millel on seadmele täielik juurdepääs"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> saab vaadata teie ekraanikuva ja teha teie seadmes toiminguid. Juurdepääsetavuse rakendused vajavad seda tüüpi juurdepääsu eesmärgipäraseks toimimiseks."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"See rakendus saab vaadata teie ekraanikuva ja teha teie seadmes toiminguid. Juurdepääsetavuse rakendused vajavad seda tüüpi juurdepääsu eesmärgipäraseks toimimiseks, kuid kontrollige rakendust ja veenduge, et usaldaksite seda."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Eemalda juurdepääs"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Kuva täieliku juurdepääsuga rakendused"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Juurdepääs eemaldati"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android-süsteem"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Rakenduse load eemaldati privaatsuse kaitsmiseks"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Rakendust <xliff:g id="APP_NAME">%s</xliff:g> ei ole mõne kuu jooksul kasutatud. Puudutage ülevaatamiseks."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"Rakendust <xliff:g id="APP_NAME">%s</xliff:g> ja veel 1 rakendust ei ole mõne kuu jooksul kasutatud. Puudutage ülevaatamiseks."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> saab kasutada teie märguandeid ning hankida teie telefoni, SMS-ide, kontaktide ja kalendri load."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"Rakendusel <xliff:g id="APP_NAME">%1$s</xliff:g> lubatakse kasutada teie märguandeid ja voogesitada teie rakenduste kuva ühendatud seadmesse."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"See teenus jagab teie fotosid, meediat ja märguandeid teie telefonist muudesse seadmetesse."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Märkmete tegemise vaikerakendus"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Hallatud load"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Asukohale pääseb juurde"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"IT-administraator lubab rakendusel <xliff:g id="APP_NAME">%s</xliff:g> teie asukohale juurde pääseda"</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>
<string name="other_permissions_label" msgid="8986184335503271992">"Muud load"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Süsteemi kasutatavad load"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Ainult süsteemirakenduste kasutatavad load."</string>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Rakenduste ja teenuste jaoks"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Mikrofoni andmeid võidakse siiski jagada hädaabinumbrile helistades."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Muuda"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Turvalisus ja privaatsus"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Otsi"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Turvalisus ja privaatsus"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Skanni seadet"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Loobu"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Loobuda sellest hoiatusest?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Saate oma turva- ja privaatsusseaded alati üle vaadata, et kaitset suurendada."</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Loobu"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Tühista"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Seaded"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Turvalisuse ja privaatsuse olek. <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">"Turvaseaded"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Anduri load"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Privaatsuse seaded"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Load"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Turvalisus ja privaatsus"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Oleku kontrollimine"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Teie privaatsuse seaded"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Rohkem seadeid"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Juurdepääs kaamerale"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Juurdepääs mikrofonile"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Luba eemaldati"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Kuva veel kaamera kasutamise teavet"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Kuva veel mikrofoni kasutamise teavet"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Eemalda kaamera luba"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Eemalda mikrofoni luba"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Kaamera hiljutise kasutamise vaatamine"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Mikrofoni hiljutise kasutamise vaatamine"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Eemalda selle rakenduse luba"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Eemalda selle rakenduse luba"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Teenuse haldamine"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Lubade haldamine"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Kasutatakse telefonikõne jaoks"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Kasutas hiljuti rakendus <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">"Kasutab rakendus <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">"Kasutas hiljuti rakendus <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Turvalisus ja privaatsus"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Oleku kontrollimine"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Kinnita"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Tagasi"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Lubatakse ka juurdepääs teistele failidele"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"See rakendus ei toeta Androidi uusimat versiooni. Kui see rakendus ei või muusika- ja helifailidele juurde pääseda, ei või see samuti fotodele ja videotele juurde pääseda."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"See rakendus ei toeta Androidi uusimat versiooni. Kui see rakendus võib fotodele ja videotele juurde pääseda, on sellel samuti lubatud muusika- ja helifailidele juurde pääseda."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"See rakendus ei toeta Androidi uusimat versiooni. Kui see rakendus ei või muusika- ja helifailidele juurde pääseda, ei või see samuti fotodele ja videotele juurde pääseda."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Vaadake üle rakendus, millel on asukohale taustal juurdepääs"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> pääseb alati teie asukohale juurde (isegi kui rakendus on suletud)"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Vaadake üle rakendus, millel on asukohale taustal juurdepääs"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"See rakendus pääseb alati teie asukohale juurde, isegi kui see on suletud.\n\nMõned turva- ja hädaabirakendused vajavad ettenähtud viisil toimimiseks taustal teie asukohale juurdepääsu."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Juurdepääsu muudeti"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Kuva hiljutine asukohaandmete kasutus"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Privaatsuse seaded"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Juurdepääs kaamerale"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Juurdepääs mikrofonile"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Rakenduste ja teenuste jaoks"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"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="2328360561197430695">"Vaadake rakendusi ja teenuseid, mis pääsevad asukohale juurde"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Kuva juurdepääs lõikelauale"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Kui rakendused pääsevad juurde kopeeritud tekstile, piltidele või muule sisule, kuvatakse teade"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Kuva paroolid"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Sisestamisel kuvatakse hetkeks tähemärgid"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Andmetöötlustavad võivad oleneda teie piirkonnast ja vanusest ning rakenduse versioonist ja kasutusest. "<annotation id="link">"Lisateave andmete jagamise kohta"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Andmetöötlustavad võivad oleneda teie piirkonnast ja vanusest ning rakenduse versioonist ja kasutusest."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Teie asukohaandmed"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Selle rakenduse juurdepääsu saate muuta "<annotation id="link">"privaatsusseadetes"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Rakenduse funktsioonid"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analüüs"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Arendaja andmevahetus"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Reklaamimine või turundus"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Pettuste vältimine, turvalisus ja eeskirjade järgimine"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Isikupärastamine"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Kontohaldus"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Nende rakenduste arendajad on esitanud rakenduste poele teavet oma andmejagamistavade kohta. Nad võivad neid aja jooksul muuta.\n\nAndmejagamistavad võivad oleneda teie piirkonnast ja vanusest ning rakenduse versioonist ja kasutusest."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Teave andmete jagamise kohta"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Teie asukohaandmeid jagatakse nüüd kolmandate osapooltega"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Teie asukohaandmeid jagatakse nüüd kolmandate osapooltega reklaami- või turunduseesmärgil"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Värskendatud viimase päeva jooksul}=1{Värskendatud viimase päeva jooksul}other{Värskendatud # päeva jooksul}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Hetkel värskendused puuduvad"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-eu-v33/strings.xml b/PermissionController/res/values-eu-v33/strings.xml
index 1ac19e68e..424feaf4a 100644
--- a/PermissionController/res/values-eu-v33/strings.xml
+++ b/PermissionController/res/values-eu-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Jakinarazpenak bidaltzeko baimena emango zaio aplikazioari, baita zure kamera, kontaktuak, mikrofonoa, telefonoa eta SMSak erabiltzeko baimena ere"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Jakinarazpenak bidaltzeko baimena emango zaio aplikazioari, baita zure kamera, kontaktuak, mikrofonoa, fitxategiak, telefonoa eta SMSak erabiltzeko baimena ere"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Gailuko fitxategi guztiak atzi ditzakete baimen hau duten aplikazioek"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Laneko gidalerroei buruzko informazioa"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"IKT saileko administratzaileak kudeatzen ditu ezarpenak"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Zabaldu eta erakutsi zerrenda"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Tolestu zerrenda eta ezkutatu ezarpenak"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Zerrenda. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Zerrenda. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Zerbait egin behar duzu. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Zerrendako elementua. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Itxi"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Zabaldu eta erakutsi aukerak"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Tolestu"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Etengailua. <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">"Aldatu"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Ireki"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Berrikusi ezarpenak"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Ezarpenak"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Informazioa"</string>
</resources>
diff --git a/PermissionController/res/values-eu-v34/strings.xml b/PermissionController/res/values-eu-v34/strings.xml
new file mode 100644
index 000000000..5b1882738
--- /dev/null
+++ b/PermissionController/res/values-eu-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Segurtasuna eta pribatutasuna"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Kontrolatzeko aukerak"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Kudeatu aplikazioak osasunari buruzko datuak erabiltzeko duen baimena"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Kokapena erabiltzeko baimena"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Aplikazio eta zerbitzuetarako. Ezarpena desaktibatuta badago ere, baliteke mikrofonoaren bidez lortutako datuak partekatzea larrialdietarako zenbaki batera deitzean."</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Aplikazio eta zerbitzuetarako"</string>
+</resources>
diff --git a/PermissionController/res/values-eu/strings.xml b/PermissionController/res/values-eu/strings.xml
index b2ac00ecf..d11ff7fab 100644
--- a/PermissionController/res/values-eu/strings.xml
+++ b/PermissionController/res/values-eu/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Atzera"</string>
<string name="available" msgid="6007778121920339498">"Baimenduta"</string>
<string name="blocked" msgid="9195547604866033708">"Blokeatuta"</string>
+ <string name="on" msgid="280241003226755921">"Aktibatuta"</string>
+ <string name="off" msgid="1438489226422866263">"Desaktibatu"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Desinstalatu edo desgaitu"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Ez da aurkitu aplikazioa"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Ez eman baimenik"</string>
@@ -30,10 +32,15 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Mantendu “Aplikazioa abian denean” aukera"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Mantendu \"Oraingo honetan soilik\""</string>
<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_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>
@@ -107,9 +114,6 @@
<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="screen_overlay_title" msgid="6977038513913222078">"Pantaila-gainjartzea hauteman da"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Baimen-ezarpen hau aldatzeko, pantailaren gainjartzea desaktibatu behar duzu Ezarpenak &gt; Aplikazioak atalean"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Ireki ezarpenak"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Azken zazpi egunetan aplikazioek <xliff:g id="PERMGROUP">%1$s</xliff:g> noiz erabili duten adierazten duen kronologia"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Aplikazioak noiz erabili duen <xliff:g id="PERMGROUP">%1$s</xliff:g> erabiltzeko baimena"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Lortu informazio gehiago"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Lortu <xliff:g id="PERMGROUP">%1$s</xliff:g> baimenari buruzko informazio gehiago"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Kontrolatu <xliff:g id="PERMGROUP">%1$s</xliff:g> erabiltzeko baimenak"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 egun}other{# egun}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 ordu}other{# ordu}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 s}other{# s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# egun}other{# egun}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# ordu}other{# ordu}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Edozein baimen"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Edonoiz"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Azken 7 egunetan"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Azken 24 orduetan"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Azken orduan"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Azken 15 minutuetan"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Azken minutuan"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Azken # egunean}other{Azken # egunetan}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Azken # orduan}other{Azken # orduetan}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Azken # minutuan}other{Azken # minutuetan}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Ez da eskatu baimenik"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Orain arteko azken sarbidea"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Azken zazpi egunetako azken sarbidea"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Azken ordubetean baimenei eman zaien erabilera"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Azken 15 minutuetan baimenei eman zaien erabilera"</string>
<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_24h" msgid="3087783232178611025">"Ez da erabili azken 24 orduetan"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Ez da erabili azken zazpi egunetan"</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{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>
@@ -185,6 +188,7 @@
<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">"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>
<string name="precise_image_description" msgid="6349638632303619872">"Kokapen zehatza"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> eta <xliff:g id="PERM_1">%2$s</xliff:g> baimenak kenduko dira."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Kenduko diren baimenak: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Kudeatu baimenak automatikoki"</string>
- <string name="off" msgid="1438489226422866263">"Desaktibatu"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"<xliff:g id="PERMISSION_NAME">%s</xliff:g> erabiltzeko baimena kendu da"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> eta <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> erabiltzeko baimenak kendu dira"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> eta beste <xliff:g id="NUMBER">%2$s</xliff:g> baimen kendu dira"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Erabiltzen ez diren aplikazioak"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Aplikazio bat zenbait hilabetez erabili ez bada:\n\n• Baimenak kendu egingo dira zure datuak babesteko.\n• Jakinarazpenak gelditu egingo dira bateria aurrezteko.\n• Aldi baterako fitxategiak kendu egingo dira tokia egiteko.\n\nBaimenak eta jakinarazpenak berreskuratu nahi badituzu, ireki aplikazioa."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Aplikazio bat zenbait hilabetez erabili ez bada:\n\n• Baimenak kenduko zaizkio zure datuak babesteko. \n• Aldi baterako fitxategiak kenduko dira tokia egiteko.\n\nBaimenak berreskuratu nahi badituzu, ireki aplikazioa."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Azken irekitze-data: duela <xliff:g id="NUMBER">%s</xliff:g> hilabete baino gehiago"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Aplikazio bat hilabetez erabili ez bada:\n\n• Baimenak kenduko zaizkio zure datuak babesteko. \n• Aldi baterako fitxategiak kenduko dira tokia egiteko.\n\nBaimenak berriro eman nahi badituzu, ireki aplikazioa."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Azken irekitze-data: duela # hilabete baino gehiago}other{Azken irekitze-data: duela # hilabete baino gehiago}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Aplikazioaren azken irekitze-data: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Azken irekitze-data: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Fitxategi guztiak kudeatzeko baimena ematen badiozu, gailu honen memorian eta hari konektatutako biltegiratze-gailuetan dauden fitxategi guztiak atzitu, editatu eta ezabatu ahal izango ditu aplikazioak. Baimenik eskatu gabe atzitu ahalko ditu fitxategiak aplikazioak."</string>
@@ -229,7 +232,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,9 +254,9 @@
<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="3447767892295843282">"{count,plural, =1{1 ordu}other{# ordu}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minutu}other{# minutu}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 segundo}other{# segundo}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# ordu}other{# ordu}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minutu}other{# minutu}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# segundo}other{# segundo}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Baimenen abisuak"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"Erabiltzen ez den 1 aplikazio"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"Erabiltzen ez diren <xliff:g id="NUMBER_OF_APPS">%s</xliff:g> aplikazio"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Aplikazio batzuk ez dira erabili zenbait hilabetez. Sakatu berrikusteko."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{Erabiltzen ez den # aplikazio}other{Erabiltzen ez diren # aplikazio}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Baimenak eta aldi baterako fitxategiak kendu, eta jakinarazpenak gelditu egin dira. Sakatu berrikusteko."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Berrikusi baimenak kenduta dauzkaten aplikazioak"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Aspaldi erabili ez dituzun aplikazioen baimenak eta aldi baterako fitxategiak kendu dira, eta aplikazioekin erlazionatutako jakinarazpenak gelditu dira."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Berrikusi aplikazioak"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Ikusi eman berri dituzun baimenak"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Gidatu bitartean, <xliff:g id="PERMISSION">%2$s</xliff:g> erabiltzeko baimena eman diozu <xliff:g id="APP">%1$s</xliff:g> aplikazioari"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Gidatu bitartean, <xliff:g id="PERMISSION_1">%2$s</xliff:g> eta <xliff:g id="PERMISSION_2">%3$s</xliff:g> erabiltzeko baimena eman diozu <xliff:g id="APP">%1$s</xliff:g> aplikazioari"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Baimenak kendu egin dira zure pribatutasuna babesteko"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> aplikazioak kokapena atzitu du atzeko planoan"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Aplikazio honek beti atzi dezake kokapena. Sakatu aldatzeko."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Berrikusi jakinarazpen guztietarako sarbidea duen aplikazioa"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> aplikazioak jakinarazpenak bazter ditzake, haiekin interakzioan aritu, eta haien edukia atzitu."</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Aplikazioak jakinarazpenak bazter ditzake, haiekin interakzioan aritu, eta haien edukia atzitu. Aplikazio batzuek sarbide mota hori behar dute behar bezala funtzionatzeko."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Kendu sarbidea"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Ikusi aukera gehiago"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Kendu da sarbidea"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Berrikusi gailua erabiltzeko baimen osoa duen aplikazioa"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> aplikazioak pantaila ikus dezake, eta gailuan ekintzak egin. Erabilerraztasun-aplikazioek sarbide mota hori behar dute behar bezala funtzionatzeko."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Aplikazioak pantaila ikus dezake, eta gailuan ekintzak egin. Erabilerraztasun-aplikazioek sarbide mota hori behar dute behar bezala funtzionatzeko, baina ikusi aplikazioa eta ziurtatu hartaz fidatzen zarela."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Kendu sarbidea"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Ikusi sarbide osoa duten aplikazioak"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Kendu da sarbidea"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android sistema"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Aplikazio-baimenak kendu dira pribatutasuna babesteko"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> aplikazioa ez da erabili hainbat hilabetean zehar. Sakatu berrikusteko."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> eta beste aplikazio bat ez dira erabili hainbat hilabetean zehar. Sakatu berrikusteko."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"Honako hauek erabiltzeko baimena izango du <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak: jakinarazpenak, Telefonoa aplikazioa, SMSak, kontaktuak eta egutegia."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"Jakinarazpenekin interakzioan aritzeko eta aplikazioak konektatutako gailura igortzeko baimena izango du <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Zerbitzu honek zure telefonoko argazkiak, multimedia-edukia eta jakinarazpenak partekatzen ditu beste gailuekin."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Oharren aplikazio lehenetsia"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Kontrolatutako baimenak"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Kokapena atzi daiteke"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"IKT saileko administratzaileak zure kokapena erabiltzeko baimena eman dio <xliff:g id="APP_NAME">%s</xliff:g> aplikazioari"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Aplikazio eta zerbitzuetarako"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Agian mikrofonotik lortutako datuak larrialdietarako zenbaki batera deitzen duzunean partekatuko dira."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Aldatu"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Segurtasuna eta pribatutasuna"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Aztertu"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Segurtasuna eta pribatutasuna"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Aztertu gailua"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Baztertu"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Alerta hau baztertu nahi duzu?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Berrikusi segurtasun- eta pribatutasun-ezarpenak edonoiz babesa handitzeko"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Baztertu"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Utzi"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Ezarpenak"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Segurtasun- eta pribatutasun-egoera. <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">"Segurtasun-ezarpenak"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Sentsoreen baimenak"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Pribatutasun-ezarpenak"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Baimenak"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Segurtasuna eta pribatutasuna"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Egiaztatu egoera"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Pribatutasun-ezarpenak"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Ezarpen gehiago"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Kamera erabiltzeko baimena"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Mikrofonoa erabiltzeko baimena"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Kendu egin da baimena"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Ikusi kameraren beste erabilera batzuk"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Ikusi mikrofonoaren beste erabilera batzuk"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Kendu kamera erabiltzeko baimena"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Kendu mikrofonoa erabiltzeko baimena"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Ikusi kameraren azkenaldiko erabilera"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Ikusi mikrofonoaren azkenaldiko erabilera"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Kendu baimena aplikazio honi"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Kendu baimena aplikazio honi"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Kudeatu zerbitzua"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Kudeatu baimenak"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Telefono-deiak darabil"</string>
@@ -517,8 +552,6 @@
<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>) aplikazioak erabili du duela gutxi"</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>) aplikazioak darabil"</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>) aplikazioak erabili du duela gutxi"</string>
- <string name="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Segurtasuna eta pribatutasuna"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Egiaztatu egoera"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Berretsi"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Atzera"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Bestelako fitxategiak erabiltzeko baimena ere emango da"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Aplikazioa ez da Android-en azken bertsioarekin bateragarria. Aplikazioak musika- eta audio-fitxategiak atzitu ezin baditu, ez du izango argazkiak eta bideoak atzitzeko baimenik."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Aplikazioa ez da Android-en azken bertsioarekin bateragarria. Aplikazioak argazkiak eta bideoak atzi baditzake, musika- eta audio-fitxategiak erabiltzeko baimena ere izango du."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Aplikazioa ez da Android-en azken bertsioarekin bateragarria. Aplikazioak musika- eta audio-fitxategiak atzitu ezin baditu, ez du izango argazkiak eta bideoak atzitzeko baimenik."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Berrikusi kokapena atzeko planoan erabiltzeko baimena duen aplikazioa"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> aplikazioak beti atzi dezake kokapena, nahiz eta itxita egon"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Berrikusi kokapena atzeko planoan erabiltzeko baimena duen aplikazioa"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Aplikazioak beti erabil dezake kokapena, nahiz eta itxita egon.\n\nSegurtasun- eta larrialdi-aplikazio batzuek atzeko planoan kokapena erabiltzeko baimena behar dute behar bezala funtzionatzeko."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Aldatu da sarbidea"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Ikusi kokapenaren azken erabilera"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Pribatutasun-ezarpenak"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Kamera erabiltzeko baimena"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Mikrofonoa erabiltzeko baimena"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Aplikazio eta zerbitzuetarako"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Aplikazio eta zerbitzuetarako. Ezarpena desaktibatuta badago, baliteke mikrofonoaren bidez lortutako datuak larrialdietarako zenbaki batera deitzen duzunean partekatzea."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Ikusi kokapena atzi dezaketen aplikazioak eta zerbitzuak"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Erakutsi arbela atzitzen denean"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Erakutsi mezu bat aplikazio batek kopiatu dituzun testuak, irudiak edo edukiak atzitzen dituenean"</string>
+ <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_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_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>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"aplikazioaren funtzioak"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"estatistikak"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"garatzaileen komunikazioak"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"publizitatea edo marketina"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"iruzurra saihestea, segurtasuna eta arau-gordetzea"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"pertsonalizazioa"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"kontuaren kudeaketa"</string>
+ <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="data_sharing_updates_title" msgid="7996933386875213859">"Kokapen-datuak partekatzeko jardunbideen 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="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_desc" msgid="7808764283266234675">"Kokapen-datuak partekatzeko modua aldatu dute aplikazio batzuek"</string>
+ <string name="safety_label_changes_gear_description" msgid="2655887555599138509">"Ezarpenak"</string>
</resources>
diff --git a/PermissionController/res/values-fa-v33/strings.xml b/PermissionController/res/values-fa-v33/strings.xml
index bb474c482..6c7abf7c5 100644
--- a/PermissionController/res/values-fa-v33/strings.xml
+++ b/PermissionController/res/values-fa-v33/strings.xml
@@ -19,4 +19,28 @@
<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_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>
+ <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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"بستن"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"باز کردن و نمایش گزینه‌ها"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"کوچک کردن"</string>
+ <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_gear_label" msgid="5175877094379694098">"تنظیمات"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"اطلاعات"</string>
</resources>
diff --git a/PermissionController/res/values-fa-v34/strings.xml b/PermissionController/res/values-fa-v34/strings.xml
new file mode 100644
index 000000000..de8036122
--- /dev/null
+++ b/PermissionController/res/values-fa-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-fa/strings.xml b/PermissionController/res/values-fa/strings.xml
index fc873cca0..a5c05ca32 100644
--- a/PermissionController/res/values-fa/strings.xml
+++ b/PermissionController/res/values-fa/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,11 +32,16 @@
<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_always_allow_all" msgid="1719900027660252167">"همه موارد همیشه مجازاند"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"هم‌پوشانی صفحه شناسایی شد"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"برای تغییر این تنظیم مجوز، ابتدا باید هم‌پوشانی صفحه را از «تنظیمات &gt; برنامه‌ها» خاموش کنید"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"باز کردن تنظیمات"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"خط زمان مواقعی که برنامه‌ها در ۷ روز گذشته از <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{یک روز}one{# روز}other{# روز}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{یک ساعت}one{# ساعت}other{# ساعت}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{یک دقیقه}one{# دقیقه}other{# دقیقه}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{یک ثانیه}one{# ثانیه}other{# ثانیه}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# روز}one{# روز}other{# روز}}"</string>
+ <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_time" msgid="3802087027301631827">"هر زمانی"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"۷ روز گذشته"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"۲۴ ساعت اخیر"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"۱ ساعت اخیر"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"۱۵ دقیقه اخیر"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"۱ دقیقه اخیر"</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>
+ <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">"آخرین دسترسی در ۷ روز گذشته"</string>
@@ -158,8 +161,8 @@
<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_preference_summary_not_used_24h" msgid="3087783232178611025">"در ۲۴ ساعت گذشته استفاده نشده است"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"در ۷ روز گذشته استفاده نشده است"</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>
<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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"همه موارد همیشه مجازاند"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"هربار پرسیده شود"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"اجازه ندادن"</string>
<string name="precise_image_description" msgid="6349638632303619872">"مکان دقیق"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"اجازه‌های <xliff:g id="PERM_0">%1$s</xliff:g> و <xliff:g id="PERM_1">%2$s</xliff:g> برداشته خواهند شد."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"اجازه‌هایی که برداشته خواهند شد: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"مدیریت خودکار اجازه‌ها"</string>
- <string name="off" msgid="1438489226422866263">"خاموش"</string>
<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_tv_summary" msgid="3685907153054355671">"اگر چند ماه از برنامه‌ای استفاده نشود:\n\n• اجازه‌ها برای محافظت از داده‌های شما برداشته می‌شوند\n• فایل‌های موقت برای آزادسازی فضا برداشته می‌شوند\n\nبرای موافقت کردن دوباره با اجازه‌ها، برنامه را باز کنید."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"آخرین باری که باز شده: بیش‌از <xliff:g id="NUMBER">%s</xliff:g> ماه قبل"</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>
<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,9 +254,9 @@
<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="3447767892295843282">"{count,plural, =1{یک ساعت}one{# ساعت}other{# ساعت}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{یک دقیقه}one{# دقیقه}other{# دقیقه}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{یک ثانیه}one{# ثانیه}other{# ثانیه}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# ساعت}one{# ساعت}other{# ساعت}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# دقیقه}one{# دقیقه}other{# دقیقه}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# ثانیه}one{# ثانیه}other{# ثانیه}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"یادآوری‌های مجوز"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"۱ برنامه استفاده‌نشده"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> برنامه استفاده‌نشده"</string>
@@ -262,6 +265,9 @@
<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>
+ <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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"‏سیستم Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"برای محافظت از حریم خصوصی، اجازه‌های برنامه برداشته شدند"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> طی چند ماه استفاده نشده است. برای مرور، ضربه بزنید."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> و ۱ برنامه دیگر طی چند ماه استفاده نشده‌اند. برای مرور، ضربه بزنید."</string>
@@ -378,12 +397,16 @@
<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_search_keywords" msgid="7710756695666744631">"یادداشت"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"مجوزهای کنترل‌شده"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"می‌توان به مکان دسترسی پیدا کرد"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"سرپرست فناوری اطلاعاتتان به <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"امنیت و حریم خصوصی"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"اسکن"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"اجازه‌های حسگر"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"تنظیمات حریم خصوصی"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"اجازه برداشته شده است"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"دیدن کاربردهای دیگر از دوربین"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"دیدن کاربردهای دیگر میکروفون"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"برداشتن اجازه دوربین"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"برداشتن اجازه میکروفون"</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="manage_service_qs" msgid="7862555549364153805">"مدیریت سرویس"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"مدیریت اجازه‌ها"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"تماس تلفنی درحال استفاده از آن است"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"امنیت و حریم خصوصی"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"بررسی وضعیت"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"ارتباطات توسعه‌دهنده برنامه"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{در روز گذشته به‌روزرسانی شده است}=1{در روز گذشته به‌روزرسانی شده است}one{در # روز به‌روزرسانی شده است}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>
</resources>
diff --git a/PermissionController/res/values-fi-v33/strings.xml b/PermissionController/res/values-fi-v33/strings.xml
index 032a62e80..9b57c6172 100644
--- a/PermissionController/res/values-fi-v33/strings.xml
+++ b/PermissionController/res/values-fi-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Sovellus saa luvan lähettää sinulle ilmoituksia ja pääsyn kameraan, yhteystietoihin, mikrofoniin, puhelimeen ja tekstiviesteihin"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Sovellus saa luvan lähettää sinulle ilmoituksia ja pääsyn kameraan, yhteystietoihin, tiedostoihin, mikrofoniin, puhelimeen ja tekstiviesteihin"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Sovellukset, joilla on tämä lupa, saavat pääsyn kaikkiin laitteen tiedostoihin"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Työkäytäntötietosi"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"IT-järjestelmänvalvojan ylläpitämät asetukset"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Laajenna ja näytä lista"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Tiivistä lista ja piilota asetukset"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Lista. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Lista. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Toimi pian. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Listan osa. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Sulje"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Laajenna ja näytä vaihtoehdot"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Tiivistä"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Vaihda. <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">"Päälle/pois"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Avaa"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Tarkista asetukset"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Asetukset"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Tiedot"</string>
</resources>
diff --git a/PermissionController/res/values-fi-v34/strings.xml b/PermissionController/res/values-fi-v34/strings.xml
new file mode 100644
index 000000000..b2f95dc19
--- /dev/null
+++ b/PermissionController/res/values-fi-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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>
+ <string name="location_settings" msgid="8863940440881290182">"Pääsy sijaintiin"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Sovellukset ja palvelut. Vaikka asetus olisi poissa päältä, mikrofonidataa saatetaan silti jakaa, kun soitat hätänumeroon"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Sovellukset ja palvelut"</string>
+</resources>
diff --git a/PermissionController/res/values-fi/strings.xml b/PermissionController/res/values-fi/strings.xml
index 8ef958bf6..ab3ce18fd 100644
--- a/PermissionController/res/values-fi/strings.xml
+++ b/PermissionController/res/values-fi/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Takaisin"</string>
<string name="available" msgid="6007778121920339498">"Käytettävissä"</string>
<string name="blocked" msgid="9195547604866033708">"Estetty"</string>
+ <string name="on" msgid="280241003226755921">"Päällä"</string>
+ <string name="off" msgid="1438489226422866263">"Pois päältä"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Poista käytöstä tai laitteelta"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Sovellusta ei löydy"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Älä salli"</string>
@@ -30,10 +32,15 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Pidä \"Kun sovellusta käytetään\""</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Säilytä \"Vain tällä kertaa\""</string>
<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_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>
@@ -107,9 +114,6 @@
<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="screen_overlay_title" msgid="6977038513913222078">"Näytön peittokuva havaittiin"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Ennen kuin voit muokata tätä käyttöoikeusasetusta, sinun täytyy poistaa näytön peittokuva käytöstä Asetukset-valikon Sovellukset-kohdasta."</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Avaa asetukset"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Aikajanalta näet, milloin <xliff:g id="PERMGROUP">%1$s</xliff:g> on ollut käytössä eri sovelluksissa 7 viime päivän aikana"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Milloin tämä sovellus käytti seuraavaa lupaa: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Lue lisää"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Lue lisää: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Päätä sovelluksen pääsystä tähän: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 päivä}other{# päivää}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 tunti}other{# tuntia}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 s}other{# s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# päivä}other{# päivää}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# tunti}other{# tuntia}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Kaikki käyttöoikeudet"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Milloin tahansa"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Viimeiset 7 päivää"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Viimeiset 24 tuntia"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Viimeisin tunti"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Viimeiset 15 minuuttia"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Viimeinen minuutti"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Edellinen päivä}other{Viimeiset # päivää}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Viimeisin tunti}other{Viimeiset # tuntia}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Viimeinen minuutti}other{Viimeiset # minuuttia}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Käyttöoikeuksia ei käytetty"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Viimeksi käytetyt koska tahansa"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Viimeksi käytetyt viimeisten 7 päivän ajalta"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Lupien käyttö viimeisen tunnin ajalta"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Lupien käyttö viimeisten 15 min ajalta"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Lupien käyttö viimeisen minuutin ajalta"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Ei käytetty 24 viime tunnin aikana"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Ei käytetty 7 viime päivän aikana"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Ei käytetty viimeisen päivän aikana}other{Ei käytetty # viime päivän aikana}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Ei käytetty viimeisen tunnin aikana}other{Ei käytetty # viime tunnin aikana}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{1 sovelluksen käyttämä}other{# sovelluksen käyttämä}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Näytä kaikki ohjauspaneelissa"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Suodatusperuste: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Salli pääsy vain mediaan"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Salli aina"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Salli vain käytön aikana"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Salli aina kaikki"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Kysy aina"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Älä salli"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Tarkka sijainti"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Seuraavat käyttöluvat poistetaan: <xliff:g id="PERM_0">%1$s</xliff:g> ja <xliff:g id="PERM_1">%2$s</xliff:g>."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Nämä käyttöluvat poistetaan: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Lupien automaattinen ylläpito"</string>
- <string name="off" msgid="1438489226422866263">"Pois päältä"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Lupa poistettu: <xliff:g id="PERMISSION_NAME">%s</xliff:g>"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Luvat poistettu: <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> ja <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> ja <xliff:g id="NUMBER">%2$s</xliff:g> muuta käyttöoikeutta poistettiin"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Käyttämättömät sovellukset"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Jos sovellusta ei käytetä muutamaan kuukauteen:\n\n• Luvat poistetaan datasi suojaamiseksi\n• Ilmoitukset lopetetaan akun säästämiseksi\n• Väliaikaiset tiedostot poistetaan tilan vapauttamiseksi\n\nJos haluat sallia luvat ja ilmoitukset uudelleen, avaa sovellus."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Jos sovellusta ei käytetä muutamaan kuukauteen:\n\n• Luvat poistetaan datasi suojaamiseksi\n• Väliaikaiset tiedostot poistetaan tilan vapauttamiseksi\n\nJos haluat sallia luvat uudelleen, avaa sovellus."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Avattu viimeksi <xliff:g id="NUMBER">%s</xliff:g> kuukautta sitten"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Jos sovellusta ei käytetä kuukauteen:\n\n• Luvat poistetaan datasi suojaamiseksi\n• Väliaikaiset tiedostot poistetaan tilan vapauttamiseksi\n\nJos haluat sallia luvat uudelleen, avaa sovellus."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Avattu viimeksi yli # kuukautta sitten}other{Avattu viimeksi yli # kuukautta sitten}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Sovellus avattiin viimeksi <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Avattu viimeksi <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Jos sallit kaikkien tiedostojen ylläpidon, tämä sovellus voi nähdä, muokata ja poistaa kaikkia tiedostoja tämän laitteen yleisessä tallennustilassa ja yhdistetyillä tallennuslaitteilla. Sovelluksella on pääsy tiedostoihin ilman erillistä lupaasi."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Ei sallittu"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Muut sovellukset, joilla on pääsy kaikkiin tiedostoihin"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 päivä}other{# päivää}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 tunti}other{# tuntia}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minuutti}other{# minuuttia}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 sekunti}other{# sekuntia}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# tunti}other{# tuntia}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minuutti}other{# minuuttia}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# sekunti}other{# sekuntia}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Käyttölupamuistutukset"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 käyttämätön sovellus"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> käyttämätöntä sovellusta"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Joitain sovelluksia ei ole käytetty muutamaan kuukauteen. Tarkista napauttamalla."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# käyttämätön sovellus}other{# käyttämätöntä sovellusta}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Luvat ja väliaikaiset tiedostot on poistettu ja ilmoitukset lopetettu. Tarkista napauttamalla."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Tarkista sovellukset, joiden lupia poistettiin"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Lupia ja väliaikaisia tiedostoja on poistettu ja ilmoituksia estetty sovelluksista, joita et ole käyttänyt viime aikoina."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Tarkista sovellukset"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Tarkista viimeaikaiset luvat"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"<xliff:g id="APP">%1$s</xliff:g> sai ajon aikana tämän luvan: <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"<xliff:g id="APP">%1$s</xliff:g> sai ajon aikana nämä luvat: <xliff:g id="PERMISSION_1">%2$s</xliff:g> ja <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Luvat poistettu tietoturvasyistä"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> sai sijaintitietosi taustalla"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Tämä sovellus voi aina käyttää sijaintiasi. Muuta napauttamalla."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Tarkista sovellus, jolla on pääsy ilmoituksiisi"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> voi hylätä sisältöä sekä reagoida ja päästä sisältöön ilmoitusten sisällä"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Sovellus voi hylätä sisältöä sekä reagoida ja päästä sisältöön ilmoitusten sisällä. Jotkin sovellukset tarvitsevat pääsyn toimiakseen oikein."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Poista pääsyoikeus"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Katso lisää vaihtoehtoja"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Pääsyoikeus on poistettu"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Tarkista sovellus, jolla on laitteiden täydet pääsyoikeudet"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> voi nähdä näyttösi ja suorittaa toimintoja laitteellasi. Saavutettavuussovellukset tarvitsevat tämäntyyppisen pääsyn, jotta ne toimivat oikein."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Sovellus voi nähdä näyttösi ja suorittaa toimintoja laitteellasi. Saavutettavuussovellukset tarvitsevat tämäntyyppisen pääsyn, jotta ne toimivat oikein. Varmista kuitenkin, että voit luottaa sovellukseen."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Poista pääsyoikeus"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Tarkista sovellukset, joilla on täydet pääsyoikeudet"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Pääsyoikeus on poistettu"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android-järjestelmä"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Sovellusten luvat poistettu tietoturvasyistä"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> ei ole ollut käytössä muutamaan kuukauteen. Tarkista napauttamalla."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> ja 1 muu sovellus ei ole ollut käytössä muutamaan kuukauteen. Tarkista napauttamalla."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> saa luvan hallinnoida ilmoituksiasi sekä pääsyn puhelimeesi, tekstiviesteihisi, kontakteihisi ja kalenteriisi."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> saa reagoida ilmoituksiin ja striimata sovelluksiasi yhdistetylle laitteelle."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Tämä palvelu jakaa kuvat, median ja ilmoitukset puhelimeltasi muille laitteille."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Oletusmuistiinpanosovellus"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Automaattisesti myönnetyt käyttöoikeudet"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Pääsy sijaintiin myönnetty"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"<xliff:g id="APP_NAME">%s</xliff:g> on saanut pääsyn sijaintiisi järjestelmänvalvojalta"</string>
+ <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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"Turvallisuus ja yksityisyys"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Etsi"</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>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Tarkista tietoturva- ja yksityisyysasetuksesi milloin tahansa parantaaksesi suojausta"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Ohita"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Peru"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Asetukset"</string>
+ <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="4365989229426201877">"Anturiluvat"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Yksityisyysasetukset"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Luvat"</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>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Pääsy kameraan"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Pääsy mikrofoniin"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Lupa poistettu"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Katso lisää kameran käytöstä"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Katso lisää mikrofonin käytöstä"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Poista kameralupa"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Poista mikrofonilupa"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Katso viimeaikainen kameran käyttö"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Katso viimeaikainen mikrofonin käyttö"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Poista lupa tältä sovellukselta"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Poista lupa tältä sovellukselta"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Ylläpidä palvelua"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Lupien valitseminen"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Puhelu käyttää tätä"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"<xliff:g id="APP_NAME">%1$s</xliff:g> käytti tätä äskettäin (<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> käyttää tätä (<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> käytti tätä äskettäin (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>
- <string name="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Turvallisuus ja yksityisyys"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Tarkista tila"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Vahvista"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Takaisin"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Pääsy muihin tiedostoihin sallitaan myös"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Sovellus ei tue Androidin viimeisintä versiota. Jos sovelluksella ei ole pääsyä musiikki‑ ja audiotiedostoihin, se ei myöskään saa pääsyä valokuviin ja videoihin."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Sovellus ei tue Androidin viimeisintä versiota. Jos sovelluksella on pääsy kuviin ja videoihin, se saa pääsyn myös musiikki- ja audiotiedostoihin."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Sovellus ei tue Androidin viimeisintä versiota. Jos sovelluksella ei ole pääsyä musiikki‑ ja audiotiedostoihin, se ei myöskään saa pääsyä valokuviin ja videoihin."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Tarkista sovellus, jolla on pääsy taustasijaintiin"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"Sovellus (<xliff:g id="APP_NAME">%s</xliff:g>) voi käyttää sijaintiasi aina, vaikka sovellus ei olisi päällä"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Tarkista sovellus, jolla on pääsy taustasijaintiin"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Sovellus voi käyttää sijaintiasi aina, vaikka sovellus ei olisi päällä.\n\nJotkin turva- ja hätäsovellukset edellyttävät pääsyä sijaintiin taustalla toimiakseen oikein."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Pääsyoikeudet muutettu"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Katso viimeisin sijainnin käyttö"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Yksityisyysasetukset"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Pääsy kameraan"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Pääsy mikrofoniin"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Sovellukset ja palvelut"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Sovellukset ja palvelut. Vaikka asetus olisi poissa päältä, mikrofonidataa saatetaan silti jakaa, kun soitat hätänumeroon."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Katso sovellukset ja palvelut, joilla on pääsy sijaintiin"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Näytä ilmoituksia leikepöydän käytöstä"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Näytä viesti, kun sovellukset käyttävät kopioimaasi tekstiä, kuvia tai muuta sisältöä"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Näytä salasanat"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Näytä kirjaimet hetkellisesti, kun kirjoitat"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Datakäytännöt voivat vaihdella sovellusversion, käytön, alueen ja iän mukaan. "<annotation id="link">"Lisätietoa datan jakamisesta"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Datakäytännöt voivat vaihdella sovellusversion, käytön, alueen ja iän mukaan."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Sijaintitietosi"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Muuta tämän sovelluksen pääsyoikeuksia "<annotation id="link">"yksityisyysasetuksissa"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Sovelluksen toiminnot"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analytiikka"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Viestit kehittäjältä"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Mainonta tai markkinointi"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Petosten estäminen, tietoturva ja sääntöjenmukaisuus"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personointi"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Tiliasioiden hoitaminen"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Näiden sovellusten kehittäjät lisäsivät sovelluskauppaan tietoa datan jakokäytännöistä. Tietoja voidaan päivittää ajan mittaan.\n\nDatan jakokäytännöt voivat vaihdella sovellusversion, käytön, alueen ja iän mukaan."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Lue lisää datan jakamisesta"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Sijaintitietojasi jaetaan nyt kolmansille osapuolille"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Sijaintitietojasi jaetaan nyt kolmansille osapuolille mainontaa tai markkinointia varten"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Päivitetty viime päivän aikana}=1{Päivitetty viime päivän aikana}other{Päivitetty # viime päivän aikana}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Ei päivityksiä tällä hetkellä"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-fr-rCA-v33/strings.xml b/PermissionController/res/values-fr-rCA-v33/strings.xml
index 627d5afb8..808e1bcd9 100644
--- a/PermissionController/res/values-fr-rCA-v33/strings.xml
+++ b/PermissionController/res/values-fr-rCA-v33/strings.xml
@@ -19,4 +19,28 @@
<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">"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>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Liste. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Liste. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Actions requises. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Élément de la liste. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Fermer"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Développer et afficher les options"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Réduire"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Commutateur. <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">"Basculer"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Ouvrir"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Vérifier les paramètres"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Réglages"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Information"</string>
</resources>
diff --git a/PermissionController/res/values-fr-rCA-v34/strings.xml b/PermissionController/res/values-fr-rCA-v34/strings.xml
new file mode 100644
index 000000000..347b04cc8
--- /dev/null
+++ b/PermissionController/res/values-fr-rCA-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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é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>
+</resources>
diff --git a/PermissionController/res/values-fr-rCA/strings.xml b/PermissionController/res/values-fr-rCA/strings.xml
index b6145afbf..3e71c4d16 100644
--- a/PermissionController/res/values-fr-rCA/strings.xml
+++ b/PermissionController/res/values-fr-rCA/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Retour"</string>
<string name="available" msgid="6007778121920339498">"Accessible"</string>
<string name="blocked" msgid="9195547604866033708">"Bloqué"</string>
+ <string name="on" msgid="280241003226755921">"Activé"</string>
+ <string name="off" msgid="1438489226422866263">"Désactivé"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Désinstaller ou désactiver"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Application non trouvée"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Ne pas autoriser"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Garder « Pendant l\'utilisation de l\'appli »"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Garder « Uniquement cette fois »"</string>
<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_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 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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"La superposition d\'écran a été détectée"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Pour modifier ce paramètre d\'autorisation, vous devez tout d\'abord désactiver la superposition d\'écran en accédant à Paramètres &gt; Applications."</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Ouvrir les paramètres"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Chronologie des moments où les applications ont utilisé votre <xliff:g id="PERMGROUP">%1$s</xliff:g> au cours des 7 derniers jours"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Lorsque cette application a utilisé votre autorisation de <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"En savoir plus"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"En savoir plus sur <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Contrôlez l\'accès par les applications à votre groupe <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 jour}one{# jour}many{# jours}other{# jours}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 heure}one{# heure}many{# heures}other{# heures}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}one{# min}many{# mins}other{# mins}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 sec}one{# sec}many{# secs}other{# secs}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# jour}one{# jour}many{# de jours}other{# jours}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# heure}one{# heure}many{# d\'heures}other{# heures}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}one{# min}many{# de minutes}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}one{# s}many{# de secondes}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Toute autorisation"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"À tout moment"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Les 7 derniers jours"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Les 24 dernières heures"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"La dernière heure"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Les 15 dernières minutes"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Dernière minute"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Depuis # jour}one{Depuis # jour}many{Depuis # de jours}other{Depuis # jours}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Depuis # heure}one{Depuis # heure}many{Depuis # d\'heures}other{Depuis # heures}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Depuis # minute}one{Depuis # minute}many{Depuis # de minutes}other{Depuis # minutes}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Aucune autoris. d\'utilisation"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"L\'accès le plus récent en tout temps"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Accès le plus récent au cours des 7 derniers jours"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Utilisation des autorisat. dans la dernière heure"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Utilisation des autor. dans les 15 dern. minutes"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Utilisation des autorisat. dans la dernière minute"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Aucune utilisation au cours des dernières 24 heures"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Inutilisée au cours des 7 derniers jours"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Aucune utilisation depuis # jour}one{Aucune utilisation depuis # jour}many{Aucune utilisation depuis # de jours}other{Aucune utilisation depuis # jours}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Aucune utilisation depuis # heure}one{Aucune utilisation depuis # heure}many{Aucune utilisation depuis # d\'heures}other{Aucune utilisation depuis # heures}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Utilisation : 1 application}one{Utilisation : # application}many{Utilisation : # applications}other{Utilisation : # applications}}"</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">"Filtré par : <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Autoriser à accéder aux éléments multimédias seulement"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Toujours autoriser"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Autoriser uniquement lorsque l\'appli est en cours d\'utilisation"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Toujours tout 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>
<string name="precise_image_description" msgid="6349638632303619872">"Position exacte"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Les autorisations <xliff:g id="PERM_0">%1$s</xliff:g> et <xliff:g id="PERM_1">%2$s</xliff:g> seront supprimées."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Autorisations qui seront supprimées : <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Gérer les autorisations automatiquement"</string>
- <string name="off" msgid="1438489226422866263">"Désactivé"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"L\'autorisation <xliff:g id="PERMISSION_NAME">%s</xliff:g> a été supprimée"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Les autorisations <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> et <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> ont été supprimées"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"L\'autorisation <xliff:g id="PERMISSION_NAME">%1$s</xliff:g> et <xliff:g id="NUMBER">%2$s</xliff:g> autres ont été supprimées"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Applications non utilisées"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Si une application n\'est pas utilisée pendant quelques mois :\n\n• les autorisations sont retirées pour protéger vos données;\n• les notifications sont arrêtées pour économiser la pile;\n• les fichiers temporaires sont retirés pour libérer de l\'espace de stockage.\n\nPour permettre d\'accéder de nouveau aux autorisations et aux notifications, ouvrez l\'application."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Si une application n\'est pas utilisée pendant quelques mois :\n\n• Les autorisations sont retirées pour protéger vos données.\n• Les fichiers temporaires sont retirés pour libérer de l\'espace de stockage.\n\nPour réactiver les autorisations, ouvrez l\'application."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Dernière ouverture : il y a plus de <xliff:g id="NUMBER">%s</xliff:g> mois"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Si une application n\'est pas utilisée pendant un mois :\n\n• Les autorisations sont retirées pour protéger vos données.\n• Les fichiers temporaires sont retirés pour libérer de l\'espace de stockage.\n\nPour réactiver les autorisations, ouvrez l\'application."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Dernière ouverture : il y a plus de # mois}one{Dernière ouverture : il y a plus de # mois}many{Dernière ouverture : il y a plus de # de mois}other{Dernière ouverture : il y a plus de # mois}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Dernière ouverture de l\'application le <xliff:g id="DATE">%s</xliff:g>"</string>
<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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Non autorisées"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Afficher d\'autres applis pouvant accéder à tous les fichiers"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 jour}one{# jour}many{# jours}other{# jours}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 heure}one{# heure}many{# heures}other{# heures}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minute}one{# minute}many{# minutes}other{# minutes}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 seconde}one{# seconde}many{# secondes}other{# secondes}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# heure}one{# heure}many{# d\'heures}other{# heures}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minute}one{# minute}many{# de minutes}other{# minutes}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# seconde}one{# seconde}many{# de secondes}other{# secondes}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Rappels d\'autorisation"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 application non utilisée"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> applications non utilisées"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Certaines applications n\'ont pas été utilisées depuis quelques mois. Touchez pour examiner."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# application non utilisée}one{# application non utilisée}many{# applications non utilisées}other{# applications non utilisées}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Les autorisations et les fichiers temporaires ont été retirés, et les notifications ont été arrêtées. Touchez pour examiner."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Voir les applications qui n\'ont plus leurs autorisations"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Pour les applications que vous n\'avez pas utilisées depuis un moment, les autorisations et les fichiers temporaires ont été retirés, et les notifications ont été désactivées."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Voir les applications"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Vérifiez les autorisations récentes"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Pendant la conduite, vous avez donné à <xliff:g id="APP">%1$s</xliff:g> l\'accès à <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Pendant la conduite, vous avez donné à <xliff:g id="APP">%1$s</xliff:g> l\'accès à <xliff:g id="PERMISSION_1">%2$s</xliff:g> et à <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Les autorisations ont été supprimées afin de protéger votre confidentialité"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"L\'application <xliff:g id="APP_NAME">%s</xliff:g> a accédé à votre position en arrière-plan"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Cette application peut toujours accéder à votre position. Touchez l\'écran pour modifier cela."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Voir l\'application ayant accès à vos notifications"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> peut ignorer et gérer le contenu de vos notifications de même qu\'y accéder"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Cette application peut ignorer le contenu de vos notifications, y accéder et le gérer. Certaines applications ont besoin de cet accès pour fonctionner correctement."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Retirer l\'accès"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Afficher d\'autres options"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Accès retiré"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Vérifier l\'application ayant un accès complet à l\'appareil"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> peut voir votre écran et effectuer des actions sur votre appareil. Les applications d\'accessibilité ont besoin de ce type d\'accès pour fonctionner correctement."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Cette application peut voir votre écran et effectuer des actions sur votre appareil. Les applications d\'accessibilité ont besoin de ce type d\'accès pour fonctionner correctement, mais vérifiez d\'abord l\'application et assurez-vous qu\'elle est fiable."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Retirer l\'accès"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Voir les applications ayant un accès complet"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Accès retiré"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Système Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Autorisations supprimées pour protéger votre confidentialité"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"L\'application <xliff:g id="APP_NAME">%s</xliff:g> n\'a pas été utilisée depuis plusieurs mois. Touchez pour examiner."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> et une autre application n\'ont pas été utilisées depuis plusieurs mois. Touchez pour examiner."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder aux autorisations pour votre téléphone, vos messages texte, vos contacts et votre agenda."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et de diffuser vos applications à l\'appareil connecté."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Ce service partage vos photos, vos contenus multimédias et vos notifications de votre téléphone vers d\'autres appareils."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Appli prise de notes par défaut"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Autorisations contrôlées"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"L\'accès à la position est autorisé"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Votre administrateur informatique autorise <xliff:g id="APP_NAME">%s</xliff:g> à accéder à votre position"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Pour les applications et les services"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Il est possible que les données du microphone soient partagées lorsque vous appelez un numéro d\'urgence."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Modifier"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Sécurité et confidentialité"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Analyser"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Sécurité et confidentialité"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Analyser l\'appareil"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Fermer"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Ignorer cette alerte?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Passez en revue les paramètres de sécurité et de confidentialité à tout moment pour ajouter une protection"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Fermer"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Annuler"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Paramètres"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"État de la sécurité et de la confidentialité. <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">"Paramètres de sécurité"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Autorisations du capteur"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Paramètres de confidentialité"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Autorisations"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Sécurité et confidentialité"</string>
+ <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 à 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="7943349178368641820">"Voir les données d\'utilisation de l\'appareil photo"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Voir les données d\'utilisation du microphone"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Retirer l\'autorisation de l\'appareil photo"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Retirer l\'autorisation du microphone"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Consulter les utilisations récentes de l\'appareil photo"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Consulter les utilisations récentes du microphone"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Retirer l\'autorisation de cette application"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Retirer l\'autorisation de cette application"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Gérer le service"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Gérer les autorisations"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"En cours d\'utilisation par un appel téléphonique"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Récemment utilisé par <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">"En cours d\'utilisation par <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">"Récemment utilisé par <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Sécurité et confidentialité"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Vérification de l\'état"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Confirmer"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Retour"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"L\'accès à d\'autres fichiers sera également autorisé"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Cette application ne prend pas en charge la dernière version d\'Android. Si cette application ne peut pas accéder aux fichiers musicaux ni audio, elle ne sera pas non plus autorisée à accéder aux photos ni aux vidéos."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Cette application ne prend pas en charge la dernière version d\'Android. Si cette application peut accéder aux photos et aux vidéos, elle sera également autorisée à accéder aux fichiers musicaux et audio."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Cette application ne prend pas en charge la dernière version d\'Android. Si cette application ne peut pas accéder aux fichiers musicaux ni audio, elle ne sera pas non plus autorisée à accéder aux photos ni aux vidéos."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Voir les applications ayant accès aux données de 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 position, même quand l\'application est fermée"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Voir les applications ayant accès aux données de localisation en arrière-plan"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Cette application peut toujours accéder à votre position, même lorsqu\'elle est fermée.\n\nCertaines applications de sécurité et d\'urgence requièrent l\'accès à votre position en arrière-plan pour fonctionner correctement."</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 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 à 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">"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">"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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Les pratiques relatives aux données peuvent varier en fonction de la version de votre application, de son utilisation, de votre région et de 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">"Les pratiques relatives aux données peuvent varier en fonction de la version de votre application, de son utilisation, de votre région et de 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 les autorisations d\'accès de cette application dans les "<annotation id="link">"paramètres de confidentialité"</annotation></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 analyses"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"les communications du développeur;"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"les annonces ou le marketing;"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"la prévention de la fraude, la sécurité et la conformité;"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"La personnalisation"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"la 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 application indique qu\'elle peut partager vos données de localisation avec des tiers"</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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Les développeurs de ces applications ont fourni des renseignements sur leurs pratiques de partage des données à une boutique d\'applications. Ils peuvent les mettre à jour au fil du temps.\n\nLes pratiques de partage des données peuvent varier en fonction de la version de votre application, de son utilisation, de votre région et de votre âge."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"En savoir plus sur le partage des données"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Vos données de localisation sont maintenant partagées avec des tiers"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Vos données de localisation sont maintenant partagées avec des tiers à des fins d\'annonces ou de marketing"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Mises à jour au cours du dernier jour}=1{Mises à jour au cours du dernier jour}one{Mises à jour il y a # jour}many{Mises à jour au cours des # de derniers jours}other{Mises à 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 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>
</resources>
diff --git a/PermissionController/res/values-fr-v33/strings.xml b/PermissionController/res/values-fr-v33/strings.xml
index 6010bb621..24bd671a8 100644
--- a/PermissionController/res/values-fr-v33/strings.xml
+++ b/PermissionController/res/values-fr-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Cette appli sera autorisée à vous envoyer des notifications, et elle aura accès à votre appareil photo, vos contacts, votre micro, votre téléphone et vos SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Cette appli sera autorisée à vous envoyer des notifications, et elle aura accès à votre appareil photo, vos contacts, vos fichiers, votre micro, votre téléphone et vos SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Les applis ayant cette autorisation peuvent accéder à tous les fichiers sur cet appareil"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Infos sur vos règles professionnelles"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Paramètres gérés par votre administrateur informatique"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Développer la liste et l\'afficher"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Réduire la liste et masquer les paramètres"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Liste. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Liste. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Actions requises. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>."</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Élément de liste. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Fermer"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Développer et afficher les options"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Réduire"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Contacteur. <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">"Activer/Désactiver"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Ouvrir"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Vérifier les para­mètres"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Paramètres"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Informations"</string>
</resources>
diff --git a/PermissionController/res/values-fr-v34/strings.xml b/PermissionController/res/values-fr-v34/strings.xml
new file mode 100644
index 000000000..f7f584b75
--- /dev/null
+++ b/PermissionController/res/values-fr-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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">"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="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 b056fa984..6af03ec38 100644
--- a/PermissionController/res/values-fr/strings.xml
+++ b/PermissionController/res/values-fr/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Retour"</string>
<string name="available" msgid="6007778121920339498">"Disponible"</string>
<string name="blocked" msgid="9195547604866033708">"Bloqué"</string>
+ <string name="on" msgid="280241003226755921">"Activé"</string>
+ <string name="off" msgid="1438489226422866263">"Désactivé"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Désinstaller ou désactiver"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Application non trouvée"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Ne pas autoriser"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Garder \"Seulement quand l\'appli est en cours d\'utilisation\""</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Conserver le paramètre \"Uniquement cette fois-ci\""</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Ne pas autoriser"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Superposition d\'écran détectée"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Pour modifier ce paramètre d\'autorisation, vous devez d\'abord désactiver la superposition d\'écran sous Paramètres &gt; Applications"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Ouvrir les paramètres"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Moments où les applis ont utilisé votre <xliff:g id="PERMGROUP">%1$s</xliff:g> au cours des 7 derniers jours"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Quand cette appli a utilisé votre autorisation <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"En savoir plus"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"En savoir plus sur <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Contrôler l\'accès des applis à votre <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 jour}one{# jour}many{# jours}other{# jours}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 heure}one{# heure}many{# heures}other{# heures}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}one{# min}many{# min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 s}one{# s}many{# s}other{# s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# jour}one{# jour}many{# jours}other{# jours}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# heure}one{# heure}many{# heures}other{# heures}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}one{# min}many{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}one{# s}many{# s}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Toute autorisation"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Indifférent"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"7 derniers jours"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Dernières 24 heures"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Dernière heure"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"15 dernières minutes"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Dernière minute"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Dernier jour (#)}one{Dernier jour (#)}many{# derniers jours}other{# derniers jours}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Dernière heure (#)}one{Dernière heure (#)}many{# dernières heures}other{# dernières heures}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Dernière minute (#)}one{Dernière minute (#)}many{# dernières minutes}other{# dernières minutes}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Aucune autorisation utilisée"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Tous les accès les plus récents"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Accès les plus récents (7 derniers jours)"</string>
@@ -158,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_24h" msgid="3087783232178611025">"Aucune utilisation au cours des dernières 24 heures"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Aucune utilisation au cours des 7 derniers jours"</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>
@@ -185,6 +188,7 @@
<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 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>
<string name="precise_image_description" msgid="6349638632303619872">"Position exacte"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Les autorisations <xliff:g id="PERM_0">%1$s</xliff:g> et <xliff:g id="PERM_1">%2$s</xliff:g> seront supprimées."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Autorisations qui seront supprimées : <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Gérer les autorisations automatiquement"</string>
- <string name="off" msgid="1438489226422866263">"Désactivé"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"L\'autorisation \"<xliff:g id="PERMISSION_NAME">%s</xliff:g>\" a été révoquée"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Les autorisations \"<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g>\" et \"<xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g>\" ont été révoquées"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"L\'autorisation \"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g>\" et <xliff:g id="NUMBER">%2$s</xliff:g> autres ont été révoquées"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Applis inutilisées"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Si vous n\'utilisez pas une appli pendant quelques mois :\n\n• Les autorisations sont supprimées pour protéger vos données.\n• Les notifications sont désactivées pour économiser la batterie.\n• Les fichiers temporaires sont supprimés pour libérer de l\'espace.\n\nPour réactiver les autorisations et les notifications, ouvrez l\'application."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Si vous n\'utilisez pas une appli pendant quelques mois :\n\n• les autorisations sont supprimées pour protéger vos données ;\n• les fichiers temporaires sont supprimés pour libérer de l\'espace.\n\nPour réactiver les autorisations, ouvrez l\'appli."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Ouvertes pour la dernière fois il y a plus de <xliff:g id="NUMBER">%s</xliff:g> mois"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Si vous n\'utilisez pas une appli pendant un mois :\n\n• Les autorisations sont supprimées pour protéger vos données\n• Les fichiers temporaires sont supprimés pour libérer de l\'espace\n\nPour réactiver les autorisations, ouvrez l\'appli."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Ouvertes pour la dernière fois il y a plus de # mois}one{Ouvertes pour la dernière fois il y a plus de # mois}many{Ouvertes pour la dernière fois il y a plus de # mois}other{Ouvertes pour la dernière fois il y a plus de # mois}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Dernière ouverture de l\'application le <xliff:g id="DATE">%s</xliff:g>"</string>
<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 l\'autorisez à gérer tous les fichiers, cette application pourra y accéder, les modifier et les supprimer, sur cet appareil et sur les périphériques de stockage connectés. L\'application pourra accéder aux fichiers sans vous le demander."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Non autorisé"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Voir plus d\'applis pouvant accéder à tous les fichiers"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 jour}one{# jour}many{# jours}other{# jours}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 heure}one{# heure}many{# heures}other{# heures}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minute}one{# minute}many{# minutes}other{# minutes}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 seconde}one{# seconde}many{# secondes}other{# secondes}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# heure}one{# heure}many{# heures}other{# heures}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minute}one{# minute}many{# minutes}other{# minutes}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# seconde}one{# seconde}many{# secondes}other{# secondes}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Rappels relatifs aux autorisations"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 application inutilisée"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> applications inutilisées"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Certaines applications n\'ont pas été utilisées depuis plusieurs mois. Appuyez ici pour en savoir plus."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# appli inutilisée}one{# appli inutilisée}many{# applis inutilisées}other{# applis inutilisées}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Les fichiers temporaires et les autorisations ont été supprimés, et les notifications ont été désactivées. Appuyez ici pour en savoir plus."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Examiner les applis avec autorisations supprimées"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Les autorisations et les fichiers temporaires des applis que vous n\'avez pas utilisées depuis un certain temps ont été supprimés, et leurs notifications ont été arrêtées."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Examiner les applis"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Vérifier les autorisations récentes"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"En conduisant, vous avez autorisé <xliff:g id="APP">%1$s</xliff:g> à accéder à : <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"En conduisant, vous avez autorisé <xliff:g id="APP">%1$s</xliff:g> à accéder à : <xliff:g id="PERMISSION_1">%2$s</xliff:g> et <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Les autorisations ont été supprimées pour protéger votre vie privée"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> a accès à votre position en arrière-plan"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Cette application peut accéder en permanence à votre position. Appuyez dessus pour modifier cette autorisation."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Examiner cette appli qui a accès à vos notifications"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> peut ignorer le contenu de vos notifications, y accéder et agir dessus"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Cette appli peut ignorer vos notifications, accéder à leurs contenus et agir en conséquence. Certaines applis ont besoin de cet accès pour fonctionner correctement."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Supprimer l\'accès"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Afficher plus d\'options"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Accès supprimé"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Examiner cette appli qui a un accès complet à l\'appareil"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> peut accéder à votre écran et effectuer des actions sur votre appareil. Les applis d\'accessibilité ont besoin de ce type d\'accès pour fonctionner correctement."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Cette appli peut accéder à votre écran et effectuer des actions sur votre appareil. Les applis d\'accessibilité ont besoin de ce type d\'accès pour fonctionner correctement. Assurez-vous toutefois qu\'il s\'agit d\'une appli approuvée."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Supprimer l\'autorisation"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Afficher les applis avec accès complet"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Autorisation supprimée"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Système Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Autorisations supprimées pour protéger votre vie privée"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"L\'application <xliff:g id="APP_NAME">%s</xliff:g> n\'a pas été utilisée depuis plusieurs mois. Appuyez pour examiner."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> et une autre application n\'ont pas été utilisées depuis plusieurs mois. Appuyez pour examiner."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder au téléphone, aux SMS, aux contacts et à l\'agenda."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et de lire vos applis en streaming sur l\'appareil connecté."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Ce service partage vos photos, contenus multimédias et notifications avec d\'autres appareils depuis votre téléphone."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Appli de notes par défaut"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Autorisations contrôlées"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Votre position est accessible"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Votre administrateur informatique autorise <xliff:g id="APP_NAME">%s</xliff:g> à accéder à votre position"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Pour les applis et services"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Il est cependant possible que les données du micro soient partagées lorsque vous appelez un numéro d\'urgence."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Modifier"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Sécurité et confidentialité"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Rechercher"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Sécurité et confidentialité"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Analyser l\'appareil"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Ignorer"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Ignorer cette alerte ?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Vérifiez vos paramètres de confidentialité et de sécurité à tout moment pour renforcer la protection"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Ignorer"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Annuler"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Paramètres"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"État de la sécurité et de la confidentialité. <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">"Paramètres de sécurité"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Autorisations du capteur"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Paramètres de confidentialité"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Autorisations"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Sécurité et confidentialité"</string>
+ <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 à 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="7943349178368641820">"Voir plus d\'utilisations de l\'appareil photo"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Voir plus d\'utilisations du micro"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Supprimer l\'autorisation de l\'appareil photo"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Supprimer l\'autorisation du micro"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Voir l\'utilisation récente de l\'appareil photo"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Voir l\'utilisation récente du micro"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Supprimer l\'autorisation de cette appli"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Supprimer l\'autorisation de cette appli"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Gérer le service"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Gérer les autorisations"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Utilisé actuellement par un appel téléphonique"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Récemment utilisé par <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">"Utilisé actuellement par <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">"Récemment utilisé par <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Sécurité et confidentialité"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Vérifier l\'état"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Confirmer"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Retour"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"L\'accès aux autres fichiers sera également autorisé"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Cette appli n\'est pas compatible avec la dernière version d\'Android. Si cette appli ne peut pas accéder à la musique ni aux fichiers audio, elle ne sera pas non plus autorisée à accéder aux photos ni aux vidéos."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Cette appli n\'est pas compatible avec la dernière version d\'Android. Si cette appli peut accéder aux photos et aux vidéos, elle sera également autorisée à accéder à la musique et aux fichiers audio."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Cette appli n\'est pas compatible avec la dernière version d\'Android. Si cette appli ne peut pas accéder à la musique ni aux fichiers audio, elle ne sera pas non plus autorisée à accéder aux photos ni aux vidéos."</string>
+ <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 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 à 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>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Voir les applis et services ayant accès aux données de localisation"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Afficher les accès au presse-papiers"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Afficher un message lorsque les applis 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 brièvement les caractères pendant la saisie"</string>
+ <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">"L\'appli peut partager données de localisation 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_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_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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Les développeurs de ces applis ont fourni des infos concernant leurs pratiques de partage des données avec une plate-forme de téléchargement d\'applications. Ils peuvent mettre à jour ces infos au fil du temps.\n\nCes pratiques de partage des données peuvent varier selon la version de l\'appli, l\'utilisation que vous en faites, votre région et votre âge."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"En savoir plus sur le partage des données"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Vos données de localisation sont désormais partagées avec des tiers"</string>
+ <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">"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>
</resources>
diff --git a/PermissionController/res/values-gl-v33/strings.xml b/PermissionController/res/values-gl-v33/strings.xml
index 711415c0b..3c8898c4f 100644
--- a/PermissionController/res/values-gl-v33/strings.xml
+++ b/PermissionController/res/values-gl-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Esta aplicación vai ter permiso para enviarche notificacións e tamén poderá acceder á cámara, aos contactos, ao micrófono, ao teléfono e ás SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Esta aplicación vai ter permiso para enviarche notificacións e tamén poderá acceder á cámara, aos contactos, aos ficheiros, ao micrófono, ao teléfono e ás SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"As aplicacións que contan con este permiso poden acceder a todos os ficheiros deste dispositivo"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Información sobre a política do teu traballo"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"A configuración xestiónaa o teu administrador de TI"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Despregar e mostrar lista"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Contraer lista e ocultar configuración"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Lista. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Lista. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Cómpre realizar accións. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Elemento da lista. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Pechar"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Despregar e mostrar opcións"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Contraer"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Cambiar. <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">"Activar/desactivar"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Abrir"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Revisar configuración"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Configuración"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Información"</string>
</resources>
diff --git a/PermissionController/res/values-gl-v34/strings.xml b/PermissionController/res/values-gl-v34/strings.xml
new file mode 100644
index 000000000..cabf7a43a
--- /dev/null
+++ b/PermissionController/res/values-gl-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Seguranza e privacidade"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Controis"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Saúde conectada"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Xestiona o acceso das aplicacións aos datos de saúde"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Acceso á localización"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Para aplicacións e servizos. Aínda que esta opción de configuración se atope desactivada, poderán compartirse datos do micrófono se chamas a un número de emerxencias"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Para aplicacións e servizos"</string>
+</resources>
diff --git a/PermissionController/res/values-gl/strings.xml b/PermissionController/res/values-gl/strings.xml
index c797040f3..ad7705f59 100644
--- a/PermissionController/res/values-gl/strings.xml
+++ b/PermissionController/res/values-gl/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Atrás"</string>
<string name="available" msgid="6007778121920339498">"Dispoñible"</string>
<string name="blocked" msgid="9195547604866033708">"Bloqueado"</string>
+ <string name="on" msgid="280241003226755921">"Activado"</string>
+ <string name="off" msgid="1438489226422866263">"Desactivado"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Desinstalar ou desactivar"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Non se encontrou a aplicación"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Non permitir"</string>
@@ -30,11 +32,16 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Manter mentres se estea utilizando a aplicación"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Manter Só esta vez"</string>
<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_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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Detectouse unha superposición na pantalla"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Para cambiar a configuración deste permiso, primeiro tes que desactivar a superposición na pantalla en Configuración &gt; Aplicacións"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Abrir configuración"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Cronoloxía da utilización do permiso <xliff:g id="PERMGROUP">%1$s</xliff:g> por parte das aplicacións nos últimos 7 días"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Cando utilizou esta aplicación o permiso de <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Máis información"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Máis información sobre <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Controla o acceso da aplicación ao grupo (<xliff:g id="PERMGROUP">%1$s</xliff:g>)"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 día}other{# días}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 hora}other{# horas}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 s}other{# s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# día}other{# días}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# hora}other{# horas}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Calquera permiso"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"En calquera momento"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Últimos 7 días"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Últimas 24 horas"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Última hora"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Últimos 15 minutos"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Último minuto"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Últimos día}other{Últimos # días}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Última hora}other{Últimas # horas}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Último minuto}other{Últimos # minutos}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Non se utilizaron os permisos"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Acceso máis recente en todo o tempo"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Acceso máis recente nos últimos 7 días"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Uso dos permisos durante a última hora"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Uso dos permisos durante os últimos 15 minutos"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Uso dos permisos durante o último minuto"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Non se utilizou nas últimas 24 horas"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Non se utilizou nos últimos 7 días"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Non se utilizou no último día}other{Non se utilizou nos últimos # días}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Non se utilizou na última hora}other{Non se utilizou nas últimas # horas}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Permiso usado por 1 aplicación}other{Permiso usado por # aplicacións}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Ver todo no panel de control"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Vista filtrada por: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Permitir acceso só a ficheiros multimedia"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Permitir sempre"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Permitir só mentres se use a aplicación"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Permitir todo sempre"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Preguntar sempre"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Non permitir"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Localización precisa"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Quitaranse os permisos de <xliff:g id="PERM_0">%1$s</xliff:g> e <xliff:g id="PERM_1">%2$s</xliff:g>."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Quitaranse os seguintes permisos: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Xestionar os permisos automaticamente"</string>
- <string name="off" msgid="1438489226422866263">"Desactivado"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Quitouse o permiso (<xliff:g id="PERMISSION_NAME">%s</xliff:g>)"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Quitáronse os permisos (<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> e <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g>)"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Quitáronse os permisos (<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> e <xliff:g id="NUMBER">%2$s</xliff:g> máis)"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Aplicacións que non se usan"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Se durante uns meses non se usa unha aplicación:\n\n• Quítanselle os permisos para protexer os teus datos.\n• Detéñense as notificacións para aforrar batería.\n• Quítanse os ficheiros temporais para liberar espazo.\n\nSe queres dar permisos e recibir notificacións de novo, abre a aplicación."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Se durante uns meses non se usa unha aplicación:\n\n• Quítanselle os permisos para protexer os teus datos.\n• Quítanse os ficheiros temporais para liberar espazo.\n\nSe queres conceder permisos de novo, abre a aplicación."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Última vez que se abriu: hai máis de <xliff:g id="NUMBER">%s</xliff:g> meses"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Se durante un mes non se usa unha aplicación:\n\n• Quítanselle os permisos para protexer os teus datos.\n• Quítanse os ficheiros temporais para liberar espazo.\n\nSe queres conceder permisos de novo, abre a aplicación."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Abriuse por última vez hai máis de # mes}other{Abriuse por última vez hai máis de # meses}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"A aplicación abriuse por última vez o <xliff:g id="DATE">%s</xliff:g>"</string>
<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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Permiso non concedido"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Ver máis aplicacións con acceso a todos os ficheiros"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 día}other{# días}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 hora}other{# horas}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minuto}other{# minutos}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 segundo}other{# segundos}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# hora}other{# horas}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minuto}other{# minutos}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# segundo}other{# segundos}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Recordatorios de permisos"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 aplicación que non se usa"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> aplicacións que non se usan"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Algunhas aplicacións levan varios meses sen usarse. Toca para revisar a utilización."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# aplicación que non se usa}other{# aplicacións que non se usan}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Quitáronse os permisos e os ficheiros temporais, e detivéronse as notificacións. Toca para revisalo."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Revisa as aplicacións ás que se lles quitaron os permisos"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"No caso das aplicacións que levas tempo sen usar, quitáronse os permisos e os ficheiros temporais, e detivéronse as notificacións."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Revisar aplicacións"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Consulta os permisos recentes"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Mentres conducías, décheslle á aplicación <xliff:g id="APP">%1$s</xliff:g> acceso ao seguinte: <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Mentres conducías, décheslle á aplicación <xliff:g id="APP">%1$s</xliff:g> acceso ao seguinte: <xliff:g id="PERMISSION_1">%2$s</xliff:g> e <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Quitáronse os permisos para protexer a túa privacidade"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"A aplicación <xliff:g id="APP_NAME">%s</xliff:g> accedeu á túa localización en segundo plano"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Esta aplicación pode acceder sempre á túa localización. Toca para cambiar esta opción."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Revisa a aplicación con acceso ás notificacións"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> pode pechar notificacións, realizar accións relacionadas con elas e acceder ao contido que inclúan"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Esta aplicación pode pechar notificacións, realizar accións relacionadas con elas e acceder ao contido que inclúan. Algunhas aplicacións requiren este acceso para funcionar correctamente."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Quitar acceso"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Ver máis opcións"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Quitouse o acceso"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Revisa a aplicación con acceso total ao dispositivo"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> pode ver a pantalla e realizar accións no dispositivo. As aplicacións de accesibilidade requiren este tipo de acceso para funcionar correctamente."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Esta aplicación pode ver a pantalla e realizar accións no dispositivo. As aplicacións de accesibilidade requiren este tipo de acceso para funcionar correctamente, pero compróbaa e asegúrate de que sexa fiable."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Quitar acceso"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Ver aplicacións con acceso total"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Quitouse o acceso"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Sistema Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Permisos de aplicacións quitados para protexer a privacidade"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> leva varios meses sen usarse. Toca para revisar a utilización."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> e 1 aplicación máis levan varios meses sen usarse. Toca para revisar a utilización."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> poderá interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das mensaxes, dos contactos e do calendario."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"Permitirase que <xliff:g id="APP_NAME">%1$s</xliff:g> interactúe coas túas notificacións e emita as túas aplicacións ao dispositivo conectado."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Este servizo comparte con outros dispositivos as fotos, o contido multimedia e as notificacións desde o teu teléfono."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"App de notas predeterminada"</string>
+ <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>
<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>
@@ -421,7 +444,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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Permisos controlados"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Pódese acceder á localización"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"O teu administrador de TI permite que <xliff:g id="APP_NAME">%s</xliff:g> acceda á túa localización"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Para aplicacións e servizos"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Con todo, é posible que se compartan os datos do micrófono cando chames a un número de emerxencias."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Cambiar"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Seguranza e privacidade"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Buscar"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Seguranza e privacidade"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Analizar dispositivo"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Pechar"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Queres pechar esta alerta?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Revisa a túa configuración de seguranza e privacidade en calquera momento para engadir máis protección"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Pechar"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Cancelar"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Configuración"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Estado de privacidade e seguranza. <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">"Configuración de seguranza"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Permisos dos sensores"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Controis de privacidade"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Permisos"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Seguranza e privacidade"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Comproba o estado"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Os teus controis de privacidade"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Máis opcións de configuración"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Acceso á cámara"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Acceso ao micrófono"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Permiso retirado"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Ver máis usos da cámara"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Ver máis usos do micrófono"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Quitar permiso da cámara"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Quitar permiso do micrófono"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Ver uso recente da cámara"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Ver uso recente do micrófono"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Retirarlle permiso a esta aplicación"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Retirarlle permiso a esta aplicación"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Xestionar servizo"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Administrar permisos"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"En uso nunha chamada telefónica"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"En uso recentemente por parte de <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">"En uso por parte de <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">"En uso recentemente por parte de <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Seguranza e privacidade"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Comproba o estado"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Confirmar"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Atrás"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Tamén se permitirá o acceso a outros ficheiros"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Esta aplicación non é compatible coa última versión de Android. Se non pode acceder a ficheiros de música e audio, tampouco terá acceso a fotos e vídeos."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Esta aplicación non é compatible coa última versión de Android. Se pode acceder a fotos e vídeos, tamén terá acceso a ficheiros de música e audio."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Esta aplicación non é compatible coa última versión de Android. Se non pode acceder a ficheiros de música e audio, tampouco terá acceso a fotos e vídeos."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Revisa a aplicación con acceso á localización en segundo plano"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> pode acceder á localización sempre, mesmo cando está pechada"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Revisa a aplicación con acceso á localización en segundo plano"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Esta aplicación pode acceder á túa localización sempre, mesmo cando está pechada.\n\nAlgunhas aplicacións de seguranza e emerxencias requiren acceso á túa localización en segundo plano para funcionar segundo o previsto."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Modificouse o acceso"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Ver uso recente da localización"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Controis de privacidade"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Acceso á cámara"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Acceso ao micrófono"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Para aplicacións e servizos"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Para aplicacións e servizos. Aínda que esta opción de configuración se atope desactivada, poderán compartirse datos do micrófono se chamas a un número de emerxencias."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Consulta as aplicacións e os servizos que teñen acceso á localización"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Mostrar acceso ao portapapeis"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Mostra unha mensaxe cando as aplicacións acceden ao texto, ás imaxes ou ao contido que copiaches"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Mostrar contrasinais"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Mostra os caracteres brevemente mentres escribes"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"As prácticas relacionadas cos datos poden variar en función da versión da aplicación, o uso que lle deas, a rexión onde vivas e a idade que teñas. "<annotation id="link">"Máis información sobre o uso compartido de datos"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"As prácticas relacionadas cos datos poden variar en función da versión da aplicación, o uso que lle deas, a rexión onde vivas e a idade que teñas."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Os teus datos de localización"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Cambia o acceso desta aplicación na "<annotation id="link">"configuración de privacidade"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Funcións da aplicación"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Estatísticas"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Comunicacións do programador"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Publicidade ou márketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Prevención de fraudes, seguranza e cumprimento normativo"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalización"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Xestión da conta"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"As persoas que programaron estas aplicacións facilitaron información sobre as súas prácticas á hora de compartir datos cunha tenda de aplicacións. É posible que modifiquen esta información co paso do tempo.\n\nAs súas prácticas á hora de compartir datos poderían variar segundo a versión da aplicación, o uso que lle deas, a rexión onde vivas e a idade que teñas."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Máis información sobre o uso compartido de datos"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Agora, os teus datos de localización compártense con terceiros"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Agora, os teus datos de localización compártense con terceiros con fins publicitarios ou de márketing"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Publicaron cambios no último día}=1{Publicaron cambios no último día}other{Publicaron cambios nos últimos # días}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Nestes momentos non hai ningunha novidade"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-gu-v33/strings.xml b/PermissionController/res/values-gu-v33/strings.xml
index ea39dafbd..d77558fc3 100644
--- a/PermissionController/res/values-gu-v33/strings.xml
+++ b/PermissionController/res/values-gu-v33/strings.xml
@@ -19,4 +19,28 @@
<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="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>
+ <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>
+ <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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"બંધ કરો"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"મોટું કરો અને વિકલ્પો બતાવો"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"નાનું કરો"</string>
+ <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_gear_label" msgid="5175877094379694098">"સેટિંગ"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"માહિતી"</string>
</resources>
diff --git a/PermissionController/res/values-gu-v34/strings.xml b/PermissionController/res/values-gu-v34/strings.xml
new file mode 100644
index 000000000..ba8a5deb0
--- /dev/null
+++ b/PermissionController/res/values-gu-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-gu/strings.xml b/PermissionController/res/values-gu/strings.xml
index 909718fac..d85b35221 100644
--- a/PermissionController/res/values-gu/strings.xml
+++ b/PermissionController/res/values-gu/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"હંમેશાં માટે બધાને મંજૂરી આપો"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"સ્ક્રીન ઓવરલે મળ્યું"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"આ પરવાનગી સેટિંગ બદલવા માટે, તમારે પહેલા સેટિંગ &gt; ઍપમાંથી સ્ક્રીન ઓવરલે બંધ કરવું પડશે"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"સેટિંગ ખોલો"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 દિવસ}one{# દિવસ}other{# દિવસ}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 કલાક}one{# કલાક}other{# કલાક}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 મિનિટ}one{# મિનિટ}other{# મિનિટ}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 સેકન્ડ}one{# સેકન્ડ}other{# સેકન્ડ}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# દિવસ}one{# દિવસ}other{# દિવસ}}"</string>
+ <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_time" msgid="3802087027301631827">"ગમે ત્યારે"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"છેલ્લા 7 દિવસ"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"છેલ્લા 24 કલાક"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"છેલ્લો 1 કલાક"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"છેલ્લી 15 મિનિટ"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"છેલ્લી 1 મિનિટ"</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>
+ <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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"છેલ્લા 24 કલાકમાં કોઈ ઉપયોગ કરવામાં આવ્યો નથી"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"છેલ્લા 7 દિવસમાં કોઈ ઉપયોગ કરવામાં આવ્યો નથી"</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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"હંમેશાં માટે બધાને મંજૂરી આપો"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"દર વખતે પૂછો"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"મંજૂરી આપશો નહીં"</string>
<string name="precise_image_description" msgid="6349638632303619872">"ચોક્કસ સ્થાન"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> અને <xliff:g id="PERM_1">%2$s</xliff:g> પરવાનગી કાઢી નાખવામાં આવશે."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"પરવાનગીઓ કે જે કાઢી નાખવામાં આવશે: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"પરવાનગીઓને ઑટોમૅટિક રીતે મેનેજ કરો"</string>
- <string name="off" msgid="1438489226422866263">"બંધ કરો"</string>
<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_tv_summary" msgid="3685907153054355671">"જો થોડા મહિના માટે કોઈ ઍપનો ઉપયોગ કરવામાં ન આવે, તો:\n\n• તમારો ડેટા સુરક્ષિત રાખવા માટે પરવાનગીઓ કાઢી લેવામાં આવે છે\n• સ્પેસ ખાલી કરવા માટે, હંગામી ફાઇલો કાઢી નાખવામાં આવે છે\n\nપરવાનગીઓની મંજૂરી ફરીથી આપવા માટે, ઍપ ખોલો."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"છેલ્લે <xliff:g id="NUMBER">%s</xliff:g> મહિના કરતાં પર વધારે સમય અગાઉ ખોલી હતી"</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>
<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,9 +254,9 @@
<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{# દિવસ}other{# દિવસ}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 કલાક}one{# કલાક}other{# કલાક}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 મિનિટ}one{# મિનિટ}other{# મિનિટ}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 સેકન્ડ}one{# સેકન્ડ}other{# સેકન્ડ}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# કલાક}one{# કલાક}other{# કલાક}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# મિનિટ}one{# મિનિટ}other{# મિનિટ}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# સેકન્ડ}one{# સેકન્ડ}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>
@@ -262,6 +265,9 @@
<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>
+ <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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android સિસ્ટમ"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"પ્રાઇવસીની સુરક્ષા કરવા માટે ઍપ્લિકેશન પરવાનગીઓ કાઢી નાખી"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g>નો થોડા મહિનાથી ઉપયોગ કરવામાં આવ્યો નથી. રિવ્યૂ કરવા માટે ટૅપ કરો."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> અને 1 અન્ય ઍપનો થોડા મહિનાથી ઉપયોગ કરવામાં આવ્યો નથી. રિવ્યૂ કરવા માટે ટૅપ કરો."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g>ને તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની અને તમારા ફોન, SMS, સંપર્કો તેમજ 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_description" msgid="8496852798616883551">"ઍપ કે જે તમને તમારા ડિવાઇસ પર નોંધ કરવાની મંજૂરી આપે છે"</string>
+ <string name="role_notes_search_keywords" msgid="7710756695666744631">"નોંધ"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"નિયંત્રિત પરવાનગીઓ"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"સ્થાન ઍક્સેસ કરી શકાય છે"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"તમારા IT વ્યવસ્થાપક <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"સુરક્ષા અને પ્રાઇવસી"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"સ્કૅન કરો"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"સેન્સર સંબંધિત પરવાનગીઓ"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"પ્રાઇવસીને લગતાં નિયંત્રણો"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"પરવાનગી કાઢી નાખવામાં આવી"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"કૅમેરાના ઉપયોગ વિશે વધુ માહિતી જુઓ"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"માઇક્રોફોનના ઉપયોગ વિશે વધુ માહિતી જુઓ"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"કૅમેરા સંબંધિત પરવાનગી કાઢી નાખો"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"માઇક્રોફોન સંબંધિત પરવાનગી કાઢી નાખો"</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="manage_service_qs" msgid="7862555549364153805">"સેવા મેનેજ કરો"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"પરવાનગીઓને મેનેજ કરો"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"ફોન કૉલ દ્વારા ઉપયોગ કરવામાં આવી રહ્યો છે"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"સુરક્ષા અને પ્રાઇવસી"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"સ્ટેટસ ચેક કરો"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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">"Analytics"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"ડેવલપર સાથેની વાતચીતો"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{છેલ્લા દિવસમાં કરેલી અપડેટ}=1{છેલ્લા દિવસમાં કરેલી અપડેટ}one{# દિવસમાં કરેલી અપડેટ}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>
</resources>
diff --git a/PermissionController/res/values-hi-v33/strings.xml b/PermissionController/res/values-hi-v33/strings.xml
index 52abea522..9cf4f044d 100644
--- a/PermissionController/res/values-hi-v33/strings.xml
+++ b/PermissionController/res/values-hi-v33/strings.xml
@@ -19,4 +19,28 @@
<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_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>
+ <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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"बंद करें"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"बड़ा करें और विकल्प दिखाएं"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"छोटा करें"</string>
+ <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_gear_label" msgid="5175877094379694098">"सेटिंग"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"जानकारी"</string>
</resources>
diff --git a/PermissionController/res/values-hi-v34/strings.xml b/PermissionController/res/values-hi-v34/strings.xml
new file mode 100644
index 000000000..7b95fb793
--- /dev/null
+++ b/PermissionController/res/values-hi-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-hi/strings.xml b/PermissionController/res/values-hi/strings.xml
index 9abd7d8b5..786a08227 100644
--- a/PermissionController/res/values-hi/strings.xml
+++ b/PermissionController/res/values-hi/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"हमेशा के लिए सभी को अनुमति दें"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"स्क्रीन ओवरले मौजूद है"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"इस अनुमति की सेटिंग बदलने के लिए, आपको पहले \'सेटिंग &gt; ऐप्लिकेशन\' पर जाकर स्क्रीन ओवरले बंद करना होगा"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"सेटिंग खोलें"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"पिछले सात दिनों में, ऐप्लिकेशन ने आपकी <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 दिन}one{# दिन}other{# दिन}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 घंटा}one{# घंटा}other{# घंटे}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 मिनट}one{# मिनट}other{# मिनट}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 सेकंड}one{# सेकंड}other{# सेकंड}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# दिन}one{# दिन}other{# दिन}}"</string>
+ <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_time" msgid="3802087027301631827">"किसी भी समय"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"पिछले सात दिनों में"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"पिछले 24 घंटों में"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"पिछले एक घंटे में"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"पिछले 15 मिनट में"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"आखिरी एक मिनट"</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>
+ <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">"पिछले सात दिनों में सबसे हाल के ऐक्सेस"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"पिछले एक घंटे में अनुमति का इस्तेमाल"</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">"पिछले एक मिनट में अनुमति का इस्तेमाल"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"पिछले 24 घंटों में इस्तेमाल नहीं किया गया"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"पिछले सात दिनों में इस्तेमाल नहीं किया गया"</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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"हमेशा के लिए सभी को ऐक्सेस की अनुमति दें"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"हर बार पूछें"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"अनुमति न दें"</string>
<string name="precise_image_description" msgid="6349638632303619872">"सटीक जगह"</string>
@@ -192,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>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> और <xliff:g id="PERM_1">%2$s</xliff:g> की अनुमतियां हटा दी जाएंगी."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"वे अनुमतियां जो हटा दी जाएंगी: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"अपने-आप अनुमतियां प्रबंधित करें"</string>
- <string name="off" msgid="1438489226422866263">"बंद करें"</string>
<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_tv_summary" msgid="3685907153054355671">"अगर कुछ महीनों से किसी ऐप्लिकेशन को इस्तेमाल न किया गया हो, तो:\n\n• आपके डेटा को सुरक्षित रखने के लिए, उस ऐप्लिकेशन को दी गई अनुमतियां हटा दी जाती हैं\n• मेमोरी खाली करने के लिए, डिवाइस पर कुछ समय के लिए सेव की गई फ़ाइलें हटा दी जाती हैं\n\nफिर से अनुमतियां देने के लिए, ऐप्लिकेशन खोलें."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"पिछली बार इसे <xliff:g id="NUMBER">%s</xliff:g> महीने पहले खोला गया था"</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>
<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>
@@ -251,9 +254,9 @@
<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{# दिन}other{# दिन}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 घंटा}one{# घंटा}other{# घंटे}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 मिनट}one{# मिनट}other{# मिनट}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 सेकंड}one{# सेकंड}other{# सेकंड}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# घंटा}one{# घंटा}other{# घंटे}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# मिनट}one{# मिनट}other{# मिनट}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# सेकंड}one{# सेकंड}other{# सेकंड}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"अनुमति रिमाइंडर"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"एक ऐप्लिकेशन इस्तेमाल नहीं किया जा रहा"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> ऐप्लिकेशन इस्तेमाल नहीं किए जा रहे"</string>
@@ -262,6 +265,9 @@
<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>
+ <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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android System"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"निजता की सुरक्षा के लिए ऐप्लिकेशन की अनुमतियां हटाई गई हैं"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> का कुछ महीनों से इस्तेमाल नहीं किया गया है. देखने के लिए टैप करें."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> और 1 दूसरी ऐप्लिकेशन का कुछ महीनों से इस्तेमाल नहीं किया गया है. देखने के लिए टैप करें."</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"नोट"</string>
<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,7 +465,7 @@
<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_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_coarselocation" msgid="7244605063736425232">"क्या आपको &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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"कंट्रोल की गई अनुमतियां"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"जगह की जानकारी देखी जा सकती है"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"आपका आईटी एडमिन <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"सुरक्षा और निजता"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"स्कैन करें"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"सेंसर ऐक्सेस करने की अनुमति"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"निजता सेटिंग"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"अनुमति हटाई गई"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"कैमरे के और इस्तेमाल देखें"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"माइक्रोफ़ोन के और इस्तेमाल देखें"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"कैमरा ऐक्सेस करने की अनुमति हटाई गई"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"माइक्रोफ़ोन ऐक्सेस करने की अनुमति हटाई गई"</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="manage_service_qs" msgid="7862555549364153805">"सेवा मैनेज करें"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"अनुमतियां मैनेज करें"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"किसी खास फ़ोन कॉल के लिए इस्तेमाल हो रहा है"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"सुरक्षा और निजता"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"स्थिति देखें"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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">"Analytics के लिए"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"डेवलपर कम्यूनिकेशन के लिए"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{कल अपडेट किया गया}=1{कल अपडेट किया गया}one{# दिन के अंदर अपडेट किया गया}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>
</resources>
diff --git a/PermissionController/res/values-hr-v33/strings.xml b/PermissionController/res/values-hr-v33/strings.xml
index 04d69db1b..a50e58158 100644
--- a/PermissionController/res/values-hr-v33/strings.xml
+++ b/PermissionController/res/values-hr-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Aplikacija će vam moći slati obavijesti i dobit će pristup vašoj kameri, kontaktima, mikrofonu, telefonu i SMS-ovima"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Aplikacija će vam moći slati obavijesti i dobit će pristup vašoj kameri, kontaktima, datotekama, mikrofonu, telefonu i SMS-ovima"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Aplikacije s tim dopuštenjem imaju pristup svim datotekama na ovom uređaju"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Informacije o pravilima za posao"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Postavkama upravlja vaš IT administrator"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Proširi i prikaži popis"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Sažmi popis i sakrij postavke"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Popis. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Popis. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Potrebno je poduzeti radnje. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Stavka popisa. <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">"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>
+ <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 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>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Sažmi"</string>
+ <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">"Promijeni"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Otvori"</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">"Podatak"</string>
</resources>
diff --git a/PermissionController/res/values-hr-v34/strings.xml b/PermissionController/res/values-hr-v34/strings.xml
new file mode 100644
index 000000000..74a1d7d1e
--- /dev/null
+++ b/PermissionController/res/values-hr-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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 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>
+</resources>
diff --git a/PermissionController/res/values-hr/strings.xml b/PermissionController/res/values-hr/strings.xml
index 058de6908..b63d820f2 100644
--- a/PermissionController/res/values-hr/strings.xml
+++ b/PermissionController/res/values-hr/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Natrag"</string>
<string name="available" msgid="6007778121920339498">"Dostupno"</string>
<string name="blocked" msgid="9195547604866033708">"Blokirano"</string>
+ <string name="on" msgid="280241003226755921">"Uključeno"</string>
+ <string name="off" msgid="1438489226422866263">"Isključeno"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Deinstaliranje ili onemogućivanje"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Aplikacija nije pronađena"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Nemoj dopustiti"</string>
@@ -30,11 +32,16 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Zadržite \"Dok se aplikacija koristi\""</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Zadrži \"Samo ovaj put\""</string>
<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_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">"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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Otkriveno je preklapanje na zaslonu"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Da biste promijenili tu postavku dopuštenja, prvo morate isključiti preklapanje na zaslonu u Postavkama &gt; Aplikacije"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Otvori postavke"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Kad su aplikacije koristile dopuštenje <xliff:g id="PERMGROUP">%1$s</xliff:g> u posljednjih sedam dana"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Kad je ova aplikacija koristili vaše dopuštenje <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Saznajte više"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Saznajte što podrazumijeva <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Upravlja pristupom aplikacije za: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 dan}one{# dan}few{# dana}other{# dana}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 h}one{# h}few{# h}other{# h}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}one{# min}few{# min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 s}one{# s}few{# s}other{# s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# dan}one{# dan}few{# dana}other{# dana}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# sat}one{# sat}few{# sata}other{# sati}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}one{# min}few{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}one{# s}few{# s}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Bilo koje dopuštenje"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Bilo kad"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Posljednjih tjedan dana"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Posljednja 24 sata"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Posljednjih sat vremena"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Posljednjih 15 minuta"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Posljednja minuta"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{posljednji # dan}one{Posljednji # dan}few{Posljednja # dana}other{Posljednjih # dana}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Posljednjih sat vremena}one{Posljednji # sat}few{Posljednja # sata}other{Posljednjih # sati}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Posljednja # minuta}one{Posljednja # minuta}few{Posljednje # minute}other{Posljednjih # minuta}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Nema upotreba dopuštenja"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Posljednji pristup u bilo koje vrijeme"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Posljednji pristup u prethodnih tjedan dana"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Upotreba dopuštenja u posljednjih sat vremena"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Upotreba dopuštenja u posljednjih 15 minuta"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Upotreba dopuštenja u posljednjoj minuti"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Nije korišteno u posljednja 24 sata"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Nije korišteno u posljednjih sedam dana"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Nije korišteno u posljednji # dan}one{Nije korišteno u posljednji # dan}few{Nije korišteno u posljednja # dana}other{Nije korišteno u posljednjih # dana}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Nije korišteno u posljednji # sat}one{Nije korišteno u posljednji # sat}few{Nije korišteno u posljednja # sata}other{Nije korišteno u posljednjih # sati}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Koristi 1 aplikacija}one{Koristi # aplikacija}few{Koriste # aplikacije}other{Koristi # aplikacija}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Pogledajte sve na nadzornoj ploči"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrirano po: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Omogući pristup samo medijima"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Dopusti cijelo vrijeme"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Dopusti samo dok se aplikacija koristi"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Uvijek dopusti sve"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Pitaj svaki put"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Nemoj dopustiti"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Točna lokacija"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Bit će uklonjena dopuštenja <xliff:g id="PERM_0">%1$s</xliff:g> i <xliff:g id="PERM_1">%2$s</xliff:g>."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Dopuštenja koja će biti uklonjena: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Automatsko upravljanje dopuštenjima"</string>
- <string name="off" msgid="1438489226422866263">"Isključeno"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Uklonjeno je dopuštenje <xliff:g id="PERMISSION_NAME">%s</xliff:g>"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Uklonjena su dopuštenja <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> i <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g>"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Uklonjeno je dopuštenje <xliff:g id="PERMISSION_NAME">%1$s</xliff:g> i njih još <xliff:g id="NUMBER">%2$s</xliff:g>"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Nekorištene aplikacije"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Ako se aplikacija ne koristi nekoliko mjeseci:\n\n• Dopuštenja se uklanjaju radi zaštite vaših podataka.\n• Obavijesti se zaustavljaju radi štednje baterije.\n• Privremene se datoteke uklanjaju radi oslobađanja prostora.\n\nDa biste ponovo odobrili dopuštenja i obavijesti, otvorite aplikaciju."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Ako se aplikacija ne koristi nekoliko mjeseci:\n\n• Dopuštenja se uklanjaju radi zaštite vaših podataka.\n• Privremene datoteke uklanjaju se radi oslobađanja prostora.\n\nDa biste ponovo odobrili dopuštenja, otvorite aplikaciju."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Posljednji put otvoreno prije više od <xliff:g id="NUMBER">%s</xliff:g> mj."</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Ako se aplikacija ne koristi mjesec dana:\n\n• Dopuštenja se uklanjaju radi zaštite vaših podataka.\n• Privremene datoteke uklanjaju se radi oslobađanja prostora.\n\nDa biste ponovo odobrili dopuštenja, otvorite aplikaciju."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Posljednji put otvoreno prije više od # mjeseca}one{Posljednji put otvoreno prije više od # mjeseca}few{Posljednji put otvoreno prije više od # mjeseca}other{Posljednji put otvoreno prije više od # mjeseci}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Aplikacija je posljednji put otvorena <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Posljednje otvaranje <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Ako dopustite upravljanje svim datotekama, ova će aplikacija moći pristupati datotekama u zajedničkoj pohrani na ovom uređaju ili povezanim uređajima za pohranu te ih mijenjati i brisati. Aplikacija će moći pristupati datotekama bez vašeg dopuštenja."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Nemaju dopuštenje"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Pogledajte koje još aplikacije imaju pristup svim datotekama"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 dan}one{# dan}few{# dana}other{# dana}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 h}one{# h}few{# h}other{# h}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 min}one{# min}few{# min}other{# min}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 s}one{# s}few{# s}other{# s}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# sat}one{# sat}few{# sata}other{# sati}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# min}one{# min}few{# min}other{# min}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# s}one{# s}few{# s}other{# s}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Podsjetnici za dopuštenja"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 nekorištena aplikacija"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"Nekorištenih aplikacija: <xliff:g id="NUMBER_OF_APPS">%s</xliff:g>"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Neke aplikacije niste upotrebljavali nekoliko mjeseci. Dodirnite za pregled."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# nekorištena aplikacija}one{# nekorištena aplikacija}few{# nekorištene aplikacije}other{# nekorištenih aplikacija}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Dopuštenja i privremene datoteke uklonjeni su, a obavijesti su zaustavljene. Dodirnite za pregled."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Pregled aplikacija s uklonjenim dopuštenjima"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Za aplikacije koje neko vrijeme niste koristili uklonjena su dopuštenja i privremene datoteke, a obavijesti su zaustavljene."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Pregled aplikacija"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Provjerite nedavna dopuštenja"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Tijekom vožnje aplikaciji <xliff:g id="APP">%1$s</xliff:g> dali ste pristup dopuštenju <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Tijekom vožnje aplikaciji <xliff:g id="APP">%1$s</xliff:g> dali ste pristup dopuštenjima <xliff:g id="PERMISSION_1">%2$s</xliff:g> i <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Uklonjena su dopuštenja radi zaštite vaše privatnosti"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"Aplikacija <xliff:g id="APP_NAME">%s</xliff:g> pristupa vašoj lokaciji u pozadini"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Ova aplikacija može uvijek pristupiti vašoj lokaciji. Dodirnite za promjenu."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Pregledavanje aplikacije s pristupom vašim obavijestima"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> može odbaciti sadržaj u vašim obavijestima, djelovati na temelju njega ili mu pristupiti"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Ova aplikacija može odbaciti sadržaj u vašim obavijestima, djelovati na temelju njega ili mu pristupiti. Neke aplikacije zahtijevaju taj pristup kako bi funkcionirale kako je predviđeno."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Ukloni pristup"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Prikaži dodatne mogućnosti"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Pristup je uklonjen"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Pregledajte aplikaciju s potpunim pristupom uređaju"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"Aplikacija <xliff:g id="APP_NAME">%s</xliff:g> može vidjeti vaš zaslon i izvršavati radnje na vašem uređaju. Aplikacije za pristupačnost trebaju tu vrstu pristupa kako bi funkcionirale kako je predviđeno."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Ova aplikacija može vidjeti vaš zaslon i izvršavati radnje na vašem uređaju. Aplikacije za pristupačnost trebaju tu vrstu pristupa kako bi funkcionirale kako je predviđeno, no provjerite aplikaciju i obavezno neka bude pouzdana."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Ukloni pristup"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Prikaži aplikacije s potpunim pristupom"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Pristup je uklonjen"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Sustav Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Dopuštenja za aplikacije uklonjena su radi zaštite privatnosti"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Aplikaciju <xliff:g id="APP_NAME">%s</xliff:g> niste upotrebljavali nekoliko mjeseci. Dodirnite za pregled."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"Aplikaciju <xliff:g id="APP_NAME">%s</xliff:g> i još jednu aplikaciju niste upotrebljavali nekoliko mjeseci. Dodirnite za pregled."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati dopuštenjima za telefon, SMS-ove, kontakte i kalendar."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i streamati aplikacije na povezanom uređaju."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Usluga dijeli vaše fotografije, medije i obavijesti s telefona s drugim uređajima."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Zadana aplikacija za bilješke"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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 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_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_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="permgrouprequestdetail_microphone" msgid="8510456971528228861">"Aplikacija će moći snimati audiozapise samo dok je upotrebljavate"</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>
@@ -474,8 +498,8 @@
<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 aplikaciji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; dopustiti da vam šalje obavijesti?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Kontrolirana dopuštenja"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Lokaciji se može pristupiti"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Vaš IT administrator dopušta aplikaciji <xliff:g id="APP_NAME">%s</xliff:g> da pristupa vašoj lokaciji"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Za aplikacije i usluge"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Podaci mikrofona i dalje se mogu dijeliti kad pozovete broj hitne službe."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Promijeni"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Sigurnost i privatnost"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Traži"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Sigurnost i privatnost"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Skeniranje uređaja"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Odbaci"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Želite li odbaciti ovo upozorenje?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Pregledajte postavke sigurnosti i privatnosti za dodatnu zaštitu"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Odbaci"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Odustani"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Postavke"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Status sigurnosti i privatnosti. <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">"Sigurnosne postavke"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Dopuštenja za senzor"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Kontrole privatnosti"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Dopuštenja"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Sigurnost i privatnost"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Provjera statusa"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Vaše kontrole privatnosti"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Više postavki"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Pristup fotoaparatu"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Pristup mikrofonu"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Dopuštenje uklonjeno"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Više informacija o upotrebi fotoaparata"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Više informacija o upotrebi mikrofona"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Ukloni dopuštenje za fotoaparat"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Ukloni dopuštenje za mikrofon"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Prikaži nedavnu upotrebu fotoaparata"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Prikaži nedavnu upotrebu mikrofona"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Uklanjanje dopuštenja za ovu aplikaciju"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Uklanjanje dopuštenja za ovu aplikaciju"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Upravljanje uslugama"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Upravljajte dopuštenjima"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Koristi telefonski poziv"</string>
@@ -517,8 +552,6 @@
<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>
<string name="recent_app_usage_2_qs" msgid="3591205954235694403">"Nedavno koristila 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>
- <string name="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Sigurnost i privatnost"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Provjera statusa"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Potvrdi"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Natrag"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Dopustit će se pristup i drugim datotekama"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Aplikacija ne podržava najnoviju verziju Androida. Ako aplikacija ne može pristupiti glazbenim i audiodatotekama, neće moći pristupiti ni fotografijama i videozapisima."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Aplikacija ne podržava najnoviju verziju Androida. Ako aplikacija može pristupiti fotografijama i videozapisima, moći će pristupiti i glazbenim i audiodatotekama."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Aplikacija ne podržava najnoviju verziju Androida. Ako aplikacija ne može pristupiti glazbenim i audiodatotekama, neće moći pristupiti ni fotografijama i videozapisima."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Pregledajte aplikaciju s pristupom lokaciji u pozadini"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"Aplikacija <xliff:g id="APP_NAME">%s</xliff:g> može uvijek pristupiti vašoj lokaciji, čak i ako je zatvorena"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Pregledajte aplikaciju s pristupom lokaciji u pozadini"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Ova aplikacija može uvijek pristupiti vašoj lokaciji, čak i kad je zatvorena.\n\nNeke sigurnosne aplikacije i aplikacije za hitne slučajeve zahtijevaju pristup vašoj lokaciji u pozadini da bi funkcionirale onako kako je predviđeno."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Promijenjen je pristup"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Prikaži nedavnu upotrebu lokacije"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Kontrole privatnosti"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Pristup fotoaparatu"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Pristup mikrofonu"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Za aplikacije i usluge"</string>
+ <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">"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">"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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Postupanje s podacima može se razlikovati ovisno o verziji aplikacije, upotrebi, regiji i dobi. "<annotation id="link">"Više o dijeljenju podataka"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Postupanje s podacima može se razlikovati ovisno o verziji aplikacije, upotrebi, regiji i dobi."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Vaši podaci o lokaciji"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Promijenite pristup aplikacije u "<annotation id="link">"postavkama privatnosti"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"funkcije aplikacije"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"analitike"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"komunikacije s razvojnim programerom"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"oglašavanja ili marketinga"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"sprječavanja prijevara, sigurnosti i usklađenosti"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"personalizacije"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"upravljanja računom."</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Razvojni programeri tih aplikacija su trgovini aplikacija poslali podatke o praksama dijeljenja podataka. S vremenom ih mogu ažurirati.\n\nPrakse dijeljenja podataka mogu se razlikovati ovisno o verziji aplikacije, upotrebi, regiji i dobi."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Saznajte više o dijeljenju podataka"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Podaci o lokaciji sada se dijele s trećim stranama"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Podaci o lokaciji sada se dijele s trećim stranama radi oglašavanja ili marketinga"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Ažurirano tijekom posljednjeg dana}=1{Ažurirano tijekom posljednjeg dana}one{Ažurirano tijekom posljednjeg # dana}few{Ažurirano tijekom posljednja # dana}other{Ažurirano tijekom posljednjih # dana}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Trenutačno nema promjena"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-hu-v33/strings.xml b/PermissionController/res/values-hu-v33/strings.xml
index 753d2162d..ee454fc12 100644
--- a/PermissionController/res/values-hu-v33/strings.xml
+++ b/PermissionController/res/values-hu-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Az alkalmazás engedélyt kap értesítések küldésére, és hozzáférhet majd a következőkhöz: Kamera, Névjegyek, Mikrofon, Telefon és SMS."</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Az alkalmazás engedélyt kap értesítések küldésére, és hozzáférhet majd a következőkhöz: Kamera, Címtár, Files, Mikrofon, Telefon és SMS."</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Az ezzel az engedéllyel rendelkező alkalmazások hozzáférhetnek az ezen az eszközön lévő összes fájlhoz"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Munkahelyi házirendekkel kapcsolatos adatok"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"A rendszergazda által kezelt beállítások"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Kibontás és lista megjelenítése"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Lista összecsukása és beállítások elrejtése"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Lista. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Lista. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Fontos teendő. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Listaelem. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Bezárás"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Kibontás és lehetőségek megjelenítése"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Összecsukás"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Váltás. <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">"Be- és kikapcsolás"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Megnyitás"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Beállítások áttekintése"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Beállítások"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Információ"</string>
</resources>
diff --git a/PermissionController/res/values-hu-v34/strings.xml b/PermissionController/res/values-hu-v34/strings.xml
new file mode 100644
index 000000000..1a01b1cc0
--- /dev/null
+++ b/PermissionController/res/values-hu-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Biztonság és adatvédelem"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Vezérlők"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Az egészségügyi adatokhoz való alkalmazás-hozzáférés kezelése"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Helyhozzáférés"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Alkalmazásoknál és szolgáltatásoknál. Ha ki van kapcsolva ez a beállítás, segélyhívó szám hívásakor a rendszer továbbra is megoszthatja a mikrofonadatokat."</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Alkalmazásoknál és szolgáltatásoknál"</string>
+</resources>
diff --git a/PermissionController/res/values-hu/strings.xml b/PermissionController/res/values-hu/strings.xml
index 0fc85e6cd..12ad687a6 100644
--- a/PermissionController/res/values-hu/strings.xml
+++ b/PermissionController/res/values-hu/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Vissza"</string>
<string name="available" msgid="6007778121920339498">"Rendelkezésre áll"</string>
<string name="blocked" msgid="9195547604866033708">"Letiltva"</string>
+ <string name="on" msgid="280241003226755921">"Be"</string>
+ <string name="off" msgid="1438489226422866263">"Ki"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Eltávolítás vagy letiltás"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Az alkalmazás nem található"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Tiltás"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Továbbra is: „Amíg az alkalmazás használatban van”"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Maradjon „Csak most”"</string>
<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">"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">"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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Képernyőfedvény észlelve"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Ennek az engedélynek a módosításához először ki kell kapcsolnia a képernyőfedvényt a Beállítások &gt; Alkalmazások menüben"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Beállítások megnyitása"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Mikor használták az alkalmazások a(z) <xliff:g id="PERMGROUP">%1$s</xliff:g> funkciót az elmúlt 7 napban"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Mikor használta ez az alkalmazás a(z) Ön <xliff:g id="PERMGROUP">%1$s</xliff:g> engedélyét?"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"További információ"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"További információ a következőről: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Alkalmazás-hozzáférés vezérlése a következőhöz: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 nap}other{# nap}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 óra}other{# óra}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 perc}other{# perc}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 mp}other{# mp}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# nap}other{# nap}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# óra}other{# óra}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# perc}other{# perc}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# mp}other{# mp}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Bármely engedély"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Bármikor"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Elmúlt 7 nap"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Elmúlt 24 óra"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Elmúlt 1 óra"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Elmúlt 15 perc"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Elmúlt 1 perc"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Elmúlt # nap}other{Elmúlt # nap}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Elmúlt # óra}other{Elmúlt # óra}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Elmúlt # perc}other{Elmúlt # perc}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Nincs engedélyhasználat"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Legutóbbi hozzáférés bármikor"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Legutóbbi hozzáférés az elmúlt hét nap során"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Engedélyhasználat az elmúlt egy órában"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Engedélyhasználat az elmúlt 15 percben"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Engedélyhasználat az elmúlt egy percben"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Semmi nem használta az elmúlt 24 órában"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Semmi nem használta az elmúlt hét napban"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Nem volt használva az elmúlt # nap során}other{Semmi nem használta az elmúlt # napban}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Nem volt használva az elmúlt # óra során}other{Semmi nem használta az elmúlt # órában}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{1 alkalmazás használta}other{# alkalmazás használta}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Összes megtekintése az irányítópulton"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Szűrés alapja: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Csak a médiatartalmakhoz való hozzáférés engedélyezése"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Mindig engedélyezett"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Csak az alkalmazás használatakor engedélyezett"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Mindig az összes engedélyezése"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Mindig kérdezzen rá"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Tiltás"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Pontos hely"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"A(z) <xliff:g id="PERM_0">%1$s</xliff:g> és a(z) <xliff:g id="PERM_1">%2$s</xliff:g> engedély el lesz távolítva."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Eltávolításra kerülő engedélyek: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Engedélyek automatikus kezelése"</string>
- <string name="off" msgid="1438489226422866263">"Ki"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"A(z) <xliff:g id="PERMISSION_NAME">%s</xliff:g> engedély visszavonva"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"A(z) <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> és a(z) <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> engedély visszavonva"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"A(z) <xliff:g id="PERMISSION_NAME">%1$s</xliff:g> és <xliff:g id="NUMBER">%2$s</xliff:g> másik engedély visszavonva"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Nem használt alkalmazások"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Ha az adott alkalmazást nem használja néhány hónapig:\n\n• Az engedélyeket az adatok védelme érdekében eltávolítjuk.\n• Az akkumulátor kímélése érdekében az értesítéseket leállítjuk.\n• Tárhely felszabadítása érdekében az ideiglenes fájlokat eltávolítjuk.\n\nAz engedélyek és az értesítések újbóli bekapcsolásához nyissa meg az alkalmazást."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Ha nem használja néhány hónapig az adott alkalmazást:\n\n• Az adatok védelme érdekében eltávolítjuk az engedélyeket.\n• Tárhely felszabadítása érdekében eltávolítjuk az ideiglenes fájlokat.\n\nAz engedélyek újbóli megadásához nyissa meg az alkalmazást."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Utoljára több mint <xliff:g id="NUMBER">%s</xliff:g> hónapja nyitotta meg"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Ha nem használja egy hónapig az adott alkalmazást:\n\n• Az adatok védelme érdekében eltávolítjuk az engedélyeket.\n• Tárhely felszabadítása érdekében eltávolítjuk az ideiglenes fájlokat.\n\nAz engedélyek újbóli megadásához nyissa meg az alkalmazást."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Utoljára több mint # hónapja nyitotta meg}other{Utoljára több mint # hónapja nyitotta meg}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Az alkalmazás legutóbbi megnyitása: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Legutóbb megnyitva ekkor: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Ha engedélyezi az összes fájl kezelését, ez az alkalmazás hozzáférhet az eszköz tárhelyén és a csatlakoztatott tárolóeszközökön található fájlokhoz, valamint módosíthatja és törölheti őket. Az alkalmazás anélkül férhet hozzá a fájlokhoz, hogy Önt megkérdezné róla."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Nem engedélyezett"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"További, minden fájlhoz hozzáférő alkalmazások megtekintése"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 nap}other{# nap}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 óra}other{# óra}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 perc}other{# perc}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 másodperc}other{# másodperc}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# óra}other{# óra}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# perc}other{# perc}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# másodperc}other{# másodperc}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Engedélyekre vonatkozó emlékeztetők"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 nem használt alkalmazás"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> nem használt alkalmazás"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Egyes alkalmazásokat több hónapja nem használt. Koppintson az áttekintéshez."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# nem használt alkalmazás}other{# nem használt alkalmazás}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Az engedélyek és az ideiglenes fájlok el lettek távolítva, az értesítések pedig le lettek állítva. Koppintson az áttekintéshez."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Eltávolított hozzáféréssel rendelkező appok áttekintése"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Az egy ideje már nem használt alkalmazásoknál el lettek távolítva az engedélyek és az ideiglenes fájlok, az értesítések pedig le lettek állítva."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Alkalmazások áttekintése"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Legfrissebb engedélyek ellenőrzése"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Vezetés közben <xliff:g id="APP">%1$s</xliff:g> alkalmazásnak <xliff:g id="PERMISSION">%2$s</xliff:g> hozzáférést adott."</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Vezetés közben <xliff:g id="APP">%1$s</xliff:g> alkalmazásnak <xliff:g id="PERMISSION_1">%2$s</xliff:g> és <xliff:g id="PERMISSION_2">%3$s</xliff:g>hozzáférést adott."</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Engedélyek visszavonva az adatainak védelme érdekében"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"A(z) <xliff:g id="APP_NAME">%s</xliff:g> hozzáfér az Ön helyadataihoz a háttérben"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Ez az alkalmazás bármikor hozzáférhet az Ön tartózkodási helyéhez. A módosításhoz koppintson."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Értesítés-hozzáféréssel rendelkező alkalmazás áttekintése"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"A(z) <xliff:g id="APP_NAME">%s</xliff:g> elvetheti az értesítéseit, műveleteket végezhet velük, és hozzáférhet az értesítések tartalmához"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Az alkalmazás elvetheti az értesítéseit, műveleteket végezhet velük, és hozzáférhet az értesítések tartalmához. Bizonyos alkalmazásoknak szükségük van az ilyen típusú hozzáférésre, hogy a tervezett módon működhessenek."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Hozzáférés megvonása"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"További lehetőségek megjelenítése"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Hozzáférés visszavonva"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Teljes eszközhozzáféréssel rendelkező alkalmazás áttekintése"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"A(z) <xliff:g id="APP_NAME">%s</xliff:g> megtekintheti a képernyőt, és műveleteket végezhet az eszközön. A kisegítő alkalmazásoknak szükségük van az ilyen típusú hozzáférésre, hogy a tervezett módon működhessenek."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Ez az alkalmazás megtekintheti a képernyőt, és műveleteket végezhet az eszközön. A kisegítő alkalmazásoknak szükségük van az ilyen típusú hozzáférésre, hogy a tervezett módon működhessenek, de ellenőrizheti az appot, hogy biztosan megbízhatónak tartja-e."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Hozzáférés megvonása"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Teljes hozzáféréssel rendelkező appok felülvizsgálata"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Hozzáférés visszavonva"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android rendszer"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Alkalmazásengedélyek eltávolítva az adatvédelem érdekében"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Több hónapja nem használta a(z) <xliff:g id="APP_NAME">%s</xliff:g> alkalmazást. Koppintson az áttekintéshez."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"Több hónapja nem használta a(z) <xliff:g id="APP_NAME">%s</xliff:g> és 1 további alkalmazást. Koppintson az áttekintéshez."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és hozzáférhet a telefonra, az SMS-ekre, a névjegyekre és a naptárra vonatkozó engedélyekhez."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és streamelheti az alkalmazásait a csatlakoztatott eszközre."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Ez a szolgáltatás megosztja a telefonján található fotóit, médiatartalmait és értesítéseit egyéb eszközökkel."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Alapértelmezett jegyzetapp"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Szabályozott engedélyek"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"A helyadatok hozzáférhetők"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Az Ön adminisztrátora engedélyezi a(z) <xliff:g id="APP_NAME">%s</xliff:g> számára, hogy hozzáférjen az eszköz helyadataihoz"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Alkalmazásoknál és szolgáltatásoknál"</string>
<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="7514620345152008005">"Biztonság és adatvédelem"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Keresé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">"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>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Bezárás"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Mégse"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Beállítások"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Biztonsági és adatvédelmi állapot. <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">"Biztonsági beállítások"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Érzékelőengedélyek"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Adatvédelmi beállítások"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Engedélyek"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Biztonság és adatvédelem"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Állapot ellenőrzése"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Adatvédelmi beállítások"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"További beállítások"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Kamera-hozzáférés"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Mikrofon-hozzáférés"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Engedély visszavonva"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"További részletek a kamerahasználatról"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"További részletek a mikrofonhasználatról"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Kamera-hozzáférési engedély visszavonása"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Mikrofon-hozzáférési engedély visszavonása"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Legutóbbi kamerahasználat megtekintése"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Legutóbbi mikrofonhasználat megtekintése"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Engedély megvonása ettől az alkalmazástól"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Engedély megvonása ettől az alkalmazástól"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Szolgáltatás kezelése"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Engedélyek kezelése"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Jelenleg telefonhívás használja"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Legutóbb használta: <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">"Jelenleg használja: <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">"Legutóbb használta: <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Biztonság és adatvédelem"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Állapot ellenőrzése"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Megerősítés"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Vissza"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Az egyéb fájlokhoz való hozzáférés szintén engedélyezett"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Az alkalmazás nem támogatja az Android legújabb verzióját. Ha az alkalmazás nem férhet hozzá a zenékhez és a hangfájlokhoz, akkor ugyanúgy a fotókhoz és a videókhoz sem férhet hozzá."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Az alkalmazás nem támogatja az Android legújabb verzióját. Ha az alkalmazás hozzáférhet a fotókhoz és videókhoz, akkor hozzáférhet a zenékhez és a hangfájlokhoz is."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Az alkalmazás nem támogatja az Android legújabb verzióját. Ha az alkalmazás nem férhet hozzá a zenékhez és a hangfájlokhoz, akkor ugyanúgy a fotókhoz és a videókhoz sem férhet hozzá."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Háttérbeli helyhozzáféréssel rendelkező alkalmazás áttekintése"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"A(z) <xliff:g id="APP_NAME">%s</xliff:g> mindig hozzáférhet az eszköz helyadataihoz, akkor is, ha be van zárva."</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Háttérbeli helyhozzáféréssel rendelkező alkalmazás áttekintése"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Ez az alkalmazás mindig hozzáférhet az Ön helyadataihoz, akkor is, ha be van zárva.\n\nEgyes biztonsági és segélykérő alkalmazásoknak hozzá kell férniük a háttérben a helyadatokhoz, hogy rendeltetésszerűen működhessenek."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Hozzáférés módosítva"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Legutóbbi helyadathasználat megtekintése"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Adatvédelmi beállítások"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Hozzáférés a kamerához"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Hozzáférés a mikrofonhoz"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Alkalmazásoknál és szolgáltatásoknál"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Alkalmazásoknál és szolgáltatásoknál. Ha ki van kapcsolva ez a beállítás, segélyhívó szám hívásakor a rendszer továbbra is megoszthatja a mikrofonadatokat."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"A helyadatokhoz hozzáférő alkalmazások és szolgáltatások megtekintése"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Vágólap-hozzáférés megjelenítése"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Üzenet megjelenítése, amikor alkalmazások férnek hozzá a vágólapra másolt szövegekhez, képekhez vagy más tartalmakhoz"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Jelszavak mutatása"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Gépelés közben rövid ideig megjeleníti a karaktereket"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Az adatkezelési gyakorlat az alkalmazásverziótól, az alkalmazáshasználattól, a régiótól és életkortól függően változhat. "<annotation id="link">"További információ az adatmegosztásról"</annotation>"."</string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Az adatkezelési gyakorlat az alkalmazásverziótól, az alkalmazáshasználattól, a régiótól és életkortól függően változhat."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Helyadatok"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Az alkalmazás hozzáférésének módosítása az "<annotation id="link">"adatvédelmi beállításokban"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Alkalmazásfunkciók"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Elemzések"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Fejlesztői közlemények"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Hirdetés vagy marketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Csalásmegelőzés, biztonság és megfelelőség"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Személyre szabás"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Fiókkezelés"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Ezeknek az alkalmazásoknak a fejlesztői információt adtak meg az alkalmazásboltokkal való adatmegosztási gyakorlatukról. Az információt idővel módosíthatják.\n\nAz adatmegosztási gyakorlatok az alkalmazásverziótól, a használattól, a régiótól és az életkortól függően eltérhetnek."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"További információ az adatmegosztásról"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Helyadatai mostantól harmadik felekkel vannak megosztva"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Helyadatai mostantól hirdetési vagy marketingcélokra harmadik felekkel vannak megosztva"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Módosítva az elmúlt napon}=1{Módosítva az elmúlt napon}other{Módosítva # napon belül}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Jelenleg nincs módosítás"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-hy-v33/strings.xml b/PermissionController/res/values-hy-v33/strings.xml
index 9710ab0b9..6efb079ef 100644
--- a/PermissionController/res/values-hy-v33/strings.xml
+++ b/PermissionController/res/values-hy-v33/strings.xml
@@ -19,4 +19,28 @@
<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="work_policy_title" msgid="832967780713677409">"Տեղեկություններ աշխատանքի կանոնների մասին"</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>
+ <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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Փակել"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Ծավալել և ցույց տալ տարբերակները"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Ծալել"</string>
+ <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_gear_label" msgid="5175877094379694098">"Կարգավորումներ"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Տեղեկություններ"</string>
</resources>
diff --git a/PermissionController/res/values-hy-v34/strings.xml b/PermissionController/res/values-hy-v34/strings.xml
new file mode 100644
index 000000000..fb8997eb1
--- /dev/null
+++ b/PermissionController/res/values-hy-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-hy/strings.xml b/PermissionController/res/values-hy/strings.xml
index 02dbc7e9c..73742eb53 100644
--- a/PermissionController/res/values-hy/strings.xml
+++ b/PermissionController/res/values-hy/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"Միշտ թույլատրել բոլորը"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Հայտնաբերվել է էկրանի վրադրում"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Այս թույլտվության կարգավորումները փոխելու համար նախ անհրաժեշտ է անջատել էկրանի վրադրումը՝ անցնելով Կարգավորումներ &gt; Հավելվածներ"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Բացել կարգավորումները"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 օր}one{# օր}other{# օր}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 ժամ}one{# ժամ}other{# ժամ}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 րոպե}one{# րոպե}other{# րոպե}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 վրկ}one{# վրկ}other{# վրկ}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# օր}one{# օր}other{# օր}}"</string>
+ <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_time" msgid="3802087027301631827">"Ցանկացած ժամանակ"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Վերջին 7 օրում"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Վերջին 24 ժամում"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Վերջին ժամում"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Վերջին 15 րոպեում"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Վերջին 1 րոպեում"</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>
+ <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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"Չի օգտագործվել վերջին 24 ժամվա ընթացքում"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Չի օգտագործվել վերջին 7 օրվա ընթացքում"</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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"Միշտ թույլատրել բոլորը"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Ամեն անգամ հարցնել"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Չթույլատրել"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Ճշգրիտ տեղադրություն"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"«<xliff:g id="PERM_0">%1$s</xliff:g>» և «<xliff:g id="PERM_1">%2$s</xliff:g>» թույլտվությունները կհեռացվեն։"</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Հետևյալ թույլտվությունները կհեռացվեն՝ <xliff:g id="PERMS">%1$s</xliff:g>։"</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Թույլտվությունների ավտոմատ կառավարում"</string>
- <string name="off" msgid="1438489226422866263">"Անջատել"</string>
<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_tv_summary" msgid="3685907153054355671">"Եթե դուք մի քանի ամիս չեք օգտագործում հավելվածը.\n\n• թույլտվությունները հեռացվում են՝ ձեր տվյալները պաշտպանելու համար,\n• ժամանակավոր ֆայլերը հեռացվում են՝ տարածք ազատելու համար։\n\nԲացեք հավելվածը, որպեսզի նորից տրամադրեք թույլտվությունները։"</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Վերջին անգամ բացվել է ավելի քան <xliff:g id="NUMBER">%s</xliff:g> ամիս առաջ"</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>
<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>
@@ -251,9 +254,9 @@
<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{# օր}other{# օր}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 ժամ}one{# ժամ}other{# ժամ}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 րոպե}one{# րոպե}other{# րոպե}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 վայրկյան}one{# վայրկյան}other{# վայրկյան}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# ժամ}one{# ժամ}other{# ժամ}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# րոպե}one{# րոպե}other{# րոպե}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# վայրկյան}one{# վայրկյան}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>
@@ -262,6 +265,9 @@
<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>
+ <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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android համակարգ"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Հավելվածի թույլտվությունները հեռացվել են"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> հավելվածը մի քանի ամիս է, ինչ չի օգտագործվել։ Հպեք՝ մանրամասները տեսնելու համար։"</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> հավելվածն ու ևս 1 հավելված մի քանի ամիս է, ինչ չեն օգտագործվել։ Հպեք՝ մանրամասները տեսնելու համար։"</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"նշումներ"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"Կառավարվող թույլտվություններ"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Հավելվածին հասանելի են ձեր տեղադրության մասին տվյալները"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Ձեր ՏՏ ադմինիստրատորը <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"Անվտանգություն և գաղտնիություն"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Սկանավորել"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"Տվիչների թույլտվություններ"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Գաղտնիության կարգավորումներ"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"Թույլտվությունը հեռացվել է"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Դիտել տեսախցիկի օգտագործման այլ տվյալներ"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Դիտել խոսափողի օգտագործման այլ տվյալներ"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Հեռացնել տեսախցիկի օգտագործման թույլտվությունը"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Հեռացնել խոսափողի օգտագործման թույլտվությունը"</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="manage_service_qs" msgid="7862555549364153805">"Կառավարել ծառայությունը"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Կառավարել թույլտվությունները"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Օգտագործվում է հեռախոսազանգի ժամանակ"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Անվտանգություն և գաղտնիություն"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Ստուգեք կարգավիճակը"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Հաղորդակցում մշակողի հետ"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Թարմացվել է վերջին 1 օրվա ընթացքում}=1{Թարմացվել է վերջին 1 օրվա ընթացքում}one{Թարմացվել է վերջին # օրվա ընթացքում}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>
</resources>
diff --git a/PermissionController/res/values-in-v33/strings.xml b/PermissionController/res/values-in-v33/strings.xml
index 12fca9c79..b74e806df 100644
--- a/PermissionController/res/values-in-v33/strings.xml
+++ b/PermissionController/res/values-in-v33/strings.xml
@@ -19,4 +19,28 @@
<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 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>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Daftar. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Daftar. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Diperlukan tindakan. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Item daftar. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Tutup"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Luaskan dan tampilkan opsi"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Ciutkan"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Beralih. <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">"Tombol"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Buka"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Tinjau setelan"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Setelan"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Informasi"</string>
</resources>
diff --git a/PermissionController/res/values-in-v34/strings.xml b/PermissionController/res/values-in-v34/strings.xml
new file mode 100644
index 000000000..7e0c0a609
--- /dev/null
+++ b/PermissionController/res/values-in-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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">"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>
+</resources>
diff --git a/PermissionController/res/values-in/strings.xml b/PermissionController/res/values-in/strings.xml
index 3abf36afe..777933785 100644
--- a/PermissionController/res/values-in/strings.xml
+++ b/PermissionController/res/values-in/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Kembali"</string>
<string name="available" msgid="6007778121920339498">"Tersedia"</string>
<string name="blocked" msgid="9195547604866033708">"Diblokir"</string>
+ <string name="on" msgid="280241003226755921">"Aktif"</string>
+ <string name="off" msgid="1438489226422866263">"Nonaktif"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Uninstal atau nonaktifkan"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Apl tidak ditemukan"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Jangan izinkan"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Pertahankan \"Saat aplikasi digunakan\""</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Pertahankan \"Hanya kali ini\""</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Bagaimanapun jangan izinkan"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Tutup"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> dari <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -107,9 +114,6 @@
<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="screen_overlay_title" msgid="6977038513913222078">"Hamparan layar terdeteksi"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Untuk mengubah setelan izin ini, terlebih dahulu Anda harus menonaktifkan hamparan layar dari Setelan &gt; Aplikasi"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Buka setelan"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Linimasa penggunaan <xliff:g id="PERMGROUP">%1$s</xliff:g> Anda oleh aplikasi dalam 7 hari terakhir"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Saat aplikasi ini menggunakan izin <xliff:g id="PERMGROUP">%1$s</xliff:g> Anda"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Pelajari lebih lanjut"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Pelajari <xliff:g id="PERMGROUP">%1$s</xliff:g> lebih lanjut"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Kontrol akses aplikasi ke <xliff:g id="PERMGROUP">%1$s</xliff:g> Anda"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 hari}other{# hari}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 jam}other{# jam}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 mnt}other{# mnt}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 dtk}other{# dtk}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# hari}other{# hari}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# jam}other{# jam}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# menit}other{# menit}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# detik}other{# detik}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Izin apa pun"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Kapan saja"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"7 hari terakhir"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"24 jam terakhir"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"1 jam terakhir"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"15 menit terakhir"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"1 menit terakhir"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{# hari terakhir}other{# hari terakhir}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{# jam terakhir}other{# jam terakhir}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{# menit terakhir}other{# menit terakhir}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Tidak ada penggunaan izin"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Akses terbaru kapan saja"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Akses terbaru dalam 7 hari terakhir"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Penggunaan izin dalam 1 jam terakhir"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Penggunaan izin dalam 15 menit terakhir"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Penggunaan izin dalam 1 menit terakhir"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Tidak digunakan dalam 24 jam terakhir"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Tidak digunakan dalam 7 hari terakhir"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Tidak digunakan dalam # hari terakhir}other{Tidak digunakan dalam # hari terakhir}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Tidak digunakan dalam # jam terakhir}other{Tidak digunakan dalam # jam terakhir}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Digunakan 1 aplikasi}other{Digunakan # aplikasi}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Lihat semua di Dasbor"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Difilter menurut: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,9 +188,10 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Izinkan akses hanya ke media"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Izinkan sepanjang waktu"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Izinkan hanya saat aplikasi digunakan"</string>
+ <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 presisi"</string>
<string name="app_permission_location_accuracy_subtitle" msgid="2654077606404987210">"Saat lokasi presisi dinonaktifkan, aplikasi dapat mengakses perkiraan lokasi"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Izin <xliff:g id="PERM_0">%1$s</xliff:g> dan <xliff:g id="PERM_1">%2$s</xliff:g> akan dihapus."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Izin yang akan dihapus: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Kelola izin secara otomatis"</string>
- <string name="off" msgid="1438489226422866263">"Nonaktif"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Izin <xliff:g id="PERMISSION_NAME">%s</xliff:g> dihapus"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Izin <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> dan <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> dihapus"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> dan <xliff:g id="NUMBER">%2$s</xliff:g> izin lainnya dihapus"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Aplikasi yang tidak digunakan"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Jika aplikasi tidak digunakan selama beberapa bulan:\n\n• Izin akan dihapus untuk melindungi data Anda\n• Notifikasi akan dihentikan untuk menghemat daya baterai\n• File sementara akan dihapus untuk mengosongkan ruang penyimpanan\n\nUntuk kembali memberikan izin dan mengaktifkan notifikasi, buka aplikasi."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Jika aplikasi tidak digunakan selama beberapa bulan:\n\n• Izin akan dihapus untuk melindungi data Anda\n• File sementara akan dihapus untuk mengosongkan ruang penyimpanan\n\nUntuk kembali memberikan izin, buka aplikasi."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Terakhir dibuka lebih dari <xliff:g id="NUMBER">%s</xliff:g> bulan lalu"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Jika aplikasi tidak digunakan selama satu bulan:\n\n• Izin akan dihapus untuk melindungi data Anda\n• File sementara akan dihapus untuk mengosongkan ruang penyimpanan\n\nUntuk kembali memberikan izin, buka aplikasi."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Terakhir dibuka lebih dari # bulan lalu}other{Terakhir dibuka lebih dari # bulan lalu}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Aplikasi terakhir dibuka pada <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Terakhir dibuka <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Jika Anda mengizinkan pengelolaan semua file, aplikasi ini dapat mengakses, mengubah, dan menghapus file di penyimpanan umum pada perangkat ini atau perangkat penyimpanan yang terhubung. Aplikasi dapat mengakses file tanpa bertanya kepada Anda."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Tidak diizinkan"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Lihat aplikasi lain yang dapat mengakses semua file"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 hari}other{# hari}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 jam}other{# jam}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 menit}other{# menit}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 detik}other{# detik}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# jam}other{# jam}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# menit}other{# menit}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# detik}other{# detik}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Pengingat izin"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 aplikasi yang tidak digunakan"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> aplikasi tidak digunakan"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Beberapa aplikasi tidak digunakan dalam beberapa bulan. Ketuk untuk meninjau."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# aplikasi tidak digunakan}other{# aplikasi tidak digunakan}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Izin dan file sementara telah dihapus dan notifikasi dihentikan. Ketuk untuk meninjau."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Tinjau aplikasi yang izinnya dihapus"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Untuk aplikasi yang sudah lama tidak Anda gunakan, izin dan file sementara akan dihapus dan notifikasi akan dihentikan."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Tinjau aplikasi"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Periksa izin terbaru"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Saat mengemudi, Anda memberikan akses <xliff:g id="APP">%1$s</xliff:g> ke <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Saat mengemudi, Anda memberikan akses <xliff:g id="APP">%1$s</xliff:g> ke <xliff:g id="PERMISSION_1">%2$s</xliff:g> &amp; <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Izin dihapus untuk melindungi privasi Anda"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> mendapatkan lokasi Anda di latar belakang"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Aplikasi ini selalu dapat mengakses lokasi Anda. Ketuk untuk mengubah."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Tinjau aplikasi yang memiliki akses ke notifikasi"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> dapat menutup, menindaklanjuti, dan mengakses konten di dalam notifikasi"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Aplikasi ini dapat menutup, menindaklanjuti, dan mengakses konten di dalam notifikasi. Beberapa aplikasi memerlukan akses ini agar dapat berfungsi sebagaimana mestinya."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Hapus akses"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Lihat opsi lainnya"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Akses dihapus"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Tinjau aplikasi yang memiliki akses perangkat penuh"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> dapat melihat layar dan melakukan tindakan di perangkat. Aplikasi aksesibilitas memerlukan jenis akses ini agar dapat berfungsi sebagaimana mestinya."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Aplikasi ini dapat melihat layar dan melakukan tindakan di perangkat. Aplikasi aksesibilitas memerlukan jenis akses ini agar dapat berfungsi sebagaimana mestinya, tetapi periksa aplikasi dan pastikan Anda memercayainya."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Hapus akses"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Lihat aplikasi yang memiliki akses penuh"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Akses dihapus"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Sistem Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Izin aplikasi dihapus untuk melindungi privasi"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> belum digunakan dalam beberapa bulan. Ketuk untuk meninjau."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> dan 1 aplikasi lainnya belum digunakan dalam beberapa bulan. Ketuk untuk meninjau."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan mengakses izin Telepon, SMS, Kontak, dan Kalender."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan men-streaming aplikasi ke perangkat terhubung."</string>
<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 untuk membuat catatan di perangkat"</string>
+ <string name="role_notes_search_keywords" msgid="7710756695666744631">"catatan"</string>
<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>
@@ -452,6 +475,7 @@
<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_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_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_microphone" msgid="2825208549114811299">"Izinkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; merekam audio?"</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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Izin terkontrol"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Lokasi dapat diakses"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Admin IT mengizinkan <xliff:g id="APP_NAME">%s</xliff:g> untuk mengakses lokasi Anda"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Untuk aplikasi dan layanan"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Data mikrofon mungkin tetap dibagikan saat Anda menelepon nomor darurat."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Ubah"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Keamanan &amp; Privasi"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Pindai"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Keamanan &amp; privasi"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Pindai perangkat"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Tutup"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Tutup peringatan ini?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Tinjau setelan keamanan dan privasi Anda kapan saja untuk meningkatkan perlindungan"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Tutup"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Batal"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Setelan"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Status keamanan dan privasi. <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">"Setelan Keamanan"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Izin Sensor"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Kontrol Privasi"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Izin"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Keamanan &amp; privasi"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Periksa status"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Kontrol privasi Anda"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Setelan lainnya"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Akses kamera"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Akses mikrofon"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Izin dihapus"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Lihat penggunaan kamera lainnya"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Lihat penggunaan mikrofon lainnya"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Hapus izin kamera"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Hapus izin mikrofon"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Lihat penggunaan kamera terbaru"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Lihat penggunaan mikrofon terbaru"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Hapus izin untuk aplikasi ini"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Hapus izin untuk aplikasi ini"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Kelola layanan"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Kelola izin"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Sedang digunakan untuk panggilan telepon"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Baru-baru ini digunakan oleh <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">"Sedang digunakan oleh <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">"Baru-baru ini digunakan oleh <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Keamanan &amp; Privasi"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Periksa status"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Konfirmasi"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Kembali"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Akses ke file lainnya juga akan diizinkan"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Aplikasi ini tidak mendukung versi terbaru Android. Jika tidak dapat mengakses file musik dan audio, aplikasi ini juga tidak akan diizinkan mengakses foto dan video."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Aplikasi ini tidak mendukung versi terbaru Android. Jika dapat mengakses foto dan video, aplikasi ini juga akan diizinkan mengakses file musik dan audio."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Aplikasi ini tidak mendukung versi terbaru Android. Jika tidak dapat mengakses file musik dan audio, aplikasi ini juga tidak akan diizinkan mengakses foto dan video."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Tinjau aplikasi yang memiliki akses lokasi latar belakang"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> dapat selalu mengakses lokasi Anda, bahkan saat aplikasi ditutup"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Tinjau aplikasi yang memiliki akses lokasi latar belakang"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Aplikasi ini dapat selalu mengakses lokasi Anda, bahkan saat aplikasi ditutup.\n\nBeberapa aplikasi keselamatan dan keadaan darurat memerlukan akses lokasi Anda di latar belakang agar dapat berfungsi sebagaimana mestinya."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Akses diubah"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Lihat penggunaan lokasi terbaru"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Kontrol privasi"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Akses kamera"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Akses mikrofon"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Untuk aplikasi dan layanan"</string>
+ <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">"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">"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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Praktik data dapat berbeda-beda berdasarkan versi aplikasi, penggunaan, wilayah, dan usia Anda. "<annotation id="link">"Selengkapnya tentang berbagi data"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Praktik data dapat berbeda-beda berdasarkan versi aplikasi, penggunaan, wilayah, dan usia Anda."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Data lokasi Anda"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Ubah akses aplikasi ini di "<annotation id="link">"setelan privasi"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Fungsi aplikasi"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analisis"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Komunikasi developer"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Iklan atau pemasaran"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Pencegahan penipuan, keamanan, dan kepatuhan"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalisasi"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Pengelolaan akun"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Developer aplikasi ini memberikan info tentang praktik berbagi data mereka kepada app store. Developer dapat memperbaruinya dari waktu ke waktu.\n\nPraktik berbagi data mungkin berbeda-beda berdasarkan versi aplikasi, penggunaan, wilayah, dan usia Anda."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Pelajari berbagi data"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Data lokasi Anda kini dibagikan kepada pihak ketiga"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Data lokasi Anda kini dibagikan kepada pihak ketiga untuk tujuan iklan atau pemasaran"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Diperbarui kemarin}=1{Diperbarui kemarin}other{Diperbarui dalam # hari}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Tidak ada pembaruan saat ini"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-is-v33/strings.xml b/PermissionController/res/values-is-v33/strings.xml
index f1e280ed6..3f7695027 100644
--- a/PermissionController/res/values-is-v33/strings.xml
+++ b/PermissionController/res/values-is-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Þetta forrit fær leyfi til að senda þér tilkynningar og fær aðgang að myndavélinni, tengiliðunum, hljóðnemanum, símanum og SMS-skilaboðum"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Þetta forrit fær leyfi til að senda þér tilkynningar og fær aðgang að myndavélinni, tengiliðunum, skrám hljóðnemanum, símanum og SMS-skilaboðum"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Forrit með þessa heimild hafa aðgang að öllum skrám í þessu tæki"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Upplýsingar um vinnureglurnar þínar"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Kerfisstjóri stjórnar stillingum"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Stækka og sýna lista"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Draga lista saman og fela stillingar"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Listi. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Listi. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Aðgerða þörf. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Listaatriði. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Loka"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Stækka og sýna valkosti"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Minnka"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Rofi. <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">"Kveikja/slökkva"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Opna"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Yfirfara stillingar"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Stillingar"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Upplýsingar"</string>
</resources>
diff --git a/PermissionController/res/values-is-v34/strings.xml b/PermissionController/res/values-is-v34/strings.xml
new file mode 100644
index 000000000..b897bcc71
--- /dev/null
+++ b/PermissionController/res/values-is-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Öryggi og persónuvernd"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Stýringar"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Heilsutenging"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Stjórna aðgangi forrita að heilsufarsgögnum"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Aðgangur að staðsetningu"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"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="6846532794702613851">"Fyrir forrit og þjónustur"</string>
+</resources>
diff --git a/PermissionController/res/values-is/strings.xml b/PermissionController/res/values-is/strings.xml
index 7e6445b95..ab698d6ab 100644
--- a/PermissionController/res/values-is/strings.xml
+++ b/PermissionController/res/values-is/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Til baka"</string>
<string name="available" msgid="6007778121920339498">"Tiltækt"</string>
<string name="blocked" msgid="9195547604866033708">"Lokað á"</string>
+ <string name="on" msgid="280241003226755921">"Kveikt"</string>
+ <string name="off" msgid="1438489226422866263">"Slökkt"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Fjarlægja eða slökkva"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Forritið finnst ekki"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Ekki leyfa"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Halda „Þegar forritið er í notkun“"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Halda „Aðeins í þetta skipti“"</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Ekki leyfa þrátt fyrir það"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Loka"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> af <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Skjáyfirlögn greindist"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Til að breyta þessari heimildarstillingu þarftu fyrst að slökkva á skjáyfirlögn undir Stillingar &gt; Forrit"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Opna stillingar"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Tímalína yfir notkun forrita á <xliff:g id="PERMGROUP">%1$s</xliff:g> síðastliðna 7 daga"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Hvenær þetta forrit notaði heimildina „<xliff:g id="PERMGROUP">%1$s</xliff:g>“"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Frekari upplýsingar"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Nánar um <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Stjórna aðgangi forrita að <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 dagur}one{# dagur}other{# dagar}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 klukkustund}one{# klukkustund}other{# klukkustundir}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 mín.}one{# mín.}other{# mín.}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 sek.}one{# sek.}other{# sek.}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# dagur}one{# dagur}other{# dagar}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# klukkustund}one{# klukkustund}other{# klukkustundir}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# mín.}one{# mín.}other{# mín.}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# sek.}one{# sek.}other{# sek.}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Hvaða heimild sem er"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Hvenær sem er"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Síðustu sjö daga"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Síðasti sólarhringur"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Síðustu klukkustund"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Síðustu 15 mínútur"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Síðasta mínúta"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Undanfarinn # dag}one{Undanfarinn # dag}other{Undanfarna # daga}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Síðustu # klst.}one{Síðustu # klst.}other{Síðustu # klst.}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Síðasta # mín.}one{Síðustu # mín.}other{Síðustu # mín.}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Engin heimildanotkun"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Síðasti aðgangur, hvenær sem er"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Síðasti aðgangur síðustu 7 daga"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Heimildanotkun síðustu klukkustund"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Heimildanotkun síðustu 15 mínútur"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Heimildanotkun síðustu mínútu"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Ekki notað síðasta sólarhringinn"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Ekki notað síðastliðna 7 daga"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Ekki notað undanfarinn # dag}one{Ekki notað undanfarinn # dag}other{Ekki notað undanfarna # daga}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Ekki notað síðustu # klst.}one{Ekki notað síðustu # klst.}other{Ekki notað síðustu # klst.}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Notað af 1 forriti}one{Notað af # forriti}other{Notað af # forritum}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Sjá allt á stjórnborði"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Síað eftir: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Leyfa aðeins aðgang að margmiðlunarefni"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Leyfa alltaf"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Leyfa aðeins þegar forritið er í notkun"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Alltaf leyfa allt"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Spyrja alltaf"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Ekki leyfa"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Nákvæm staðsetning"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> og <xliff:g id="PERM_1">%2$s</xliff:g> heimildir verða fjarlægðar."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Heimildir sem verða fjarlægðar: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Stjórna heimildum sjálfkrafa"</string>
- <string name="off" msgid="1438489226422866263">"Slökkt"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Heimild fyrir <xliff:g id="PERMISSION_NAME">%s</xliff:g> fjarlægð"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Heimildirnar <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> og <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> fjarlægðar"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> og <xliff:g id="NUMBER">%2$s</xliff:g> heimildir í viðbót voru fjarlægðar"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Ónotuð forrit"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Ef forrit er ekki notað í nokkra mánuði:\n\n• Heimildir eru fjarlægðar til að vernda gögnin þín\n• Slökkt er á tilkynningum til að spara rafhlöðu\n• Tímabundnar skrár eru fjarlægðar til að losa um pláss\n\nOpnaðu forritið til að leyfa heimildir og tilkynningar að nýju."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Ef forrit er ekki notað í nokkra mánuði:\n\n• Heimildir eru fjarlægðar til að vernda gögnin þín\n• Tímabundnar skrár eru fjarlægðar til að losa um pláss\n\nOpnaðu forritið til að leyfa heimildir og tilkynningar að nýju."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Síðast opnað fyrir meira en <xliff:g id="NUMBER">%s</xliff:g> mánuðum"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Ef forrit er ekki notað í mánuð:\n\n• Heimildir eru fjarlægðar til að vernda gögnin þín\n• Tímabundnar skrár eru fjarlægðar til að losa um pláss\n\nOpnaðu forritið til að leyfa heimildir og tilkynningar að nýju."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Síðast opnað fyrir meira en # mánuði}one{Síðast opnað fyrir meira en # mánuði}other{Síðast opnað fyrir meira en # mánuðum}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Forrit síðast opnað <xliff:g id="DATE">%s</xliff:g>"</string>
<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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Ekki heimilað"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Sjá fleiri forrit sem geta opnað allar skrár"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 dagur}one{# dagur}other{# dagar}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 klukkustund}one{# klukkustund}other{# klukkustundir}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 mínúta}one{# mínúta}other{# mínútur}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 sekúnda}one{# sekúnda}other{# sekúndur}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# klukkustund}one{# klukkustund}other{# klukkustundir}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# mínúta}one{# mínúta}other{# mínútur}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# sekúnda}one{# sekúnda}other{# sekúndur}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Áminningar um heimild"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 ónotað forrit"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> ónotuð forrit"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Sum forrit hafa ekki verið notuð í nokkra mánuði. Ýttu til að skoða."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# ónotað forrit}one{# ónotað forrit}other{# ónotuð forrit}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Heimildir og tímabundnar skrár voru fjarlægðar og slökkt var á tilkynningum. Ýttu til að skoða."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Yfirfara forrit með fjarlægðar heimildir"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Heimildir og tímabundnar skrár voru fjarlægðar fyrir forrit sem þú hefur ekki notað um hríð og lokað var fyrir tilkynningar."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Fara yfir forrit"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Skoða nýlegar heimildir"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Þú veittir <xliff:g id="APP">%1$s</xliff:g> aðgang að <xliff:g id="PERMISSION">%2$s</xliff:g> við akstur"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Þú veittir <xliff:g id="APP">%1$s</xliff:g> aðgang að <xliff:g id="PERMISSION_1">%2$s</xliff:g> og <xliff:g id="PERMISSION_2">%3$s</xliff:g> við akstur"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Heimildir fjarlægðar til að tryggja persónuvernd þína"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> er með staðsetningu þína í bakgrunni"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Þetta forrit hefur alltaf aðgang að staðsetningu þinni. Ýttu til að breyta."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Yfirfara forrit með aðgang að þínum tilkynningum"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> getur hunsað, brugðist við og nálgast efni í tilkynningunum þínum"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Þetta forrit getur hunsað, brugðist við og nálgast efni í tilkynningunum þínum. Sum forrit þurfa þessa gerð aðgangs til að virka rétt."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Fjarlægja aðgang"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Sjá fleiri valkosti"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Aðgangur fjarlægður"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Yfirfara forrit með fullan tækjaaðgang"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> getur skoðað skjáinn þinn og framkvæmt aðgerðir í tækinu þínu. Aðgengisforrit þurfa þessa gerð aðgangs til að virka rétt."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Þetta forrit getur skoðað skjáinn þinn og framkvæmt aðgerðir í tækinu þínu. Aðgengisforrit þurfa þessa gerð aðgangs til að virka rétt en gott er að skoða forritið og athuga hvort því er treystandi."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Fjarlægja aðgang"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Skoða forrit með fullan aðgang"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Aðgangur fjarlægður"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android kerfið"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Heimildir forrits fjarlægðar vegna persónuverndar"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> hefur ekki verið notað í nokkra mánuði. Ýttu til að skoða."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> og eitt forrit í viðbót hafa ekki verið notuð í nokkra mánuði. Ýttu til að skoða."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> fær aðgang að tilkynningum og heimildum síma, SMS, tengiliða og dagatals."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> getur brugðist við tilkynningunum þínum og streymt forritunum þínum í tengda tækinu."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Þessi þjónusta deilir myndum, efni og tilkynningum frá þér úr símanum þínum til annarra tækja."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Sjálfgefið glósuforrit"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Stýrðar heimildir"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Hægt er að nálgast upplýsingar um staðsetningu"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Kerfisstjórinn þinn leyfir forritinu „<xliff:g id="APP_NAME">%s</xliff:g>“ að fá upplýsingar um staðsetningu þína"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Fyrir forrit og þjónustu"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Hljóðnemagögnum er þó hugsanlega deilt þegar hringt er í neyðarnúmer."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Breyta"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Öryggi og persónuvernd"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Leita"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Öryggi og persónuvernd"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Skanna tæki"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Hunsa"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Hunsa þessa viðvörun?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Þú getur hvenær sem er farið yfir öryggis- og persónuverndarstillingarnar til að auka vernd þína"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Hunsa"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Hætta við"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Stillingar"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Staða öryggis og persónuverndar. <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">"Öryggisstillingar"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Skynjaraheimildir"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Persónuverndarstillingar"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Heimildir"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Öryggi og persónuvernd"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Athuga stöðu"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Persónuverndarstillingar þínar"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Fleiri stillingar"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Aðgangur að myndavél"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Aðgangur að hljóðnema"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Heimild fjarlægð"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Sjá meiri myndavélarnotkun"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Sjá meiri hljóðnemanotkun"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Fjarlægja myndavélarheimild"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Fjarlægja hljóðnemaheimild"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Skoða nýlega myndavélanotkun"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Skoða nýlega hljóðnemanotkun"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Fjarlægja heimild fyrir þetta forrit"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Fjarlægja heimild fyrir þetta forrit"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Stjórna þjónustu"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Stjórna heimildum"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Notað í símtali"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Nýlega notað af <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">"Notað af <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">"Nýlega notað af <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Öryggi og persónuvernd"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Athuga stöðu"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Staðfesta"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Til baka"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Aðgangur að öðrum skrám verður einnig leyfður"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Þetta forrit styður ekki nýjustu útgáfu Android. Ef forritið hefur ekki aðgang að tónlist og hljóðskrám fær það ekki heldur aðgang að myndum og myndskeiðum."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Þetta forrit styður ekki nýjustu útgáfu Android. Ef forritið hefur aðgang að myndum og myndskeiðum fær það einnig aðgang að tónlist og hljóðskrám."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Þetta forrit styður ekki nýjustu útgáfu Android. Ef forritið hefur ekki aðgang að tónlist og hljóðskrám fær það ekki heldur aðgang að myndum og myndskeiðum."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Yfirfara forrit með aðgang að bakgrunnsstaðsetningu"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> hefur alltaf aðgang að staðsetningunni þinni, jafnvel þegar forritið er lokað"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Yfirfara forrit með aðgang að bakgrunnsstaðsetningu"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Þetta forrit hefur alltaf aðgang að staðsetningu þinni, líka þegar það er lokað.\n\nTiltekin öryggis- og neyðarforrit verða að fá aðgang að staðsetningu þinni í bakgrunni til að virka sem skyldi."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Aðgangi breytt"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Skoða nýlega notkun á staðsetningu"</string>
+ <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ó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>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Birta skilaboð þegar forrit fá aðgang að texta, myndum eða öðru efni sem þú hefur afritað"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Sýna aðgangsorð"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Birta stafi í stutta stund þegar þú skrifar"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Gagnameðhöndlun getur verið breytileg miðað við útgáfu forritsins, notkun, svæði og aldur notandans. "<annotation id="link">"Nánar um gagnadeilingu"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Gagnameðhöndlun getur verið breytileg miðað við útgáfu forritsins, notkun, svæði og aldur notandans."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Staðsetningargögnin þín"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Breyttu aðgangi þessa forrits í "<annotation id="link">"persónuverndarstillingunum"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Forritseiginleikar"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Greining"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Hafa samskipti við þróunaraðila"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Auglýsingar eða markaðssetning"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Svikavörn, öryggi og reglufylgni"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Sérstillingar"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Reikningsstjórnun"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Þróunaraðilar þessa forrits veittu forritaverslun upplýsingar um vinnureglur sínar varðandi gagnadeilingu. Viðkomandi aðilar kunna að uppfæra upplýsingarnar síðar.\n\nVinnureglur varðandi gagnadeilingu geta verið mismunandi eftir útgáfu forrits, notkun, svæði og aldri notanda."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Nánar um gagnadeilingu"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Staðsetningargögnunum þínum er nú deilt með þriðju aðilum"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Staðsetningargögnunum þínum er nú deilt með þriðju aðilum í auglýsinga- eða markaðssetningartilgangi"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Uppfært innan síðasta sólarhrings}=1{Uppfært innan síðasta sólarhrings}one{Uppfært innan # dags}other{Uppfært innan # daga}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Engar uppfærslur eins og er"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-it-v33/strings.xml b/PermissionController/res/values-it-v33/strings.xml
index ce187823e..66187fa98 100644
--- a/PermissionController/res/values-it-v33/strings.xml
+++ b/PermissionController/res/values-it-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"L\'app sarà autorizzata a inviarti notifiche e ad accedere a Fotocamera, Contatti, Microfono, Telefono e SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"L\'app sarà autorizzata a inviarti notifiche e ad accedere a fotocamera, contatti, file, microfono, telefono e SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Le app con questa autorizzazione possono accedere a tutti i file su questo dispositivo"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Informazioni sulle norme di lavoro"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Impostazioni gestite dall\'amministratore IT"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Espandi e visualizza elenco"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Comprimi elenco e nascondi impostazioni"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Elenco. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Elenco. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Azioni richieste. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Voce elenco. <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">"Altri avvisi"</string>
+ <string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Avvisi chiusi"</string>
+ <string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Espandi e visualizza un altro avviso}many{Espandi e visualizza altri # avvisi}other{Espandi e visualizza altri # avvisi}}"</string>
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Avviso. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
+ <string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Azione completata"</string>
+ <string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Controlla le impostazioni che possono proteggere meglio il tuo dispositivo"</string>
+ <string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Impostazioni rapide di sicurezza e privacy"</string>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Chiudi"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Espandi e mostra le opzioni"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Comprimi"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Opzione. <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">"Attiva/disattiva"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Apri"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Verifica le impostazioni"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Impostazioni"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Informazioni"</string>
</resources>
diff --git a/PermissionController/res/values-it-v34/strings.xml b/PermissionController/res/values-it-v34/strings.xml
new file mode 100644
index 000000000..27da7e634
--- /dev/null
+++ b/PermissionController/res/values-it-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Sicurezza e privacy"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Controlli"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Connessione Salute"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Gestisci l\'accesso delle app ai dati sulla salute"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Accesso alla posizione"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Per app e servizi. Se questa impostazione viene disattivata, i dati del microfono potrebbero comunque essere condivisi quando chiami un numero di emergenza"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Per app e servizi"</string>
+</resources>
diff --git a/PermissionController/res/values-it/strings.xml b/PermissionController/res/values-it/strings.xml
index d5c9a19cc..d8aecd780 100644
--- a/PermissionController/res/values-it/strings.xml
+++ b/PermissionController/res/values-it/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Indietro"</string>
<string name="available" msgid="6007778121920339498">"Disponibile"</string>
<string name="blocked" msgid="9195547604866033708">"Bloccato"</string>
+ <string name="on" msgid="280241003226755921">"On"</string>
+ <string name="off" msgid="1438489226422866263">"Off"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Disinstalla o disattiva"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"App non trovata"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Non consentire"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Mantieni \"Mentre l\'app è in uso\""</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Mantieni solo questa volta"</string>
<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_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 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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Overlay schermo rilevato"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Per modificare questa impostazione di autorizzazione, devi innanzitutto disattivare l\'overlay schermo da Impostazioni &gt; App"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Apri impostazioni"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Cronologia delle volte in cui le app hanno usato <xliff:g id="PERMGROUP">%1$s</xliff:g> negli ultimi 7 giorni"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Quando questa app ha usato l\'autorizzazione <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Scopri di più"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Informazioni su <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Controlla l\'accesso dell\'app al gruppo <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 giorno}many{# giorni}other{# giorni}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 ora}many{# ore}other{# ore}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}many{# min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 sec}many{# sec}other{# sec}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# giorno}many{# giorni}other{# giorni}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# ora}many{# ore}other{# ore}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}many{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# sec}many{# sec}other{# sec}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Qualsiasi autorizzazione"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Qualsiasi data"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Ultimi 7 giorni"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Ultime 24 ore"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Ultima ora"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Ultimi 15 minuti"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Ultimo minuto"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Ultimo giorno}many{Ultimi # giorni}other{Ultimi # giorni}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Ultima ora}many{Ultime # ore}other{Ultime # ore}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Ultimo minuto}many{Ultimi # minuti}other{Ultimi # minuti}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Autorizzazioni non usate"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Accesso più recente in qualsiasi momento"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Accesso più recente negli ultimi 7 giorni"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Uso autorizzazioni nell\'ultima ora"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Uso autorizzazioni negli ultimi 15 minuti"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Uso autorizzazioni nell\'ultimo minuto"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Autorizzazione non utilizzata nelle ultime 24 ore"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Autorizzazione non utilizzata negli ultimi 7 giorni"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Autorizzazione non utilizzata nell\'ultimo giorno}many{Autorizzazione non utilizzata negli ultimi # giorni}other{Autorizzazione non utilizzata negli ultimi # giorni}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Autorizzazione non utilizzata nell\'ultima ora}many{Autorizzazione non utilizzata nelle ultime # ore}other{Autorizzazione non utilizzata nelle ultime # ore}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Autorizzazione usata da 1 app}many{Autorizzazione usata da # app}other{Autorizzazione usata da # app}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Mostra tutto nella Dashboard"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrata per: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Consenti l\'accesso solo ai file multimediali"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Consenti sempre"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Consenti solo mentre l\'app è in uso"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Consenti sempre tutti"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Chiedi ogni volta"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Non consentire"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Posizione esatta"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Le autorizzazioni <xliff:g id="PERM_0">%1$s</xliff:g> e <xliff:g id="PERM_1">%2$s</xliff:g> verranno rimosse."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Autorizzazioni che verranno rimosse: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Gestisci autorizzazioni automaticamente"</string>
- <string name="off" msgid="1438489226422866263">"Off"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Autorizzazione <xliff:g id="PERMISSION_NAME">%s</xliff:g> rimossa"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Autorizzazioni <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> e <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> rimosse"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> e altre <xliff:g id="NUMBER">%2$s</xliff:g> autorizzazioni rimosse"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"App inutilizzate"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Se un\'app non viene usata per alcuni mesi:\n\n• Vengono rimosse le autorizzazioni per proteggere i tuoi dati\n• Vengono interrotte le notifiche per risparmiare batteria\n• Vengono rimossi i file temporanei per liberare spazio\n\nApri l\'app per consentire di nuovo autorizzazioni e notifiche."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Se un\'app non viene usata per alcuni mesi:\n\n• vengono rimosse le autorizzazioni per proteggere i tuoi dati;\n• vengono rimossi i file temporanei per liberare spazio.\n\nApri l\'app per consentire di nuovo le autorizzazioni."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Aperte l\'ultima volta più di <xliff:g id="NUMBER">%s</xliff:g> mesi fa"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Se un\'app non viene usata per un mese:\n\n• Vengono rimosse le autorizzazioni per proteggere i tuoi dati\n• Vengono rimossi i file temporanei per liberare spazio\n\nApri l\'app per consentire di nuovo le autorizzazioni."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Aperte l\'ultima volta più di # mese fa}many{Aperte l\'ultima volta più di # mesi fa}other{Aperte l\'ultima volta più di # mesi fa}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Ultimo utilizzo dell\'app: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Ultimo utilizzo: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Se consenti la gestione di tutti i file, questa app potrà accedere, modificare ed eliminare tutti i file salvati in spazi di archiviazione comuni su questo dispositivo o su qualsiasi dispositivo di archiviazione connesso. L\'app potrà accedere ai file senza informarti."</string>
@@ -242,18 +245,18 @@
<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="3447767892295843282">"{count,plural, =1{1 ora}many{# ore}other{# ore}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minuto}many{# minuti}other{# minuti}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 secondo}many{# secondi}other{# secondi}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# ora}many{# ore}other{# ore}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minuto}many{# minuti}other{# minuti}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# secondo}many{# secondi}other{# secondi}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Promemoria autorizzazione"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 app inutilizzata"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> app inutilizzate"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Alcune app non sono state usate per alcuni mesi. Tocca per controllare."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# app inutilizzata}many{# app inutilizzate}other{# app inutilizzate}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Le autorizzazioni e i file temporanei sono stati rimossi; le notifiche sono state interrotte. Tocca per controllare."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Controlla le app di cui sono state rimosse le autorizzazioni"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Per le app che non usi da un po\' di tempo sono stati rimossi i file temporanei e le autorizzazioni e sono state interrotte le notifiche."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Controlla le app"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Controlla le autorizzazioni recenti"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Durante la guida, hai consentito all\'app <xliff:g id="APP">%1$s</xliff:g> di accedere a <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Durante la guida, hai consentito all\'app <xliff:g id="APP">%1$s</xliff:g> di accedere a <xliff:g id="PERMISSION_1">%2$s</xliff:g> e <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Autorizzazioni rimosse per proteggere la tua privacy"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> ha recuperato la tua posizione in background"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Questa app può accedere sempre alla tua posizione. Tocca per modificare."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Controlla l\'app con accesso alle tue notifiche"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> può ignorare i contenuti, intervenire su questi ultimi e accedervi all\'interno delle notifiche"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Questa app può intervenire sui contenuti, ignorarli e accedervi all\'interno delle notifiche. Alcune app richiedono questo accesso per poter funzionare come previsto."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Rimuovi accesso"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Vedi altre opzioni"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Accesso rimosso"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Controlla l\'app con accesso completo al dispositivo"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"L\'app <xliff:g id="APP_NAME">%s</xliff:g> può vedere il tuo schermo e compiere azioni sul tuo dispositivo. Le app di accessibilità hanno bisogno di questo tipo di accesso per poter funzionare come previsto."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Questa app può vedere il tuo schermo e compiere azioni sul tuo dispositivo. Le app di accessibilità hanno bisogno di questo tipo di accesso per poter funzionare come previsto, ma controlla l\'app e assicurati che sia attendibile."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Rimuovi accesso"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Visualizza app con accesso completo"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Accesso rimosso"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Sistema Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Autorizzazioni app rimosse per proteggere la privacy"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"L\'app <xliff:g id="APP_NAME">%s</xliff:g> non è stata utilizzata per alcuni mesi. Tocca per controllare."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"L\'app <xliff:g id="APP_NAME">%s</xliff:g> e un\'altra app non sono state utilizzate per alcuni mesi. Tocca per controllare."</string>
@@ -319,7 +338,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>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> potrà interagire con le tue notifiche e accedere a telefono, SMS, contatti e calendario."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> potrà interagire con le tue notifiche e trasmettere le tue app al dispositivo connesso."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Questo servizio condivide le tue foto, i tuoi contenuti multimediali e le tue notifiche dal telefono ad altri dispositivi."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"App per le note predefinita"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Autorizzazioni controllate"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"È possibile accedere alla posizione"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"L\'amministratore IT consentirà all\'app <xliff:g id="APP_NAME">%s</xliff:g> di accedere alla tua posizione"</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>
<string name="other_permissions_label" msgid="8986184335503271992">"Altre autorizzazioni"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Autorizzazione usata dal sistema"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Autorizzazioni usate soltanto dalle applicazioni di sistema."</string>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Per app e servizi"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"I dati del microfono potrebbero comunque essere condivisi quando chiami un numero di emergenza."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Cambia"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Sicurezza e privacy"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Analizza"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Sicurezza e privacy"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Analizza il dispositivo"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Ignora"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Vuoi ignorare questo avviso?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Esamina in qualsiasi momento le Impostazioni di sicurezza e privacy per aumentare la protezione"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Ignora"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Annulla"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Impostazioni"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Stato relativo a sicurezza e privacy. <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">"Impostazioni di sicurezza"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Autorizzaz. accesso ai sensori"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Controlli per la privacy"</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 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>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Accesso al microfono"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Autorizzazione rimossa"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Scopri ulteriore utilizzo della fotocamera"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Scopri ulteriore utilizzo del microfono"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Rimuovi autorizzazione di accesso alla fotocamera"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Rimuovi autorizzazione di accesso al microfono"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Visualizza uso recente della fotocamera"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Visualizza uso recente del microfono"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Rimuovi l\'autorizzazione per questa app"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Rimuovi l\'autorizzazione per questa app"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Gestisci servizio"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Gestire le autorizzazioni"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Attualmente in uso per la telefonata"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Recentemente in uso per <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">"Attualmente in uso da <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">"Recentemente in uso per <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Sicurezza e privacy"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Verifica stato"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Conferma"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Indietro"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Sarà consentito l\'accesso anche ad altri file"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Questa app non supporta l\'ultima versione di Android. Se questa app non può accedere a file audio e musicali, non potrà accedere neanche a foto e video."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Questa app non supporta l\'ultima versione di Android. Se questa app può accedere a foto e video, potrà accedere anche a file audio e musicali."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Questa app non supporta l\'ultima versione di Android. Se questa app non può accedere a file audio e musicali, non potrà accedere neanche a foto e video."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Controlla l\'app con accesso alla posizione in background"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"L\'app <xliff:g id="APP_NAME">%s</xliff:g> può accedere sempre alla tua posizione, anche quando è chiusa"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Controlla l\'app con accesso alla posizione in background"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Questa app può accedere sempre alla tua posizione, anche quando è chiusa.\n\nAlcune app di emergenza e per la sicurezza richiedono l\'accesso alla tua posizione in background per funzionare come previsto."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Accesso modificato"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Visualizza uso recente della posizione"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Controlli per la privacy"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Accesso alla fotocamera"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Accesso al microfono"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Per app e servizi"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Per app e servizi. Se questa impostazione viene disattivata, i dati del microfono potrebbero comunque essere condivisi quando chiami un numero di emergenza."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Visualizza le app e i servizi che hanno accesso alla posizione"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Mostra accesso agli appunti"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Viene mostrato un messaggio quando le app accedono a testo, immagini o altri contenuti che hai copiato"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Mostra password"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Mostra brevemente i caratteri durante la digitazione"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Le pratiche relative ai dati potrebbero variare in base alla versione e all\'utilizzo dell\'app, alla regione e all\'età. "<annotation id="link">"Scopri di più sulla condivisione dei dati"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Le pratiche relative ai dati potrebbero variare in base alla versione e all\'utilizzo dell\'app, alla regione e all\'età."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"I tuoi dati sulla posizione"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Cambia l\'accesso di questa app nelle "<annotation id="link">"impostazioni della privacy"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Funzionalità dell\'app"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analisi dei dati"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Comunicazioni dello sviluppatore"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Pubblicità o marketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Prevenzione di attività fraudolente, sicurezza e conformità"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalizzazione"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Gestione dell\'account"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Gli sviluppatori di queste app hanno fornito a uno store informazioni relative alle loro prassi di condivisione dei dati. Le informazioni potrebbero essere aggiornate nel tempo.\n\nLe prassi di condivisione dei dati potrebbero variare in base alla versione e all\'utilizzo dell\'app, alla regione e all\'età."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Scopri di più sulla condivisione dei dati"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Ora i tuoi dati sulla posizione vengono condivisi con terze parti"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Ora i tuoi dati sulla posizione vengono condivisi con terze parti per scopi pubblicitari o di marketing"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Aggiornamenti nelle ultime 24 ore}=1{Aggiornamenti nelle ultime 24 ore}many{Aggiornamenti negli ultimi # giorni}other{Aggiornamenti negli ultimi # giorni}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Nessun aggiornamento al momento"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-iw-v33/strings.xml b/PermissionController/res/values-iw-v33/strings.xml
index 13f53df5f..b94c5f360 100644
--- a/PermissionController/res/values-iw-v33/strings.xml
+++ b/PermissionController/res/values-iw-v33/strings.xml
@@ -19,4 +19,28 @@
<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="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>
+ <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>
+ <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{הרחבה וצפייה ב-# התראות נוספות}two{הרחבה וצפייה ב-# התראות נוספות}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"סגירה"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"הרחבה והצגת האפשרויות"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"כיווץ"</string>
+ <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_gear_label" msgid="5175877094379694098">"הגדרות"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"מידע"</string>
</resources>
diff --git a/PermissionController/res/values-iw-v34/strings.xml b/PermissionController/res/values-iw-v34/strings.xml
new file mode 100644
index 000000000..370a20dcb
--- /dev/null
+++ b/PermissionController/res/values-iw-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-iw/strings.xml b/PermissionController/res/values-iw/strings.xml
index e9f90bdb7..f261a0552 100644
--- a/PermissionController/res/values-iw/strings.xml
+++ b/PermissionController/res/values-iw/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,11 +32,16 @@
<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_always_allow_all" msgid="1719900027660252167">"אישור של הכול תמיד"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"זוהתה שכבת-על במסך"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"כדי לשנות את הגדרת ההרשאה הזו, קודם צריך לכבות את שכבת העל במסך ב\'הגדרות\' &gt; \'אפליקציות\'"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"פתיחת ההגדרות"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{יום אחד}one{# ימים}two{יומיים}other{# ימים}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{שעה אחת}one{# שעות}two{שעתיים}other{# שעות}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{דקה אחת}one{# דקות}two{# דקות}other{# דקות}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{שנייה אחת}one{# שניות}two{# שניות}other{# שניות}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{יום אחד}one{# ימים}two{יומיים}other{# ימים}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{שעה}one{# שעות}two{שעתיים}other{# שעות}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{דקה אחת}one{# דקות}two{# דקות}other{# דקות}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{שנייה אחת}one{# שניות}two{# שניות}other{# שניות}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"כל הרשאה שהיא"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"בכל עת"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"7 הימים האחרונים"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"ב-24 השעות החולפות"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"בשעה האחרונה"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"15 הדקות האחרונות"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"הדקה האחרונה"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{ביום האחרון}one{ב-# הימים האחרונים}two{ביומיים האחרונים}other{ב-# הימים האחרונים}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{בשעה האחרונה}one{ב-# השעות האחרונות}two{בשעתיים האחרונות}other{ב-# השעות האחרונות}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{בדקה האחרונה}one{ב-# הדקות האחרונות}two{ב-# הדקות האחרונות}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>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"שימוש בהרשאות בשעה האחרונה"</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">"שימוש בהרשאות בדקה האחרונה"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"לא נעשה שימוש ב-24 השעות האחרונות"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"לא נעשה שימוש ב-7 הימים האחרונים"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{לא נעשה שימוש ביום האחרון}one{לא נעשה שימוש ב-# הימים האחרונים}two{לא נעשה שימוש ביומיים האחרונים}other{לא נעשה שימוש ב-# הימים האחרונים}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{לא נעשה שימוש בשעה האחרונה}one{לא נעשה שימוש ב-# השעות האחרונות}two{לא נעשה שימוש בשעתיים האחרונות}other{לא נעשה שימוש ב-# השעות האחרונות}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{בשימוש על ידי אפליקציה אחת}one{בשימוש על ידי # אפליקציות}two{בשימוש על ידי # אפליקציות}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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"אישור של הכול תמיד"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"יש לשאול בכל פעם"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"אין אישור"</string>
<string name="precise_image_description" msgid="6349638632303619872">"מיקום מדויק"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"ההרשאות <xliff:g id="PERM_0">%1$s</xliff:g> ו<xliff:g id="PERM_1">%2$s</xliff:g> יוסרו."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"ההרשאות שיוסרו: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"ניהול הרשאות באופן אוטומטי"</string>
- <string name="off" msgid="1438489226422866263">"כבוי"</string>
<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_tv_summary" msgid="3685907153054355671">"אם האפליקציה לא בשימוש במשך מספר חודשים:\n\n• ההרשאות יבוטלו כדי להגן על הנתונים שלך\n• הקבצים הזמניים יוסרו כדי לפנות שטח אחסון\n\nכדי להעניק הרשאות שוב, צריך לפתוח את האפליקציה."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"נפתחו לאחרונה לפני יותר מ-<xliff:g id="NUMBER">%s</xliff:g> חודשים"</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{נפתחו לאחרונה לפני יותר מ-# חודשים}two{נפתחו לאחרונה לפני יותר מחודשיים (#)}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">"‏אם מאשרים ניהול של כל הקבצים, האפליקציה הזו תוכל לגשת לקבצים באחסון משותף (Common storage) במכשיר הזה או בהתקני אחסון מחוברים, ולשנות או למחוק אותם. האפליקציה תוכל לגשת לקבצים בלי לבקש ממך אישור."</string>
@@ -251,9 +254,9 @@
<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{# ימים}two{יומיים}other{# ימים}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{שעה אחת}one{# שעות}two{שעתיים}other{# שעות}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{דקה אחת}one{# דקות}two{# דקות}other{# דקות}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{שנייה אחת}one{# שניות}two{# שניות}other{# שניות}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{שעה}one{# שעות}two{שעתיים}other{# שעות}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{דקה אחת}one{# דקות}two{# דקות}other{# דקות}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{שנייה אחת}one{# שניות}two{# שניות}other{# שניות}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"תזכורות להרשאות"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"אפליקציה אחת שמזמן לא השתמשת בה"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> אפליקציות שמזמן לא השתמשת בהן"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"יש אפליקציות שלא נעשה בהן שימוש כבר כמה חודשים. אפשר להקיש כדי לבדוק."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{אפליקציה אחת שמזמן לא השתמשת בה}one{# אפליקציות שמזמן לא השתמשת בהן}two{# אפליקציות שמזמן לא השתמשת בהן}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_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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"‏מערכת Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"הוסרו הרשאות הניתנות לאפליקציה כדי להגן על הפרטיות"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"כבר כמה חודשים לא נעשה שימוש באפליקציה <xliff:g id="APP_NAME">%s</xliff:g>. יש להקיש כדי לבדוק."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"כבר כמה חודשים לא נעשה שימוש באפליקציה <xliff:g id="APP_NAME">%s</xliff:g> ובאפליקציה אחת נוספת. יש להקיש כדי לבדוק."</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"הערות"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"הרשאות בבקרה"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"ניתן לגשת למיקום"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"‏לאפליקציה <xliff:g id="APP_NAME">%s</xliff:g> ניתנה הרשאה ממנהל ה-IT לגשת למיקום שלך"</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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"אבטחה ופרטיות"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"סריקה"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"הרשאות גישה לחיישן"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"אמצעי בקרה על פרטיות"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"ההרשאה הוסרה"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"הצגת פרטים נוספים על השימוש במצלמה"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"הצגת פרטים נוספים על השימוש במיקרופון"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"הסרה של הרשאת הגישה למצלמה"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"הסרה של הרשאת הגישה למיקרופון"</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="manage_service_qs" msgid="7862555549364153805">"ניהול השירות"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"ניהול הרשאות"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"בשימוש על ידי שיחת טלפון"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"אבטחה ופרטיות"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"בדיקת הסטטוס"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"הודעות מהמפתחים"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{עודכנו ב-24 השעות האחרונות}=1{עודכנו ב-24 השעות האחרונות}one{עודכנו ב-# הימים האחרונים}two{עודכנו ביומיים (#) האחרונים}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>
</resources>
diff --git a/PermissionController/res/values-ja-v33/strings.xml b/PermissionController/res/values-ja-v33/strings.xml
index 35263f0f2..e735bb0f7 100644
--- a/PermissionController/res/values-ja-v33/strings.xml
+++ b/PermissionController/res/values-ja-v33/strings.xml
@@ -19,4 +19,28 @@
<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="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>
+ <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>
+ <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{1 個以上のアラートを開いて表示する}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"閉じる"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"オプションを開いて表示する"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"閉じる"</string>
+ <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_gear_label" msgid="5175877094379694098">"設定"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"情報"</string>
</resources>
diff --git a/PermissionController/res/values-ja-v34/strings.xml b/PermissionController/res/values-ja-v34/strings.xml
new file mode 100644
index 000000000..1a27a1df1
--- /dev/null
+++ b/PermissionController/res/values-ja-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="location_settings" msgid="8863940440881290182">"位置情報へのアクセス"</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 bc8aeef2d..06ee27a95 100644
--- a/PermissionController/res/values-ja/strings.xml
+++ b/PermissionController/res/values-ja/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"戻る"</string>
<string name="available" msgid="6007778121920339498">"使用可能"</string>
<string name="blocked" msgid="9195547604866033708">"ブロック中"</string>
+ <string name="on" msgid="280241003226755921">"ON"</string>
+ <string name="off" msgid="1438489226422866263">"OFF"</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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"常にすべて許可"</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>
@@ -64,7 +71,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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"画面オーバーレイを検出"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"この権限設定を変更するには、まず [設定] &gt; [アプリ] から画面オーバーレイを OFF にします"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"設定を開く"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 日}other{# 日}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 時間}other{# 時間}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 分}other{# 分}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 秒}other{# 秒}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# 日}other{# 日}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# 時間}other{# 時間}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# 分}other{# 分}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# 秒}other{# 秒}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"すべての権限"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"全期間"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"過去 7 日間"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"過去 24 時間"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"過去 1 時間"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"過去 15 分間"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"過去 1 分間"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{過去 # 日}other{過去 # 日間}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{過去 # 時間}other{過去 # 時間}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{過去 # 分間}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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"過去 24 時間では使用されていません"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"過去 7 日間では使用されていません"</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_view_details" msgid="6675335735468752787">"ダッシュボードにすべて表示"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"フィルタ: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"常にすべて許可"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"毎回確認する"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"許可しない"</string>
<string name="precise_image_description" msgid="6349638632303619872">"正確な現在地"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g>、<xliff:g id="PERM_1">%2$s</xliff:g>の権限が削除されます。"</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"削除される権限: <xliff:g id="PERMS">%1$s</xliff:g>。"</string>
<string name="auto_manage_title" msgid="7693181026874842935">"権限の自動管理"</string>
- <string name="off" msgid="1438489226422866263">"OFF"</string>
<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_tv_summary" msgid="3685907153054355671">"数か月使用されていないアプリがある場合:\n\n• データを保護するため、権限が削除されます\n• 空き容量を増やすため、一時ファイルが削除されます\n\n権限をもう一度付与する場合は、アプリを開いてください。"</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"最後に開いたのが <xliff:g id="NUMBER">%s</xliff:g> か月以上前"</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>
<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>
@@ -251,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 時間}other{# 時間}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 分}other{# 分}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 秒}other{# 秒}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# 時間}other{# 時間}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<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_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_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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android システム"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"プライバシー保護のためアプリの権限を削除しました"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> は数か月使用されていません。タップしてご確認ください。"</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> と他 1 件のアプリは、数か月使用されていません。タップしてご確認ください。"</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"メモ"</string>
<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>
@@ -452,6 +475,7 @@
<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_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_microphone" msgid="2825208549114811299">"音声の録音を「&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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"権限は管理されています"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"位置情報へのアクセスが許可されています"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"IT 管理者があなたの位置情報へのアクセスを <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"セキュリティとプライバシー"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"スキャン"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"センサーの権限"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"プライバシー管理"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"権限が削除されました"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"カメラの使用状況の詳細"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"マイクの使用状況の詳細"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"カメラの権限を削除"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"マイクの権限を削除"</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="manage_service_qs" msgid="7862555549364153805">"サービスを管理"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"権限の管理"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"通話が使用中"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"セキュリティとプライバシー"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"ステータスを確認する"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"デベロッパーによる情報伝達"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{更新日: 過去 1 日以内}=1{更新日: 過去 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>
</resources>
diff --git a/PermissionController/res/values-ka-v33/strings.xml b/PermissionController/res/values-ka-v33/strings.xml
index a04cdbc09..f92c9ebe8 100644
--- a/PermissionController/res/values-ka-v33/strings.xml
+++ b/PermissionController/res/values-ka-v33/strings.xml
@@ -19,4 +19,28 @@
<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="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>
+ <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>
+ <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{გააფართოვეთ და ნახეთ კიდევ ერთი გაფრთხილება}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"დახურვა"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"გაფართოება და ვარიანტების ჩვენება"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"ჩაკეცვა"</string>
+ <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_gear_label" msgid="5175877094379694098">"პარამეტრები"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"ინფორმაცია"</string>
</resources>
diff --git a/PermissionController/res/values-ka-v34/strings.xml b/PermissionController/res/values-ka-v34/strings.xml
new file mode 100644
index 000000000..c3e4c7715
--- /dev/null
+++ b/PermissionController/res/values-ka-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-ka/strings.xml b/PermissionController/res/values-ka/strings.xml
index 22691ef00..15f434a33 100644
--- a/PermissionController/res/values-ka/strings.xml
+++ b/PermissionController/res/values-ka/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"ყოველთვის ყველას დაშვება"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"ეკრანის გადაფარვა გამოვლინდა"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"ამ ნებართვის პარამეტრის შესაცვლელად, ჯერ უნდა გამორთოთ ეკრანის გადაფარვა პარამეტრებიდან &gt; აპებიდან"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"პარამეტრების გახსნა"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 დღე}other{# დღე}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 საათი}other{# საათი}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 წთ}other{# წთ}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 წმ}other{# წმ}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# დღე}other{# დღე}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# საათი}other{# საათი}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# წთ}other{# წთ}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# წმ}other{# წმ}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"ნებისმიერი ნებართვა"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"ნებისმიერი დრო"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"ბოლო 7 დღე"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"ბოლო 24 საათი"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"ბოლო 1 საათი"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"ბოლო 15 წუთი"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"ბოლო 1 წუთი"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{ბოლო # დღე}other{ბოლო # დღე}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{ბოლო # საათი}other{ბოლო # საათი}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{ბოლო # წუთი}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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"არ გამოყენებულა ბოლო 24 საათის განმავლობაში"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"არ გამოყენებულა ბოლო 7 დღის განმავლობაში"</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_view_details" msgid="6675335735468752787">"ყველაფრის ნახვა საინფორმაციო დაფაზე"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"გაფილტვრის კრიტერიუმი: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"ყოველთვის ყველას დაშვება"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"ყოველთვის მკითხე"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"არ დაიშვას"</string>
<string name="precise_image_description" msgid="6349638632303619872">"ზუსტი მდებარეობა"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> და <xliff:g id="PERM_1">%2$s</xliff:g> ნებართვები ამოიშლება."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"ნებართვები, რომლებიც ამოიშლება: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"ნებართვების ავტომატურად მართვა"</string>
- <string name="off" msgid="1438489226422866263">"გამორთულია"</string>
<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_tv_summary" msgid="3685907153054355671">"თუ აპი რამდენიმე თვის განმავლობაში არ გამოიყენება:\n\n• ნებართვები ამოიშლება თქვენი მონაცემების დასაცავად\n• დროებითი ფაილები ამოიშლება მეხსიერების გასათავისუფლებლად\n\nნებართვების ხელახლა დასაშვებად გახსენით აპი."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"აპის ბოლო გახსნა: <xliff:g id="NUMBER">%s</xliff:g>-ზე მეტი თვის წინ"</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>
@@ -251,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 საათი}other{# საათი}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 წუთი}other{# წუთი}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 წამი}other{# წამი}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# საათი}other{# საათი}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<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_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_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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android სისტემა"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"აპის ნებართვა ამოშლილია კონფიდენციალურობის დაცვის მიზნით"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> რამდენიმე თვის განმავლობაში არ გამოგიყენებიათ. შეეხეთ გადასახედად."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> და 1 სხვა აპი რამდენიმე თვის განმავლობაში არ გამოგიყენებიათ. შეეხეთ გადასახედად."</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"ჩანიშვნები"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"კონტროლირებული ნებართვები"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"მდებარეობაზე წვდომა შესაძლებელია"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"თქვენი IT ადმინისტრატორი <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"უსაფრთხ. და კონფიდენციალურობა"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"სკანირება"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"სენსორის ნებართვები"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"კონფიდენც. მართვის პარამეტრები"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"ამოშლილია ნებართვა"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"ნახეთ მეტი კამერის მოხმარების შესახებ"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"ნახეთ მეტი მიკროფონის მოხმარების შესახებ"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"კამერის ნებართვის ამოშლა"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"მიკროფონის ნებართვის ამოშლა"</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="manage_service_qs" msgid="7862555549364153805">"სერვისის მართვა"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"ნებართვების მართვა"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"ამჟამად იყენებს სატელეფონო ზარი"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"უსაფრთხოება და კონფიდენციალურობა"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"სტატუსის შემოწმება"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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">"Analytics"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"კომუნიკაცია დეველოპერისგან"</string>
+ <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="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="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="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>
</resources>
diff --git a/PermissionController/res/values-kk-v33/strings.xml b/PermissionController/res/values-kk-v33/strings.xml
index 120f80907..9538c1503 100644
--- a/PermissionController/res/values-kk-v33/strings.xml
+++ b/PermissionController/res/values-kk-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Бұл қолданбаға сізге хабарландырулар жіберу және Камера, Контактілер, Микрофон, Телефон және SMS қолданбаларына кіру рұқсаты беріледі."</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Бұл қолданбаға сізге хабарландырулар жіберу және Камера, Контактілер, Files, Микрофон, Телефон және SMS қолданбаларын пайдалану рұқсаты беріледі."</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="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>
+ <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{Тағы бір хабарландыруды жаю және көру}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Жабу"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Опцияларды жаю және көрсету"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Жию"</string>
+ <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_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
new file mode 100644
index 000000000..002624b5a
--- /dev/null
+++ b/PermissionController/res/values-kk-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-kk/strings.xml b/PermissionController/res/values-kk/strings.xml
index 7ae10735e..72320b1d0 100644
--- a/PermissionController/res/values-kk/strings.xml
+++ b/PermissionController/res/values-kk/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,11 +32,16 @@
<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_always_allow_all" msgid="1719900027660252167">"Әрдайым бәріне рұқсат беру"</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_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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Экран үстін жабу анықталды"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Бұл рұқсат параметрін өзгерту үшін алдымен \"Параметрлер\" &gt; \"Қолданбалар\" тармағында экран үстін жабуды өшіру керек"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Параметрлерді ашу"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 күн}other{# күн}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 сағат}other{# сағат}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 мин}other{# мин}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 с}other{# с}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# күн}other{# күн}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# сағат}other{# сағат}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# мин}other{# мин}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# с}other{# с}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Кез келген рұқсат"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Кез келген уақытта"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Соңғы 7 күн"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Соңғы 24 сағат"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Соңғы 1 сағат"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Соңғы 15 минут"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Соңғы 1 минут"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Соңғы # күн}other{Соңғы # күн}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Соңғы # сағат}other{Соңғы # сағат}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Соңғы # минут}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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"Соңғы 24 сағатта пайдаланылмады."</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Соңғы 7 күнде пайдаланылмады."</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_view_details" msgid="6675335735468752787">"Барлығын бақылау тақтасынан көру"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Сүзгі шарты: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"Барлығына әрқашан рұқсат ету"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Әрдайым сұрау"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Рұқсат бермеу"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Нақты орын"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> және <xliff:g id="PERM_1">%2$s</xliff:g> рұқсаттары өшіріледі."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Өшірілетін рұқсаттар: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Рұқсаттарды автоматты түрде басқару"</string>
- <string name="off" msgid="1438489226422866263">"Өшіру"</string>
<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_tv_summary" msgid="3685907153054355671">"Қолданба бірнеше ай бойы пайдаланылмаса:\n\n• Деректерді қорғау үшін рұқсаттар өшіріледі.\n• Орын босату үшін уақытша файлдар жойылады.\n\nРұқсаттарды қайта пайдалану үшін қолданбаны ашыңыз."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Соңғы рет <xliff:g id="NUMBER">%s</xliff:g> айдан астам уақыт бұрын ашылған"</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>
@@ -251,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 сағат}other{# сағат}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 минут}other{# минут}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 секунд}other{# секунд}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# сағат}other{# сағат}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<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_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_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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android жүйесі"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Құпиялықты сақтау үшін қолданба рұқсаттары өшірілді"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> қолданбасы бірнеше ай бойы пайдаланылмады. Көру үшін түртіңіз."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> және тағы 1 қолданба бірнеше ай бойы пайдаланылмады. Көру үшін түртіңіз."</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"ескертпелер"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"Басқарылатын рұқсаттар"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Локация пайдаланылады."</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Әкімшіңіз <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"Қауіпсіздік және құпиялық"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Сканерлеу"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"Датчик пайдалану рұқсаттары"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Құпиялық параметрлері"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"Рұқсат өшірілді."</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Камераны пайдаланатын басқа қолданбаларды көру"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Микрофонды пайдаланатын басқа қолданбаларды көру"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Камера пайдалану рұқсатын өшіру"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Микрофон пайдалану рұқсатын өшіру"</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="manage_service_qs" msgid="7862555549364153805">"Қызметті басқару"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Рұқсаттарды басқару"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Телефон қоңырауы үшін пайдаланылуда."</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Қауіпсіздік және құпиялық"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Күйді тексеру"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Әзірлеушімен байланыс құралдары"</string>
+ <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="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="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">"Бұл қолданбалардың әзірлеушілері App Store дүкенінде өздерінің деректерді бөлісу тәртібі туралы ақпарат берді. Олар уақыт өте келе оны жаңарта алады.\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="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>
</resources>
diff --git a/PermissionController/res/values-km-v33/strings.xml b/PermissionController/res/values-km-v33/strings.xml
index d4c6b3aa9..9926d9664 100644
--- a/PermissionController/res/values-km-v33/strings.xml
+++ b/PermissionController/res/values-km-v33/strings.xml
@@ -19,4 +19,28 @@
<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="work_policy_title" msgid="832967780713677409">"ព័ត៌មាន​អំពីគោលការណ៍ការងារ​របស់អ្នក"</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>
+ <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{ពង្រីកដើម្បីមើលការជូនដំណឹងមួយទៀត}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"បិទ"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"ពង្រីក និង​បង្ហាញ​ជម្រើស​នានា"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"បង្រួម"</string>
+ <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_gear_label" msgid="5175877094379694098">"ការកំណត់"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"ព័ត៌មាន"</string>
</resources>
diff --git a/PermissionController/res/values-km-v34/strings.xml b/PermissionController/res/values-km-v34/strings.xml
new file mode 100644
index 000000000..ccf92d186
--- /dev/null
+++ b/PermissionController/res/values-km-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-km/strings.xml b/PermissionController/res/values-km/strings.xml
index 3bef6d1f7..a50189176 100644
--- a/PermissionController/res/values-km/strings.xml
+++ b/PermissionController/res/values-km/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,11 +32,16 @@
<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_always_allow_all" msgid="1719900027660252167">"អនុញ្ញាតទាំងអស់ជានិច្ច"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"បានរកឃើញ​ការត្រួតគ្នា​លើអេក្រង់"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"ដើម្បី​ប្តូរការកំណត់​ការអនុញ្ញាតនេះ មុនដំបូងអ្នកត្រូវបិទ​ការត្រួតគ្នា​លើអេក្រង់​នៅក្នុង ការកំណត់ &gt; កម្មវិធី​"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"បើកការកំណត់"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 ថ្ងៃ}other{# ថ្ងៃ}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 ម៉ោង}other{# ម៉ោង}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 ន}other{# ន}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 វិ}other{# វិ}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# ថ្ងៃ}other{# ថ្ងៃ}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# ម៉ោង}other{# ម៉ោង}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# នាទីមុន}other{# ន}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# វិ}other{# វិ}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"ការអនុញ្ញាត​ណាមួយ"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"ពេល​ណា​ក៏​បាន"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"7 ថ្ងៃ​ចុងក្រោយ"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"24 ម៉ោង​ចុងក្រោយ"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"1 ម៉ោង​ចុងក្រោយ"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"15 នាទី​ចុងក្រោយ"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"1 នាទី​ចុងក្រោយ"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{# ថ្ងៃចុងក្រោយ}other{# ថ្ងៃចុងក្រោយ}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{# ម៉ោង​ចុងក្រោយ}other{# ម៉ោង​ចុងក្រោយ}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{# នាទី​ចុងក្រោយ}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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"មិនបានប្រើក្នុងរយៈពេល 24 ម៉ោងចុងក្រោយ"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"មិនបានប្រើក្នុងរយៈពេល 7 ថ្ងៃចុងក្រោយ"</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_view_details" msgid="6675335735468752787">"មើល​ទាំងអស់នៅក្នុងផ្ទាំង​គ្រប់គ្រង"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"ត្រង​តាម៖ <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"អនុញ្ញាតទាំងអស់ជានិច្ច"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"សួរគ្រប់ពេល"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"មិនអនុញ្ញាត"</string>
<string name="precise_image_description" msgid="6349638632303619872">"ទីតាំងជាក់លាក់"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"ការអនុញ្ញាត <xliff:g id="PERM_0">%1$s</xliff:g> និង <xliff:g id="PERM_1">%2$s</xliff:g> នឹងត្រូវ​ដកចេញ​។"</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"ការអនុញ្ញាត​ដែលនឹងត្រូវ​ដកចេញ៖ <xliff:g id="PERMS">%1$s</xliff:g>។"</string>
<string name="auto_manage_title" msgid="7693181026874842935">"គ្រប់គ្រង​ការអនុញ្ញាត​ដោយស្វ័យប្រវត្តិ"</string>
- <string name="off" msgid="1438489226422866263">"បិទ"</string>
<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_tv_summary" msgid="3685907153054355671">"ប្រសិនបើ​កម្មវិធីណាមួយ​មិនត្រូវបានប្រើ​រយៈពេលពីរបីខែ៖\n\n• ការអនុញ្ញាតត្រូវបានដកចេញ ដើម្បីការពារ​ទិន្នន័យ​របស់អ្នក\n• ឯកសារ​បណ្ដោះអាសន្នត្រូវបាន​ដកចេញ ដើម្បីបង្កើន​ទំហំផ្ទុកទំនេរ\n\nដើម្បីផ្ដល់​ការអនុញ្ញាតម្ដងទៀត សូមបើក​កម្មវិធីនោះ។"</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"បានបើក​លើកចុងក្រោយ​លើសពី <xliff:g id="NUMBER">%s</xliff:g> ខែមុន"</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>
@@ -251,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 ម៉ោង}other{# ម៉ោង}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 នាទី}other{# នាទី}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 វិនាទី}other{# វិនាទី}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# ម៉ោង}other{# ម៉ោង}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<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_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_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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"ប្រព័ន្ធ Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"បានដក​ការអនុញ្ញាត​កម្មវិធីចេញ ដើម្បី​ការពារ​ឯកជនភាព"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> មិនត្រូវបាន​ប្រើប្រាស់​រយៈពេល​ពីរបីខែ​ហើយ។ សូមចុច ដើម្បី​ពិនិត្យមើល។"</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> និង​កម្មវិធី 1 ផ្សេងទៀត​មិនត្រូវបាន​ប្រើប្រាស់​រយៈពេល​ពីរបីខែ​ហើយ។ សូមចុច ដើម្បី​ពិនិត្យមើល។"</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"កំណត់ចំណាំ"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"ការអនុញ្ញាត​ដែលស្ថិតក្រោម​ការគ្រប់គ្រង"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"អាចចូលប្រើទីតាំងបាន"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"អ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នកកំពុងអនុញ្ញាតឱ្យ <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"សុវត្ថិភាព និងឯកជនភាព"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"ស្កេន"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"ការអនុញ្ញាតឧបករណ៍ចាប់សញ្ញា"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"ការគ្រប់គ្រង​ឯកជនភាព"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"បានដក​ការអនុញ្ញាត"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"មើលការប្រើប្រាស់កាមេរ៉ាច្រើនទៀត"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"មើលការប្រើប្រាស់មីក្រូហ្វូនច្រើនទៀត"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"ដកការអនុញ្ញាតកាមេរ៉ា"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"ដកការអនុញ្ញាតមីក្រូហ្វូន"</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="manage_service_qs" msgid="7862555549364153805">"គ្រប់គ្រង​សេវាកម្ម"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"គ្រប់គ្រង​ការអនុញ្ញាត"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"កំពុងប្រើដោយការហៅទូរសព្ទ"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"សុវត្ថិភាព និងឯកជនភាព"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"ពិនិត្យ​​ស្ថានភាព"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"ការធ្វើទំនាក់ទំនង​របស់​អ្នកអភិវឌ្ឍន៍"</string>
+ <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="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="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="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>
</resources>
diff --git a/PermissionController/res/values-kn-v33/strings.xml b/PermissionController/res/values-kn-v33/strings.xml
index f94bb4ab3..f4d39d7ac 100644
--- a/PermissionController/res/values-kn-v33/strings.xml
+++ b/PermissionController/res/values-kn-v33/strings.xml
@@ -19,4 +19,28 @@
<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="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>
+ <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>
+ <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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"ಮುಚ್ಚಿರಿ"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"ಆಯ್ಕೆಗಳನ್ನು ವಿಸ್ತರಿಸಿ ಮತ್ತು ತೋರಿಸಿ"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"ಕುಗ್ಗಿಸಿ"</string>
+ <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_gear_label" msgid="5175877094379694098">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"ಮಾಹಿತಿ"</string>
</resources>
diff --git a/PermissionController/res/values-kn-v34/strings.xml b/PermissionController/res/values-kn-v34/strings.xml
new file mode 100644
index 000000000..34a939459
--- /dev/null
+++ b/PermissionController/res/values-kn-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-kn/strings.xml b/PermissionController/res/values-kn/strings.xml
index 145988733..5aa9991bd 100644
--- a/PermissionController/res/values-kn/strings.xml
+++ b/PermissionController/res/values-kn/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"ಯಾವಾಗಲೂ ಎಲ್ಲವನ್ನೂ ಅನುಮತಿಸಿ"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"ಸ್ಕ್ರೀನ್ ಓವರ್‌ಲೇ ಪತ್ತೆಹಚ್ಚಲಾಗಿದೆ"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"ಈ ಅನುಮತಿ ಸೆಟ್ಟಿಂಗ್ ಬದಲಾಯಿಸಲು, ನೀವು ಮೊದಲು ಸೆಟ್ಟಿಂಗ್‌ಗಳು &gt; ಆ್ಯಪ್‌ಗಳಿಂದ ಸ್ಕ್ರೀನ್ ಓವರ್‌ಲೇ ಆಫ್ ಮಾಡಬೇಕು"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"ಸೆಟ್ಟಿಂಗ್‍ಗಳನ್ನು ತೆರೆಯಿರಿ"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 ದಿನ}one{# ದಿನಗಳು}other{# ದಿನಗಳು}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 ಗಂಟೆ}one{# ಗಂಟೆಗಳು}other{# ಗಂಟೆಗಳು}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 ನಿಮಿಷ}one{# ನಿಮಿಷಗಳು}other{# ನಿಮಿಷಗಳು}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 ಸೆಕೆಂಡ್}one{# ಸೆಕೆಂಡ್‌ಗಳು}other{# ಸೆಕೆಂಡ್‌ಗಳು}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# ದಿನ}one{# ದಿನಗಳು}other{# ದಿನಗಳು}}"</string>
+ <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_time" msgid="3802087027301631827">"ಯಾವುದಾದರೂ ಸಮಯದಲ್ಲಿ"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"ಕಳೆದ 7 ದಿನಗಳು"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"ಕೊನೆಯ 24 ಗಂಟೆಗಳು"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"1 ಗಂಟೆಯ ಹಿಂದೆ"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"ಹಿಂದಿನ 15 ನಿಮಿಷಗಳು"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"ಕಳೆದ 1 ನಿಮಿಷ"</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>
+ <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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"ಕಳೆದ 24 ಗಂಟೆಗಳಲ್ಲಿ ಬಳಸಿಲ್ಲ"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"ಕಳೆದ 7 ದಿನಗಳಲ್ಲಿ ಬಳಸಿಲ್ಲ"</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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"ಯಾವಾಗಲೂ ಎಲ್ಲವನ್ನೂ ಅನುಮತಿಸಿ"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"ಪ್ರತಿ ಬಾರಿ ಕೇಳಿ"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"ಅನುಮತಿಸಬೇಡಿ"</string>
<string name="precise_image_description" msgid="6349638632303619872">"ನಿಖರವಾದ ಸ್ಥಾನ"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> ಹಾಗೂ <xliff:g id="PERM_1">%2$s</xliff:g> ಅನುಮತಿಗಳನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"ತೆಗೆದುಹಾಕಲಾಗುವ ಅನುಮತಿಗಳು: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"ಅನುಮತಿಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ನಿರ್ವಹಿಸಿ"</string>
- <string name="off" msgid="1438489226422866263">"ಆಫ್"</string>
<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_tv_summary" msgid="3685907153054355671">"ಆ್ಯಪ್ ಅನ್ನು ಕೆಲವು ತಿಂಗಳುಗಳ ಕಾಲ ಬಳಸದೇ ಇದ್ದರೆ:\n\n• ನಿಮ್ಮ ಡೇಟಾವನ್ನು ರಕ್ಷಿಸಲು ಅನುಮತಿಗಳನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ\n• ಸ್ಥಳಾವಕಾಶವನ್ನು ಮುಕ್ತಗೊಳಿಸಲು ತಾತ್ಕಾಲಿಕ ಫೈಲ್‌ಗಳನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ\n\nಅನುಮತಿಗಳನ್ನು ಪುನಃ ಅನುಮತಿಸಲು ಆ್ಯಪ್ ಅನ್ನು ತೆರೆಯಿರಿ."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"ಕೊನೆಯದಾಗಿ <xliff:g id="NUMBER">%s</xliff:g> ತಿಂಗಳುಗಳಿಗೂ ಹಿಂದೆ ತೆರೆಯಲಾಗಿದೆ"</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>
<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>
@@ -251,9 +254,9 @@
<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{# ದಿನಗಳು}other{# ದಿನಗಳು}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 ಗಂಟೆ}one{# ಗಂಟೆಗಳು}other{# ಗಂಟೆಗಳು}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 ನಿಮಿಷ}one{# ನಿಮಿಷಗಳು}other{# ನಿಮಿಷಗಳು}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 ಸೆಕೆಂಡ್}one{# ಸೆಕೆಂಡ್‌ಗಳು}other{# ಸೆಕೆಂಡ್‌ಗಳು}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# ಗಂಟೆ}one{# ಗಂಟೆಗಳು}other{# ಗಂಟೆಗಳು}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# ನಿಮಿಷ}one{# ನಿಮಿಷಗಳು}other{# ನಿಮಿಷಗಳು}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# ಸೆಕೆಂಡ್}one{# ಸೆಕೆಂಡ್‌ಗಳು}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>
@@ -262,6 +265,9 @@
<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>
+ <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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android ಸಿಸ್ಟಂ"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"ಗೌಪ್ಯತೆಯನ್ನು ರಕ್ಷಿಸಲು ಆ್ಯಪ್‌ ಅನುಮತಿಗಳನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> ಅನ್ನು ಕೆಲವು ತಿಂಗಳುಗಳಿಂದ ಬಳಸಲಾಗಿಲ್ಲ. ಪರಿಶೀಲಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> ಮತ್ತು 1 ಇತರ ಆ್ಯಪ್‌ ಅನ್ನು ಕೆಲವು ತಿಂಗಳುಗಳಿಂದ ಬಳಸಲಾಗಿಲ್ಲ. ಪರಿಶೀಲಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಫೋನ್, ಎಸ್ಎಂಎಸ್, ಸಂಪರ್ಕಗಳು ಮತ್ತು Calendar ಅನುಮತಿಗಳನ್ನು ಪ್ರವೇಶಿಸಲು <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_search_keywords" msgid="7710756695666744631">"ಟಿಪ್ಪಣಿಗಳು"</string>
<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>
@@ -452,6 +475,7 @@
<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_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_microphone" msgid="2825208549114811299">"ಆಡಿಯೋ ರೆಕಾರ್ಡ್‌ ಮಾಡಲು &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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"ನಿಯಂತ್ರಿತ ಅನುಮತಿಗಳು"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"ಸ್ಥಳವನ್ನು ಪ್ರವೇಶಿಸಬಹುದು"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರು <xliff:g id="APP_NAME">%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>
@@ -488,25 +512,36 @@
<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="7514620345152008005">"ಭದ್ರತೆ ಮತ್ತು ಗೌಪ್ಯತೆ"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"ಸ್ಕ್ಯಾನ್ ಮಾಡಿ"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"ಸೆನ್ಸರ್ ಅನುಮತಿಗಳು"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"ಗೌಪ್ಯತೆ ನಿಯಂತ್ರಣಗಳು"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"ಅನುಮತಿಯನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"ಕ್ಯಾಮರಾ ಬಳಕೆಯ ಕುರಿತು ಇನ್ನೂ ಹೆಚ್ಚಿನವನ್ನು ನೋಡಿ"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"ಮೈಕ್ರೊಫೋನ್ ಬಳಕೆಯ ಕುರಿತು ಇನ್ನೂ ಹೆಚ್ಚಿನವನ್ನು ನೋಡಿ"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"ಕ್ಯಾಮರಾ ಅನುಮತಿಯನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"ಮೈಕ್ರೊಫೋನ್ ಅನುಮತಿಯನ್ನು ತೆಗೆದುಹಾಕಿ"</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="manage_service_qs" msgid="7862555549364153805">"ಸೇವೆಯನ್ನು ನಿರ್ವಹಿಸಿ"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"ಅನುಮತಿಗಳನ್ನು ನಿರ್ವಹಿಸಿ"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"ಫೋನ್ ಕರೆಯು ಇದನ್ನು ಬಳಸುತ್ತಿದೆ"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"ಭದ್ರತೆ ಮತ್ತು ಗೌಪ್ಯತೆ"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"ಸ್ಥಿತಿ ಪರಿಶೀಲಿಸಿ"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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">"Analytics"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"ಡೆವಲಪರ್ ಸಂವಹನಗಳು"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{ಕೊನೆಯ ದಿನದೊಳಗೆ ಅಪ್‌ಡೇಟ್‌ ಮಾಡಲಾಗಿದೆ}=1{ಕೊನೆಯ ದಿನದೊಳಗೆ ಅಪ್‌ಡೇಟ್‌ ಮಾಡಲಾಗಿದೆ}one{# ದಿನಗಳೊಳಗೆ ಅಪ್‌ಡೇಟ್‌ ಮಾಡಲಾಗಿದೆ}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>
</resources>
diff --git a/PermissionController/res/values-ko-v33/strings.xml b/PermissionController/res/values-ko-v33/strings.xml
index b3009cd84..87bd343e9 100644
--- a/PermissionController/res/values-ko-v33/strings.xml
+++ b/PermissionController/res/values-ko-v33/strings.xml
@@ -19,4 +19,28 @@
<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="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>
+ <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>
+ <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{펼쳐서 알림 1개 더보기}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"닫기"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"펼치기 및 옵션 보기"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"접기"</string>
+ <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_gear_label" msgid="5175877094379694098">"설정"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"정보"</string>
</resources>
diff --git a/PermissionController/res/values-ko-v34/strings.xml b/PermissionController/res/values-ko-v34/strings.xml
new file mode 100644
index 000000000..7b3091170
--- /dev/null
+++ b/PermissionController/res/values-ko-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-ko/strings.xml b/PermissionController/res/values-ko/strings.xml
index 5199d6036..15256ebec 100644
--- a/PermissionController/res/values-ko/strings.xml
+++ b/PermissionController/res/values-ko/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"항상 모두 허용"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"화면 오버레이 감지됨"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"이 권한 설정을 변경하려면 먼저 설정 &gt; 앱에서 화면 오버레이를 사용 중지해야 합니다."</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"설정 열기"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1일}other{#일}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1시간}other{#시간}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1분}other{#분}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1초}other{#초}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{#일}other{#일}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{#시간}other{#시간}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{#분}other{#분}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{#초}other{#초}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"모든 권한"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"전체 기간"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"최근 7일"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"최근 24시간"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"최근 1시간"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"최근 15분"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"최근 1분"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{지난 #일}other{지난 #일}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{최근 #시간}other{최근 #시간}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{최근 #분}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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"지난 24시간 이내에 사용하지 않음"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"지난 7일 이내에 사용하지 않음"</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_view_details" msgid="6675335735468752787">"대시보드에서 모두 보기"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"필터링 기준: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"항상 모두 허용"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"항상 확인"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"허용 안함"</string>
<string name="precise_image_description" msgid="6349638632303619872">"정확한 위치"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> 및 <xliff:g id="PERM_1">%2$s</xliff:g> 권한이 삭제됩니다."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"삭제되는 권한: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_manage_title" msgid="7693181026874842935">"권한 자동 관리"</string>
- <string name="off" msgid="1438489226422866263">"사용 중지"</string>
<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_tv_summary" msgid="3685907153054355671">"앱을 몇 개월간 사용하지 않는 경우 다음 사항이 적용됩니다.\n\n• 데이터 보호를 위해 권한이 삭제됨\n• 여유 공간 확보를 위해 임시 파일이 삭제됨\n\n권한을 다시 부여하려면 앱을 여세요."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"마지막으로 실행한 지 <xliff:g id="NUMBER">%s</xliff:g>개월 이상 경과함"</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>
<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>
@@ -251,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1시간}other{#시간}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1분}other{#분}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1초}other{#초}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{#시간}other{#시간}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<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_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_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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android 시스템"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"개인정보 보호를 위해 앱 권한이 삭제됨"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> 앱을 몇 개월 동안 사용하지 않았습니다. 검토하려면 탭하세요."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> 외 1개 앱을 몇 개월 동안 사용하지 않았습니다. 검토하려면 탭하세요."</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"메모"</string>
<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>
@@ -433,7 +456,7 @@
<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_location" msgid="6990232580121067883">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 내 기기의 위치 정보에 액세스하도록 허용하시겠습니까?"</string>
+ <string name="permgrouprequest_location" msgid="6990232580121067883">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 이 기기의 위치 정보에 액세스하도록 허용하시겠습니까?"</string>
<string name="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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"관리 대상 권한"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"앱이 위치 정보에 액세스할 수 있음"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"IT 관리자가 <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"보안 및 개인 정보 보호"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"검사"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"센서 권한"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"개인 정보 보호 설정"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"권한 삭제됨"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"카메라 사용 정보 더보기"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"마이크 사용 정보 더보기"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"카메라 권한 삭제"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"마이크 권한 삭제"</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="manage_service_qs" msgid="7862555549364153805">"서비스 관리"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"권한 관리"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"전화 통화에서 사용 중"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"보안 및 개인 정보 보호"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"상태 확인"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"개발자 커뮤니케이션"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{1일 이내에 업데이트됨}=1{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>
</resources>
diff --git a/PermissionController/res/values-ky-v33/strings.xml b/PermissionController/res/values-ky-v33/strings.xml
index 1f58b86ef..3f2e12a3d 100644
--- a/PermissionController/res/values-ky-v33/strings.xml
+++ b/PermissionController/res/values-ky-v33/strings.xml
@@ -19,4 +19,28 @@
<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="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>
+ <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>
+ <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{Дагы бир эскертүүнү көрүү үчүн жайып көрсөтүү}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Жабуу"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Параметрлерди жайып көрсөтүү"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Жыйыштыруу"</string>
+ <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_gear_label" msgid="5175877094379694098">"Параметрлер"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Маалымат"</string>
</resources>
diff --git a/PermissionController/res/values-ky-v34/strings.xml b/PermissionController/res/values-ky-v34/strings.xml
new file mode 100644
index 000000000..15fc8424e
--- /dev/null
+++ b/PermissionController/res/values-ky-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-ky/strings.xml b/PermissionController/res/values-ky/strings.xml
index 6d0f557e7..e8816f7fd 100644
--- a/PermissionController/res/values-ky/strings.xml
+++ b/PermissionController/res/values-ky/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"Ар дайым баарына уруксат берүү"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Колдонмонун үстүнө коюу күйүк"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Бул уруксаттын жөндөөсүн өзгөртүү үчүн адегенде Параметрлер &gt; Колдонмолор бөлүмүнөн колдонмонун үстүнө коюуну өчүрүңүз"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Параметрлерди ачуу"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 күн}other{# күн}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 саат}other{# саат}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 мүн.}other{# мүн.}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 сек.}other{# сек.}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# күн}other{# күн}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# саат}other{# саат}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# мүн.}other{# мүн.}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# сек.}other{# сек.}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Бардык уруксаттар"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Каалаган убакта"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Акыркы 7 күндө"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Акыркы 24 саатта"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Акыркы 1 саатта"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Акыркы 15 мүнөттө"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Акыркы 1 мүнөт"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Акыркы # күндө}other{Акыркы # күндө}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Акыркы # саатта}other{Акыркы # саатта}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Акыркы # мүнөттө}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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"Акыркы 24 сааттын ичинде колдонулган жок"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Акыркы 7 күндө колдонулган жок"</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_view_details" msgid="6675335735468752787">"Баарын Куралдар тактасында көрүү"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Чыпка: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"Ар дайым баарына уруксат берүү"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Ар дайым суралсын"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Жок"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Так жайгашкан жери"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> жана <xliff:g id="PERM_1">%2$s</xliff:g> уруксаттары өчүрүлөт."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Өчүрүлө турган уруксаттар: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Уруксаттарды автоматтык түрдө башкаруу"</string>
- <string name="off" msgid="1438489226422866263">"Өчүк"</string>
<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_tv_summary" msgid="3685907153054355671">"Эгер колдонмо бир нече ай колдонулбаса:\n\n• Маалыматыңызды коргоо үчүн уруксаттар жоюлат\n• Орун бошотуу үчүн убактылуу файлдар өчүрүлөт\n\nУруксаттарды жана билдирмелерди кайра иштетүү үчүн колдонмону ачыңыз."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Акыркы жолу <xliff:g id="NUMBER">%s</xliff:g> ай мурда ачылган"</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>
@@ -251,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 саат}other{# саат}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 мүнөт}other{# мүнөт}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 секунд}other{# секунд}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# саат}other{# саат}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<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_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_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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android системасы"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Колдонмонун уруксаттары купуялыкты сактоо үчүн өчүрүлдү"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> бир нече айдан бери колдонулган жок. Көрүү үчүн таптап коюңуз."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> жана дагы 1 колдонмо бир нече айдан бери колдонулган жок. Көрүү үчүн таптап коюңуз."</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"кыска жазуулар"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"Көзөмөлдөнгөн уруксаттар"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Кайда жүргөнүңүз көрүнүп турат"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"IT администраторуңуз <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"Коопсуздук жана купуялык"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Текшерүү"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"Сенсорду колдонуу уруксаттары"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Купуялыкты көзөмөлдөө каражаттары"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"Уруксат өчүрүлдү"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Камеранын колдонулушун көрүү"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Микрофондун колдонулушун көрүү"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Камераны колдонуу уруксатын өчүрүү"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Микрофонду колдонуу уруксатын өчүрүү"</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="manage_service_qs" msgid="7862555549364153805">"Кызматты башкаруу"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Уруксаттарды башкаруу"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Телефон чалууда иштеп жатат"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Коопсуздук жана купуялык"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Статусту текшерүү"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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">"Analytics"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Иштеп чыгуучу менен байланышуу"</string>
+ <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="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="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="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>
</resources>
diff --git a/PermissionController/res/values-lo-v33/strings.xml b/PermissionController/res/values-lo-v33/strings.xml
index 1525817cc..743a5bec9 100644
--- a/PermissionController/res/values-lo-v33/strings.xml
+++ b/PermissionController/res/values-lo-v33/strings.xml
@@ -19,4 +19,28 @@
<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="work_policy_title" msgid="832967780713677409">"ຂໍ້ມູນນະໂຍບາຍວຽກຂອງທ່ານ"</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>
+ <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{ຂະຫຍາຍ ແລະ ເບິ່ງແຈ້ງເຕືອນເພີ່ມອີກ 1 ລາຍການ}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"ປິດ"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"ຂະຫຍາຍ ແລະ ສະແດງຕົວເລືອກ"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"ຫຍໍ້"</string>
+ <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_gear_label" msgid="5175877094379694098">"ການຕັ້ງຄ່າ"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"ຂໍ້ມູນ"</string>
</resources>
diff --git a/PermissionController/res/values-lo-v34/strings.xml b/PermissionController/res/values-lo-v34/strings.xml
new file mode 100644
index 000000000..431b80ec1
--- /dev/null
+++ b/PermissionController/res/values-lo-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-lo/strings.xml b/PermissionController/res/values-lo/strings.xml
index 73c2c6e5a..be8cf2947 100644
--- a/PermissionController/res/values-lo/strings.xml
+++ b/PermissionController/res/values-lo/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"ອະນຸຍາດທັງໝົດຕະຫຼອດ"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"ກວດພົບການວາງຊ້ອນໜ້າຈໍ"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"ເພື່ອປ່ຽນການຕັ້ງຄ່າສິດອະນຸຍາດນີ້, ກ່ອນອື່ນທ່ານຕ້ອງປິດການວາງຊ້ອນໜ້າຈໍຈາກການຕັ້ງຄ່າ &gt; ແອັບ"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"ເປີດການຕັ້ງຄ່າ"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 ມື້}other{# ມື້}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 ຊົ່ວໂມງ}other{# ຊົ່ວໂມງ}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 ນທ}other{# ນທ}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 ວິ}other{# ວິ}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# ມື້}other{# ມື້}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# ຊົ່ວໂມງ}other{# ຊົ່ວໂມງ}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# ນທ}other{# ນທ}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# ວິ}other{# ວິ}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"ສິດອະນຸຍາດໃດກໍໄດ້"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"ເວລາໃດກໍໄດ້"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"7 ມື້ທີ່ຜ່ານມາ"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"24 ຊົ່ວໂມງທີ່ຜ່ານມາ"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"1 ຊົ່ວໂມງທີ່ຜ່ານມາ"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"15 ນາທີຜ່ານມາ"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"1 ນາທີທີ່ຜ່ານມາ"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{# ມື້ທີ່ຜ່ານມາ}other{# ມື້ທີ່ຜ່ານມາ}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{# ຊົ່ວໂມງທີ່ຜ່ານມາ}other{# ຊົ່ວໂມງທີ່ຜ່ານມາ}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{# ນາທີທີ່ຜ່ານມາ}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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"ບໍ່ໄດ້ໃຊ້ໃນ 24 ຊົ່ວໂມງທີ່ຜ່ານມາ"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"ບໍ່ໄດ້ໃຊ້ໃນ 7 ມື້ທີ່ຜ່ານມາ"</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_view_details" msgid="6675335735468752787">"ເບິ່ງທັງໝົດໃນແຜງໜ້າປັດ"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"ກັ່ນຕອງແລ້ວໂດຍ: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"ອະນຸຍາດທັງໝົດຕະຫຼອດ"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"ຖາມທຸກເທື່ອ"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"ບໍ່ອະນຸຍາດ"</string>
<string name="precise_image_description" msgid="6349638632303619872">"ສະຖານທີ່ແບບລະອຽດ"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"ສິດອະນຸຍາດ <xliff:g id="PERM_0">%1$s</xliff:g> ແລະ <xliff:g id="PERM_1">%2$s</xliff:g> ຈະຖືກລຶບອອກ."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"ສິດອະນຸຍາດທີ່ຈະຖືກລຶບອອກ: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"ຈັດການສິດອະນຸຍາດອັດຕະໂນມັດ"</string>
- <string name="off" msgid="1438489226422866263">"ປິດ"</string>
<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_tv_summary" msgid="3685907153054355671">"ຫາກບໍ່ໄດ້ໃຊ້ແອັບໃດໜຶ່ງເປັນເວລາສອງສາມເດືອນ:\n\n• ການອະນຸຍາດຈະຖືກລຶບອອກເພື່ອປົກປ້ອງຂໍ້ມູນຂອງທ່ານ\n• ໄຟລ໌ຊົ່ວຄາວຈະຖືກລຶບອອກເພື່ອສ້າງພື້ນທີ່ຫວ່າງ\n\nເພື່ອໃຫ້ການອະນຸຍາດອີກເທື່ອໜຶ່ງ, ໃຫ້ເປີດແອັບຂຶ້ນມາ."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"ເປີດຫຼ້າສຸດຫຼາຍກວ່າ <xliff:g id="NUMBER">%s</xliff:g> ເດືອນກ່ອນ"</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>
@@ -251,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 ຊົ່ວໂມງ}other{# ຊົ່ວໂມງ}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 ນາທີ}other{# ນາທີ}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 ວິນາທີ}other{# ວິນາທີ}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# ຊົ່ວໂມງ}other{# ຊົ່ວໂມງ}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<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_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_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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"ລະບົບ Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"ລຶບສິດອະນຸຍາດແອັບອອກແລ້ວເພື່ອປົກປ້ອງຄວາມເປັນສ່ວນຕົວ"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"ບໍ່ໄດ້ໃຊ້ <xliff:g id="APP_NAME">%s</xliff:g> ມາສອງສາມເດືອນແລ້ວ. ແຕະເພື່ອກວດສອບ."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"ບໍ່ໄດ້ໃຊ້ <xliff:g id="APP_NAME">%s</xliff:g> ແລະ ອີກ 1 ແອັບມາສອງສາມເດືອນແລ້ວ. ແຕະເພື່ອກວດສອບ."</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"ບັນທຶກ"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"ສິດອະນຸຍາດທີ່ມີການຄວບຄຸມ"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"ສາມາດເຂົ້າເຖິງສະຖານທີ່ໄດ້ແລ້ວ"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"ຜູ້ເບິ່ງແຍງໄອທີຂອງທ່ານອະນຸຍາດໃຫ້ <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"ຄວາມປອດໄພ ແລະ ຄວາມເປັນສ່ວນຕົວ"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"ສະແກນ"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"ການອະນຸຍາດເຊັນເຊີ"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"ການຄວບຄຸມຄວາມເປັນສ່ວນຕົວ"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"ລຶບການອະນຸຍາດອອກແລ້ວ"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"ເບິ່ງການນຳໃຊ້ກ້ອງຖ່າຍຮູບເພີ່ມເຕີມ"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"ເບິ່ງການນຳໃຊ້ໄມໂຄຣໂຟນເພີ່ມເຕີມ"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"ລຶບການອະນຸຍາດກ້ອງຖ່າຍຮູບອອກ"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"ລຶບການອະນຸຍາດໄມໂຄຣໂຟນອອກ"</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="manage_service_qs" msgid="7862555549364153805">"ຈັດການບໍລິການ"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"ຈັດການການອະນຸຍາດ"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"ກຳລັງຖືກໃຊ້ໂດຍການໂທລະສັບ"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"ຄວາມປອດໄພ ແລະ ຄວາມເປັນສ່ວນຕົວ"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"ກວດສອບສະຖານະ"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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">"Analytics"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"ການສື່ສານຂອງນັກພັດທະນາ"</string>
+ <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="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="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">"ນັກພັດທະນາແອັບເຫຼົ່ານີ້ໄດ້ໃຫ້ຂໍ້ມູນກ່ຽວກັບແນວທາງປະຕິບັດໃນການແບ່ງປັນຂໍ້ມູນຂອງເຂົາເຈົ້າໄວ້ໃນ App Store. ເຂົາເຈົ້າອາດອັບເດດຂໍ້ມູນເມື່ອເວລາຜ່ານໄປ.\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="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>
</resources>
diff --git a/PermissionController/res/values-lt-v33/strings.xml b/PermissionController/res/values-lt-v33/strings.xml
index f0a2ee724..41c3bdc9f 100644
--- a/PermissionController/res/values-lt-v33/strings.xml
+++ b/PermissionController/res/values-lt-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Šiai programai bus leista jums siųsti pranešimus ir suteikta prieiga prie Vaizdo kameros, Kontaktų, Mikrofono, Telefono ir SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Šiai programai bus leista jums siųsti pranešimus ir suteikta prieiga prie vaizdo kameros, Kontaktų, Failų, mikrofono, telefono ir SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Programos, kurioms suteiktas šis leidimas, gali pasiekti visus failus šiame įrenginyje"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Darbo politikos informacija"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Nustatymus tvarko jūsų IT administratorius"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Išskleisti ir rodyti sąrašą"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Sutraukti sąrašą ir slėpti nustatymus"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Sąrašas. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Sąrašas. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Būtina imtis veiksmų. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Sąrašo elementas. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Uždaryti"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Išskleisti ir rodyti parinktis"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Sutraukti"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Perjunkite. <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">"Perjungti"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Atidaryti"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Žr. nustatymus"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Nustatymai"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Informacija"</string>
</resources>
diff --git a/PermissionController/res/values-lt-v34/strings.xml b/PermissionController/res/values-lt-v34/strings.xml
new file mode 100644
index 000000000..f7a60d198
--- /dev/null
+++ b/PermissionController/res/values-lt-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Sauga ir privatumas"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Valdikliai"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Programos prieigos prie sveikatos duomenų tvarkymas"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Prieiga prie vietovės"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Programos ir paslaugos. Jei šis nustatymas išjungtas, mikrofono duomenys vis tiek gali būti bendrinami, skambinant pagalbos numeriu"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Programos ir paslaugos"</string>
+</resources>
diff --git a/PermissionController/res/values-lt/strings.xml b/PermissionController/res/values-lt/strings.xml
index 47d2a5de4..1c179457d 100644
--- a/PermissionController/res/values-lt/strings.xml
+++ b/PermissionController/res/values-lt/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Atgal"</string>
<string name="available" msgid="6007778121920339498">"Pasiekiama"</string>
<string name="blocked" msgid="9195547604866033708">"Užblokuota"</string>
+ <string name="on" msgid="280241003226755921">"Įjungta"</string>
+ <string name="off" msgid="1438489226422866263">"Išjungti"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Pašalinti arba išjungti"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Programa nerasta"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Neleisti"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Išlaikyti režimą „Kai programa naudojama“ įjungtą"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Palikti „Tik šį kartą“"</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Vis tiek neleisti"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Atmesti"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> iš <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Aptikta ekrano perdanga"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Jei norite pakeisti šį leidimo nustatymą, pirmiausia turite išjungti ekrano perdangą skiltyje „Nustatymai“ &gt; „Programos“"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Atidaryti nustatymus"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Laiko juosta, kurioje rodoma, kada programos naudojo leidimų grupę „<xliff:g id="PERMGROUP">%1$s</xliff:g>“ per pastarąsias 7 dienas"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Kada ši programa naudojo jūsų leidimų grupės „<xliff:g id="PERMGROUP">%1$s</xliff:g>“ leidimą"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Sužinokite daugiau"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Sužinokite daugiau apie „<xliff:g id="PERMGROUP">%1$s</xliff:g>“"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Valdykite programų prieigą prie: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • „<xliff:g id="APP_NAME">%2$s</xliff:g>“ • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 diena}one{# diena}few{# dienos}many{# dienos}other{# dienų}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 valanda}one{# valanda}few{# valandos}many{# valandos}other{# valandų}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 minutė}one{# minutė}few{# minutės}many{# minutės}other{# minučių}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 sekundė}one{# sekundė}few{# sekundės}many{# sekundės}other{# sekundžių}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# diena}one{# diena}few{# dienos}many{# dienos}other{# dienų}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# valanda}one{# valanda}few{# valandos}many{# valandos}other{# valandų}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# minutė}one{# minutė}few{# minutės}many{# minutės}other{# minučių}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# sekundė}one{# sekundė}few{# sekundės}many{# sekundės}other{# sekundžių}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Bet koks leidimas"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Bet koks laikas"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Pastarosios 7 dienos"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Pastarosios 24 valandos"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Pastaroji 1 valanda"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Pastarosios 15 minučių"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Pastaroji minutė"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Pastaroji # diena}one{Pastaroji # diena}few{Pastarosios # dienos}many{Pastarosios # dienos}other{Pastarųjų # dienų}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Pastaroji # valanda}one{Pastaroji # valanda}few{Pastarosios # valandos}many{Pastarosios # valandos}other{Pastarųjų # valandų}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Pastaroji # minutė}one{Pastaroji # minutė}few{Pastarosios # minutės}many{Pastarosios # minutės}other{Pastarųjų # minučių}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Leidimai nenaudoti"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Paskutinį kartą pasiekta bet kuriuo metu"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Paskutinį kartą pasiekta per pastarąsias 7 dienas"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Leidimo naudojimas per pastarąją 1 valandą"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Leidimo naudojimas per pastarąsias 15 minučių"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Leidimo naudojimas per pastarąją 1 minutę"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Nenaudota per pastarąsias 24 val."</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Nenaudota per pastarąsias septynias dienas"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Nenaudota per pastarąją # dieną}one{Nenaudota per pastarąją # dieną}few{Nenaudota per pastarąsias # dienas}many{Nenaudota per pastarosios # dienos}other{Nenaudota per pastarąsias # dienų}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Nenaudota per pastarąją # valandą}one{Nenaudota per pastarąją # valandą}few{Nenaudota per pastarąsias # valandas}many{Nenaudota per pastarosios # valandos}other{Nenaudota per pastarąsias # valandų}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Naudojama 1 programoje}one{Naudojama # programoje}few{Naudojama # programose}many{Naudojama # programos}other{Naudojama # programų}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Žr. viską informacijos suvestinėje"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtruota pagal: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Leisti pasiekti tik mediją"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Leisti visą laiką"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Leisti tik naudojant programą"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Visada leisti viską"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Klausti kaskart"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Neleisti"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Tiksli vietovė"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Leidimai (<xliff:g id="PERM_0">%1$s</xliff:g> ir <xliff:g id="PERM_1">%2$s</xliff:g>) bus pašalinti."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Leidimai, kurie bus pašalinti: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Automatinis leidimų tvarkymas"</string>
- <string name="off" msgid="1438489226422866263">"Išjungti"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Leidimas „<xliff:g id="PERMISSION_NAME">%s</xliff:g>“ pašalintas"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Leidimai „<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g>“ ir „<xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g>“ pašalinti"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Leidimas „<xliff:g id="PERMISSION_NAME">%1$s</xliff:g>“ ir dar <xliff:g id="NUMBER">%2$s</xliff:g> pašalinti"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Nenaudojamos programos"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Jei programa nenaudojama kelis mėnesius:\n\n• pašalinami leidimai siekiant apsaugoti jūsų duomenis;\n• sustabdomi pranešimai, siekiant tausoti akumuliatoriaus energiją;\n• pašalinami laikinieji failai siekiant atlaisvinti vietos.\n\nNorėdami vėl suteikti leidimus ir leisti pranešimus, atidarykite programą."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Jei programa nenaudojama kelis mėnesius:\n\n• pašalinami leidimai siekiant apsaugoti jūsų duomenis;\n• pašalinami laikinieji failai siekiant atlaisvinti vietos.\n\nNorėdami vėl suteikti leidimus, atidarykite programą."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Paskutinį kartą atidaryta daugiau nei prieš <xliff:g id="NUMBER">%s</xliff:g> mėn."</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Jei programa nenaudojama mėnesį:\n\n• pašalinami leidimai siekiant apsaugoti jūsų duomenis;\n• pašalinami laikinieji failai siekiant atlaisvinti vietos.\n\nNorėdami vėl suteikti leidimus, atidarykite programą."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Paskutinį kartą atidaryta daugiau nei prieš # mėnesį}one{Paskutinį kartą atidaryta daugiau nei prieš # mėnesį}few{Paskutinį kartą atidaryta daugiau nei prieš # mėnesius}many{Paskutinį kartą atidaryta daugiau nei prieš # mėnesio}other{Paskutinį kartą atidaryta daugiau nei prieš # mėnesių}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Programa paskutinį kartą atidaryta <xliff:g id="DATE">%s</xliff:g>"</string>
<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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Neleidžiama"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Peržiūrėti daugiau programų, galinčių pasiekti visus failus"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 diena}one{# diena}few{# dienos}many{# dienos}other{# dienų}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 valanda}one{# valanda}few{# valandos}many{# valandos}other{# valandų}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minutė}one{# minutė}few{# minutės}many{# minutės}other{# minučių}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 sekundė}one{# sekundė}few{# sekundės}many{# sekundės}other{# sekundžių}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# valanda}one{# valanda}few{# valandos}many{# valandos}other{# valandų}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minutė}one{# minutė}few{# minutės}many{# minutės}other{# minučių}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# sekundė}one{# sekundė}few{# sekundės}many{# sekundės}other{# sekundžių}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Leidimų priminimai"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 nenaudojama programa"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"Nenaudojamų programų: <xliff:g id="NUMBER_OF_APPS">%s</xliff:g>"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Kai kurios programos nebuvo naudojamos kelis mėnesius. Palieskite ir peržiūrėkite."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# nenaudojama programa}one{# nenaudojama programa}few{# nenaudojamos programos}many{# nenaudojamos programos}other{# nenaudojamų programų}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Leidimai ir laikinieji failai pašalinti, o pranešimai sustabdyti. Palieskite ir peržiūrėkite."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Programų, kurių leidimai pašalinti, peržiūra"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Programų, kurių tam tikrą laiką nenaudojote, leidimai ir laikini failai buvo pašalinti ir pranešimai sustabdyti."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Programų peržiūra"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Naujausių leidimų patikra"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Vairuodami suteikėte programai „<xliff:g id="APP">%1$s</xliff:g>“ prieigą prie šio leidimo: <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Vairuodami suteikėte programai „<xliff:g id="APP">%1$s</xliff:g>“ prieigą prie šių leidimų: <xliff:g id="PERMISSION_1">%2$s</xliff:g> ir <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Leidimai pašalinti siekiant užtikrinti jūsų privatumą"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"Programa „<xliff:g id="APP_NAME">%s</xliff:g>“ gavo vietovės duomenis fone"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Ši programa visada gali pasiekti jūsų vietovę. Palieskite, kad pakeistumėte."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Pranešimus galinčios pasiekti programos peržiūra"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"„<xliff:g id="APP_NAME">%s</xliff:g>“ gali atmesti pranešimus, atlikti veiksmus ir pasiekti jūsų pranešimų turinį"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Ši programa gali atmesti pranešimus, atlikti veiksmus ir pasiekti jūsų pranešimų turinį. Kai kurioms programoms reikalinga ši prieiga, kad galėtų veikti, kaip numatyta."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Prieigos pašalinimas"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Žr. daugiau parinkčių"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Prieiga pašalinta"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Programos su visateise įrenginio prieiga peržiūra"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"„<xliff:g id="APP_NAME">%s</xliff:g>“ gali peržiūrėti jūsų ekraną ir atlikti veiksmus įrenginyje. Pritaikomumo programoms reikalinga šio tipo prieiga, kad galėtų veikti, kaip numatyta."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Ši programa gali peržiūrėti jūsų ekraną ir atlikti veiksmus įrenginyje. Pritaikomumo programoms reikalinga šio tipo prieiga, kad galėtų veikti, kaip numatyta, bet patikrinkite programą ir įsitikinkite, kad ja pasitikite."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Pašalinti prieigą"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Peržiūrėti visateisę prieigą turinčias programas"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Prieiga pašalinta"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Sistema „Android“"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Programos leidimai pašalinti siekiant užtikrinti privatumą"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"„<xliff:g id="APP_NAME">%s</xliff:g>“ nebuvo naudojama kelis mėnesius. Palieskite ir peržiūrėkite."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"„<xliff:g id="APP_NAME">%s</xliff:g>“ ir dar viena programa nebuvo naudojamos kelis mėnesius. Palieskite ir peržiūrėkite."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ galės sąveikauti su pranešimų funkcija ir pasiekti telefoną, SMS, kontaktus ir kalendorių."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ galės sąveikauti su pranešimų funkcija ir srautu perduoti programas į prijungtą įrenginį."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Ši paslauga bendrina jūsų nuotraukas, mediją ir pranešimus iš telefono ir kitų įrenginių."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Numatytoji užrašų programa"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Valdomi leidimai"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Vietovė pasiekiama"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"IT administratorius leidžia „<xliff:g id="APP_NAME">%s</xliff:g>“ pasiekti jūsų vietovę"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Programos ir paslaugos"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Mikrofono duomenys vis tiek gali būti bendrinami, skambinant pagalbos numeriu."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Pakeisti"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Sauga ir privatumas"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Nuskaityti"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Sauga ir privatumas"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Nuskaityti įrenginį"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Atsisakyti"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Atsisakyti šio įspėjimo?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Peržiūrėkite saugos bei privatumo nustatymus bet kuriuo metu ir pasirūpinkite geresne apsauga"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Atsisakyti"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Atšaukti"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Nustatymai"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Saugos ir privatumo būsena. <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">"Saugos nustatymai"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Jutiklių leidimai"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Privatumo valdikliai"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Leidimai"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Sauga ir privatumas"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Patikrinkite būseną"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Jūsų privatumo valdikliai"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Daugiau nustatymų"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Prieiga prie fotoaparato"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Prieiga prie mikrofono"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Leidimas pašalintas"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Žr. daugiau vaizdo kameros naudojimo atvejų"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Žr. daugiau mikrofono naudojimo atvejų"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Pašalinti vaizdo kameros leidimą"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Pašalinti mikrofono leidimą"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Žr. pastarąjį vaizdo kameros naudojimą"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Žr. pastarąjį mikrofono naudojimą"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Pašalinti šios programos leidimą"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Pašalinti šios programos leidimą"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Tvarkyti paslaugą"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Tvarkyti leidimus"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Naudojama telefono skambučiui"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Neseniai naudota „<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">"Naudojama „<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">"Neseniai naudota „<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Sauga ir privatumas"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Patikrinkite būseną"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Patvirtinti"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Atgal"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Taip pat bus galima pasiekti kitus failus"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Ši programa nepalaiko naujausios „Android“ versijos. Jei ši programa negali pasiekti muzikos ir garso failų, ji taip pat negalės pasiekti nuotraukų ir vaizdo įrašų."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Ši programa nepalaiko naujausios „Android“ versijos. Jei ši programa gali pasiekti nuotraukas ir vaizdo įrašus, ji taip pat galės pasiekti muzikos ir garso failus."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Ši programa nepalaiko naujausios „Android“ versijos. Jei ši programa negali pasiekti muzikos ir garso failų, ji taip pat negalės pasiekti nuotraukų ir vaizdo įrašų."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Programos, pasiekiančios fone veikiančią vietovės nustatymo funkciją, peržiūra"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"„<xliff:g id="APP_NAME">%s</xliff:g>“ visada gali pasiekt vietovės nustatymo funkciją, net kai programa uždaryta"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Programos, pasiekiančios fone veikiančią vietovės nustatymo funkciją, peržiūra"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Ši programa gali visada pasiekti vietovės nustatymo funkciją, net kai uždaryta.\n\nKai kurioms saugos ir kritinės padėties programoms reikia pasiekti vietovės informaciją fone, kad jos veiktų, kaip numatyta."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Prieiga pakeista"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Žr. pastarąjį vietovės nustatymo funkcijos naudojimą"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Privatumo valdikliai"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Prieiga prie fotoaparato"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Prieiga prie mikrofono"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Skirta programoms ir paslaugoms"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Skirta programoms ir paslaugoms. Jei šis nustatymas išjungtas, mikrofono duomenys vis tiek gali būti bendrinami, skambinant pagalbos numeriu."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Peržiūrėkite programas ir paslaugas, kurios gali pasiekti vietovės duomenis"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Rodyti iškarpinės prieigą"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Rodyti pranešimą, kai programos pasiekia nukopijuotą tekstą, vaizdus ar kitą turinį"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Rodyti slaptažodžius"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Trumpai rodyti simbolius vedant tekstą"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Duomenų praktika gali skirtis, atsižvelgiant į jūsų programos versiją, naudojimą, regioną ir amžių. "<annotation id="link">"Daugiau apie duomenų bendrinimą"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Duomenų praktika gali skirtis, atsižvelgiant į jūsų programos versiją, naudojimą, regioną ir amžių."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Jūsų vietovės duomenys"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Keiskite šios programos prieigą "<annotation id="link">"privatumo nustatymuose"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Programos funkcijos"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analizė"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Kūrėjų komunikacija"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Reklamavimas ar rinkodara"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Apsauga nuo apgaulių, sauga ir taisyklių laikymasis"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Suasmeninimas"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Paskyros valdymas"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Šių programų kūrėjai pateikė informacijos apie savo duomenų bendrinimo praktikos metodus programų parduotuvėje. Jie gali ją atnaujinti per laiką.\n\nDuomenų bendrinimo praktikos metodai gali skirtis atsižvelgiant į programos versiją, naudojimą, regioną ir amžių."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Sužinokite apie duomenų bendrinimą"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Jūsų vietovės duomenys dabar bendrinami su trečiosiomis šalimis"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Jūsų vietovės duomenys dabar bendrinami su trečiosiomis šalimis reklamavimo arba rinkodaros tikslais"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Atnaujinta per pastarąją dieną}=1{Atnaujinta per pastarąją dieną}one{Atnaujinta per pastarąją # dieną}few{Atnaujinta per pastarąsias # dienas}many{Atnaujinta per pastarąsias # dienos}other{Atnaujinta per pastarąsias # dienų}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Šiuo metu nėra naujinių"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-lv-v33/strings.xml b/PermissionController/res/values-lv-v33/strings.xml
index c747627c2..825ac7aec 100644
--- a/PermissionController/res/values-lv-v33/strings.xml
+++ b/PermissionController/res/values-lv-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Šai lietotnei tiks atļauts sūtīt jums paziņojumus un tiks piešķirta piekļuve jūsu kamerai, kontaktpersonām, mikrofonam, tālrunim un īsziņām"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Šai lietotnei tiks atļauts sūtīt jums paziņojumus un tiks piešķirta piekļuve jūsu kamerai, kontaktpersonām, failiem, mikrofonam, tālrunim un īsziņām"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Lietotnes ar šo atļauju var piekļūt visiem failiem šajā ierīcē"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Informācija par jūsu darba politiku"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Iestatījumi, ko pārvalda jūsu IT administrators"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Izvērst un rādīt sarakstu"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Sakļaut sarakstu un paslēpt iestatījumus"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Saraksts. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Saraksts. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Nepieciešama rīcība. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Saraksta vienums. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Aizvērt"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Izvērst un rādīt opcijas"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Sakļaut"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Slēdzis. <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">"Pārslēgt"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Atvērt"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Pārskatīt iestatījumus"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Iestatījumi"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Informācija"</string>
</resources>
diff --git a/PermissionController/res/values-lv-v34/strings.xml b/PermissionController/res/values-lv-v34/strings.xml
new file mode 100644
index 000000000..3c99e3275
--- /dev/null
+++ b/PermissionController/res/values-lv-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Drošība un konfidencialitāte"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Vadīklas"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Pārvaldiet lietotņu piekļuvi veselības datiem."</string>
+ <string name="location_settings" msgid="8863940440881290182">"Piekļuve atrašanās vietai"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Lietotnēm un pakalpojumiem. Ja šis iestatījums ir izslēgts, mikrofona dati joprojām var tikt kopīgoti, kad zvanīsiet uz ārkārtas numuru."</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Lietotnēm un pakalpojumiem"</string>
+</resources>
diff --git a/PermissionController/res/values-lv/strings.xml b/PermissionController/res/values-lv/strings.xml
index f1b9188ab..530e2cc6c 100644
--- a/PermissionController/res/values-lv/strings.xml
+++ b/PermissionController/res/values-lv/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Atpakaļ"</string>
<string name="available" msgid="6007778121920339498">"Pieejama"</string>
<string name="blocked" msgid="9195547604866033708">"Bloķēta"</string>
+ <string name="on" msgid="280241003226755921">"Ieslēgta"</string>
+ <string name="off" msgid="1438489226422866263">"Izslēgti"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Atinstalēt vai atspējot"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Lietotne netika atrasta"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Neatļaut"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Paturēt atļauju “Kamēr lietotne tiek izmantota”"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Paturēt iestatījumu “Tikai šoreiz”"</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Tomēr neatļaut"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Nerādīt"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g>. no <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Konstatēts ekrāna pārklājums"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Lai mainītu šo atļaujas iestatījumu, vispirms sadaļā Iestatījumi &gt; Lietotnes izslēdziet ekrāna pārklājumu."</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Atvērt iestatījumus"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Šajā laika skalā ir norādīts, kad lietotnes pēdējo 7 dienu laikā izmantoja atļauju <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Tālāk norādīts, kad šī lietotne izmantoja šādu atļauju: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Uzzināt vairāk"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Plašāka informācija par tēmu <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Kontrolēt lietotņu piekļuvi jūsu atļauju grupai “<xliff:g id="PERMGROUP">%1$s</xliff:g>”"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 diena}zero{# dienu}one{# diena}other{# dienas}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 stunda}zero{# stundu}one{# stunda}other{# stundas}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}zero{# min}one{# min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 s}zero{# s}one{# s}other{# s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# diena}zero{# dienu}one{# diena}other{# dienas}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# stunda}zero{# stundu}one{# stunda}other{# stundas}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}zero{# min}one{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}zero{# s}one{# s}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Jebkura atļauja"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Jebkurā laikā"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Pēdējās 7 dienās"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Pēdējās 24 stundās"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Pēdējā stundā"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Pēdējās 15 minūtēs"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Pēdējā minūtē"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Pēdējā # dienā}zero{Pēdējās # dienās}one{Pēdējā # dienā}other{Pēdējās # dienās}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Pēdējā # stundā}zero{Pēdējās # stundās}one{Pēdējā # stundā}other{Pēdējās # stundās}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Pēdējā # minūtē}zero{Pēdējās # minūtēs}one{Pēdējā # minūtē}other{Pēdējās # minūtēs}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Nav lietota neviena atļauja"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Nesenākā piekļuve jebkurā laikā"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Nesenākā piekļuve pēdējo 7 dienu laikā"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Atļauju lietojums pēdējās stundas laikā"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Atļauju lietojums pēdējās 15 minūtēs"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Atļauju lietojums pēdējā minūtē"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Pēdējo 24 stundu laikā nav izmantota"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Pēdējo 7 dienu laikā nav izmantota"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Pēdējās # dienas laikā nav izmantota}zero{Pēdējo # dienu laikā nav izmantota}one{Pēdējās # dienas laikā nav izmantota}other{Pēdējo # dienu laikā nav izmantota}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Pēdējās # stundas laikā nav izmantota}zero{Pēdējo # stundu laikā nav izmantota}one{Pēdējās # stundas laikā nav izmantota}other{Pēdējo # stundu laikā nav izmantota}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Izmanto 1 lietotne}zero{Izmanto # lietotnes}one{Izmanto # lietotne}other{Izmanto # lietotnes}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Skatīt visu rīkā Permission Dashboard"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrēts pēc: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Atļaut piekļūt tikai multivides failiem"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Vienmēr atļaut"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Atļaut tikai lietotnes izmantošanas laikā"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Vienmēr atļaut visu"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Vaicāt katru reizi"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Neatļaut"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Precīza atrašanās vieta"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Tiks noņemtas šādas atļaujas : <xliff:g id="PERM_0">%1$s</xliff:g> un <xliff:g id="PERM_1">%2$s</xliff:g>."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Tiks noņemtas šādas atļaujas: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Atļauju automātiska pārvaldība"</string>
- <string name="off" msgid="1438489226422866263">"Izslēgti"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Atļauja “<xliff:g id="PERMISSION_NAME">%s</xliff:g>” tika automātiski noņemta"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Atļauja “<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g>” un “<xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g>” tika automātiski noņemta"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Atļauja “<xliff:g id="PERMISSION_NAME">%1$s</xliff:g>” un vēl <xliff:g id="NUMBER">%2$s</xliff:g> tika automātiski noņemtas"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Neizmantotās lietotnes"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Ja kāda lietotne nav izmantota vairākus mēnešus:\n\n• tiek noņemtas atļaujas, lai aizsargātu jūsu datus;\n• tiek apturēti paziņojumi, lai taupītu akumulatora enerģiju;\n• tiek noņemti pagaidu faili, lai atbrīvotu vietu.\n\nLai atkal piešķirtu atļaujas un atļautu paziņojumus, atveriet lietotni."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Ja kāda lietotne nav izmantota vairākus mēnešus:\n\n• tiek noņemtas atļaujas, lai aizsargātu jūsu datus;\n• tiek noņemti pagaidu faili, lai atbrīvotu vietu.\n\nLai atkal piešķirtu atļaujas, atveriet lietotni."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Pēdējoreiz atvērtas pirms vairāk nekā <xliff:g id="NUMBER">%s</xliff:g> mēnešiem"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Ja kāda lietotne nav izmantota mēnesi:\n\n• tiek noņemtas atļaujas, lai aizsargātu jūsu datus;\n• tiek noņemti pagaidu faili, lai atbrīvotu vietu.\n\nLai atkal piešķirtu atļaujas, atveriet lietotni."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Pēdējoreiz atvērtas pirms vairāk nekā # mēneša}zero{Pēdējoreiz atvērtas pirms vairāk nekā # mēnešiem}one{Pēdējoreiz atvērtas pirms vairāk nekā # mēneša}other{Pēdējoreiz atvērtas pirms vairāk nekā # mēnešiem}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Lietotne pēdējoreiz tika atvērta <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Pēdējoreiz atvērta <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Ja atļausiet pārvaldīt visus failus, šī lietotne varēs piekļūt visiem failiem un modificēt un dzēst visus failus, kas atrodas parastā krātuvē šajā ierīcē vai pievienotās atmiņas ierīcēs. Lietotne varēs piekļūt failiem, nepieprasot jūsu atļauju."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Nav atļauts"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Skatīt citas lietotnes, kas drīkst piekļūt visiem failiem"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 diena}zero{# dienu}one{# diena}other{# dienas}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 stunda}zero{# stundu}one{# stunda}other{# stundas}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minūte}zero{# minūšu}one{# minūte}other{# minūtes}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 sekunde}zero{# sekunžu}one{# sekunde}other{# sekundes}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# stunda}zero{# stundu}one{# stunda}other{# stundas}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minūte}zero{# minūšu}one{# minūte}other{# minūtes}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# sekunde}zero{# sekunžu}one{# sekunde}other{# sekundes}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Atgādinājumi par atļauju"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 neizmantota lietotne"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> neizmantotas lietotnes"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Dažas lietotnes nav izmantotas vairākus mēnešus. Pieskarieties, lai tās skatītu."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# neizmantota lietotne}zero{# neizmantotu lietotņu}one{# neizmantota lietotne}other{# neizmantotas lietotnes}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Atļaujas un pagaidu faili ir noņemti, un paziņojumi ir apturēti. Pieskarieties, lai to pārskatītu."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Pārskatiet lietotnes, kam piešķirtās atļaujas tika atsauktas"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Lietotnēm, ko kādu laiku neesat izmantojis, tika atsauktas atļaujas, noņemti pagaidu faili un apturēti paziņojumi."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Pārskatīt lietotnes"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Skatiet nesen piešķirtās atļaujas"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Braukšanas laikā jūs piešķīrāt lietotnei <xliff:g id="APP">%1$s</xliff:g> atļauju “<xliff:g id="PERMISSION">%2$s</xliff:g>”."</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Braukšanas laikā jūs piešķīrāt lietotnei <xliff:g id="APP">%1$s</xliff:g> atļaujas “<xliff:g id="PERMISSION_1">%2$s</xliff:g>” un “<xliff:g id="PERMISSION_2">%3$s</xliff:g>”."</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Lai aizsargātu jūsu konfidencialitāti, atļaujas ir noņemtas."</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"Lietotne <xliff:g id="APP_NAME">%s</xliff:g> ieguva jūsu atrašanās vietas informāciju fonā"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Šī lietotne jebkurā laikā var piekļūt jūsu atrašanās vietai. Pieskarieties, lai mainītu šo iestatījumu."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Pārskatiet lietotni ar piekļuvi paziņojumiem"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"Lietotne <xliff:g id="APP_NAME">%s</xliff:g> var piekļūt saturam jūsu paziņojumos, noraidīt tos un veikt ar tiem citas darbības."</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Šī lietotne var piekļūt saturam jūsu paziņojumos, noraidīt tos un veikt ar tiem citas darbības. Dažām lietotnēm ir nepieciešama šāda piekļuve, lai tās darbotos, kā paredzēts."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Noņemt piekļuvi"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Skatīt citas iespējas"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Piekļuve ir noņemta"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Pārskatiet lietotni ar pilnīgu piekļuvi ierīcei"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> var skatīt jūsu ekrānu un veikt darbības jūsu ierīcē. Lai pieejamības lietotnes darbotos, kā paredzēts, tām ir nepieciešama šāda veida piekļuve."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Šī lietotne var skatīt jūsu ekrānu un veikt darbības jūsu ierīcē. Lai pieejamības lietotnes darbotos, kā paredzēts, tām ir nepieciešama šāda veida piekļuve, taču pārbaudiet lietotni un apsveriet, vai tai uzticaties."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Noņemt piekļuvi"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Skatīt lietotnes ar pilnīgu piekļuvi"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Piekļuve ir noņemta"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android sistēma"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Lietotņu atļaujas noņemtas, lai aizsargātu konfidencialitāti"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Lietotne <xliff:g id="APP_NAME">%s</xliff:g> nav izmantota vairākus mēnešus. Lai pārskatītu izmaiņas, pieskarieties."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> un vēl 1 lietotne nav izmantota vairākus mēnešus. Lai pārskatītu izmaiņas, pieskarieties."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"Lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g> tiks atļauts mijiedarboties ar jūsu paziņojumiem un piekļūt šādām atļaujām: Tālrunis, Īsziņas, Kontaktpersonas un Kalendārs."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"Lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g> tiks atļauts mijiedarboties ar jūsu paziņojumiem un straumēt jūsu lietotņu saturu uz pievienoto ierīci."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Izmantojot šo pakalpojumu, jūsu tālruņa fotoattēli, multivides saturs un paziņojumi tiek kopīgoti ar citām ierīcēm."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Noklusējuma piezīmju lietotne"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Kontrolētās atļaujas"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Atrašanās vietas datiem var piekļūt."</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"IT administrators ir atļāvis lietotnei <xliff:g id="APP_NAME">%s</xliff:g> piekļūt jūsu atrašanās vietas datiem."</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Lietotnēm un pakalpojumiem"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Mikrofona dati joprojām var tikt kopīgoti, kad zvanīsiet uz ārkārtas numuru."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Mainīt"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Drošība un konfidencialitāte"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Pārbaudīt"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Drošība un konfidencialitāte"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Skenēt ierīci"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Noraidīt"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Vai nerādīt šo brīdinājumu?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Lai pievienotu papildu aizsardzību, jebkurā brīdī varat pārskatīt drošības un konfidencialitātes iestatījumus"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Nerādīt"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Atcelt"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Iestatījumi"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Drošības un konfidencialitātes statuss. <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">"Drošības iestatījumi"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Sensora atļaujas"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Konfidencialitātes vadīklas"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Atļaujas"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Drošība un konfidencialitāte"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Pārbaudiet statusu"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Konfidencialitātes vadīklas"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Citi iestatījumi"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Piekļuve kamerai"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Piekļuve mikrofonam"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Atļauja ir noņemta"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Skatīt vairāk kameras lietojuma datu"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Skatīt vairāk mikrofona lietojuma datu"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Noņemt kameras atļauju"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Noņemt mikrofona atļauju"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Skatīt nesenos kameras lietojuma datus"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Skatīt nesenos mikrofona lietojuma datus"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Noņemt atļauju šai lietotnei"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Noņemt atļauju šai lietotnei"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Pārvaldīt pakalpojumu"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Pārvaldīt atļaujas"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"To izmanto tālruņa zvans"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Nesen to izmantoja lietotne <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">"To izmanto lietotne <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">"Nesen to izmantoja lietotne <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Drošība un konfidencialitāte"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Pārbaudiet statusu"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Apstiprināt"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Atpakaļ"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Tiks sniegta piekļuve arī citiem failiem"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Šī lietotne neatbalsta jaunāko Android versiju. Ja šī lietotne nevar piekļūt mūzikas un audio failiem, tai netiks atļauts piekļūt arī fotoattēliem un video."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Šī lietotne neatbalsta jaunāko Android versiju. Ja šī lietotne var piekļūt fotoattēliem un video, tai tiks atļauts piekļūt arī mūzikai un audio failiem."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Šī lietotne neatbalsta jaunāko Android versiju. Ja šī lietotne nevar piekļūt mūzikas un audio failiem, tai netiks atļauts piekļūt arī fotoattēliem un video."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Pārskatiet lietotni ar piekļuvi atrašanās vietas datiem fonā"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> var piekļūt atrašanās vietas datiem vienmēr, pat ja šī lietotne ir aizvērta"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Pārskatiet lietotni ar piekļuvi atrašanās vietas datiem fonā"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Šī lietotne vienmēr var piekļūt jūsu atrašanās vietas datiem, pat ja tā ir aizvērta.\n\nDažu drošības un ārkārtas palīdzības lietotņu pienācīgai darbībai ir nepieciešama piekļuve atrašanās vietas datiem fonā."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Piekļuve ir mainīta"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Skatīt, kā nesen ir lietoti atrašanās vietas dati"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Konfidencialitātes vadīklas"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Piekļuve kamerai"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Piekļuve mikrofonam"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Lietotnēm un pakalpojumiem"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Lietotnēm un pakalpojumiem. Ja šis iestatījums ir izslēgts, mikrofona dati joprojām var tikt kopīgoti, kad zvanīsiet uz ārkārtas numuru."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Skatīt lietotnes un pakalpojumus, kas var piekļūt atrašanās vietai"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Rādīt paziņojumus par piekļuvi starpliktuvei"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Rādīt ziņojumu, kad lietotnes piekļūst jūsu nokopētajam tekstam, attēliem vai citam saturam"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Rādīt paroles"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Rakstot tiek īslaicīgi rādītas rakstzīmes"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Datu apstrāde var atšķirties atkarībā no lietotnes versijas un izmantojuma, kā arī jūsu reģiona un vecuma. "<annotation id="link">"Uzziniet vairāk par datu kopīgošanu."</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Datu apstrāde var atšķirties atkarībā no lietotnes versijas un izmantojuma, kā arī jūsu reģiona un vecuma."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Jūsu atrašanās vietas dati"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Varat mainīt šīs lietotnes piekļuvi "<annotation id="link">"konfidencialitātes iestatījumos"</annotation>"."</string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Lietotnes funkcionalitāte"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analīze"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Izstrādātāja saziņa"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Reklamēšana vai mārketings"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Krāpšanas novēršana, drošība un atbilstības nodrošināšana"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalizēšana"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Konta pārvaldība"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Šo lietotņu izstrādātāji sniedza kādam lietotņu veikalam informāciju par datu kopīgošanas praksi. Laika gaitā viņi var šo informāciju atjaunināt.\n\nDatu kopīgošanas prakse var atšķirties atkarībā no lietotnes versijas un izmantojuma, kā arī jūsu reģiona un vecuma."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Uzzināt vairāk par datu kopīgošanu"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Jūsu atrašanās vietas dati tagad tiek kopīgoti ar trešajām pusēm."</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Jūsu atrašanās vietas dati tagad tiek kopīgoti ar trešajām pusēm reklamēšanas vai mārketinga nolūkos."</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Atjaunināta pēdējās diennakts laikā}=1{Atjaunināta pēdējās diennakts laikā}zero{Atjaunināta pēdējo # dienu laikā}one{Atjaunināta pēdējo # dienu laikā}other{Atjaunināta pēdējo # dienu laikā}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Šobrīd nav atjauninājumu"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-mk-v33/strings.xml b/PermissionController/res/values-mk-v33/strings.xml
index 9730afb33..95896fb8e 100644
--- a/PermissionController/res/values-mk-v33/strings.xml
+++ b/PermissionController/res/values-mk-v33/strings.xml
@@ -19,4 +19,28 @@
<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="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>
+ <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>
+ <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{Проширете и видете уште # предупредувањa}}"</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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Затвори"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Прошири и прикажи ги опциите"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Собери"</string>
+ <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_gear_label" msgid="5175877094379694098">"Поставки"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Информации"</string>
</resources>
diff --git a/PermissionController/res/values-mk-v34/strings.xml b/PermissionController/res/values-mk-v34/strings.xml
new file mode 100644
index 000000000..e8f9afc25
--- /dev/null
+++ b/PermissionController/res/values-mk-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-mk/strings.xml b/PermissionController/res/values-mk/strings.xml
index 7591ec806..d8c542b76 100644
--- a/PermissionController/res/values-mk/strings.xml
+++ b/PermissionController/res/values-mk/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"Секогаш дозволувај ги сите"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Откривме преклопување на екранот"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"За да ја измените оваа поставка за дозвола, прво мора да го исклучите преклопувањето на екранот од „Поставки &gt; Апликации“"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Отвори ги поставките"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 ден}one{# ден}other{# дена}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 час}one{# час}other{# часа}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 мин.}one{# мин.}other{# мин.}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 сек.}one{# сек.}other{# сек.}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# ден}one{# ден}other{# дена}}"</string>
+ <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_time" msgid="3802087027301631827">"Кога било"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Минатите 7 дена"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Минатите 24 часа"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Минатиот час"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Минатите 15 минути"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Последна 1 минута"</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>
+ <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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"Не е користена во минатите 24 часа"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Не е користена во минатите 7 дена"</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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"Секогаш дозволувај ги сите"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Прашувај секогаш"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Не дозволувај"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Прецизна локација"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Дозволите за <xliff:g id="PERM_0">%1$s</xliff:g> и <xliff:g id="PERM_1">%2$s</xliff:g> ќе се отстранат."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Дозволи што ќе се отстранат: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Автоматско управување со дозволите"</string>
- <string name="off" msgid="1438489226422866263">"Исклучи"</string>
<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_tv_summary" msgid="3685907153054355671">"Ако некоја апликација не се користи неколку месеци:\n\n• Дозволите се отстрануваат за да се заштитат вашите податоци\n• Привремените датотеки се отстрануваат за да се ослободи простор\n\nЗа да ги овозможите дозволите повторно, отворете ја апликацијата."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Последно отворени пред повеќе од <xliff:g id="NUMBER">%s</xliff:g> месеци"</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>
<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>
@@ -251,9 +254,9 @@
<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{# ден}other{# дена}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 час}one{# час}other{# часа}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 минута}one{# минута}other{# минути}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 секунда}one{# секунда}other{# секунди}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# час}one{# час}other{# часа}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# минута}one{# минута}other{# минути}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# секунда}one{# секунда}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>
@@ -262,6 +265,9 @@
<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>
+ <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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Систем Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Дозволите за аплик. се отстранети за заштита на приватноста"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> не е користена неколку месеци. Допрете за да прегледате."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> и уште 1 апликација не се користени неколку месеци. Допрете за да прегледате."</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"белешки"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"Контролирани дозволи"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Може да се пристапи до локацијата"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"IT-администраторот дозволува <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"Безбедност и приватност"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Скенирај"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"Дозволи за сензор"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Контроли за приватност"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"Дозволата е отстранета"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Видете повеќе начини на користење на камерата"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Видете повеќе начини на користење на микрофонот"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Отстранете ја дозволата за камерата"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Отстранете ја дозволата за микрофонот"</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="manage_service_qs" msgid="7862555549364153805">"Управувајте со услугата"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Управувајте со дозволите"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Се користи од телефонски повик"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Безбедност и приватност"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Проверете го статусот"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Комуникација со програмерот"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Ажурирано во текот на минатиот ден}=1{Ажурирано во текот на минатиот ден}one{Ажурирано во текот на минатите # ден}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>
</resources>
diff --git a/PermissionController/res/values-ml-v33/strings.xml b/PermissionController/res/values-ml-v33/strings.xml
index f37fa2ffa..fec0f6707 100644
--- a/PermissionController/res/values-ml-v33/strings.xml
+++ b/PermissionController/res/values-ml-v33/strings.xml
@@ -19,4 +19,28 @@
<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="work_policy_title" msgid="832967780713677409">"നിങ്ങളുടെ ഔദ്യോഗിക നയ വിവരങ്ങൾ"</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>
+ <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{വികസിപ്പിച്ച് ഒരു മുന്നറിയിപ്പ് കൂടി കാണുക}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"അടയ്ക്കുക"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"വികസിപ്പിച്ച് ഓപ്ഷനുകൾ കാണിക്കുക"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"ചുരുക്കുക"</string>
+ <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_gear_label" msgid="5175877094379694098">"ക്രമീകരണം"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"വിവരങ്ങൾ"</string>
</resources>
diff --git a/PermissionController/res/values-ml-v34/strings.xml b/PermissionController/res/values-ml-v34/strings.xml
new file mode 100644
index 000000000..7f22bbf9c
--- /dev/null
+++ b/PermissionController/res/values-ml-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-ml/strings.xml b/PermissionController/res/values-ml/strings.xml
index d1fb46999..81cf39cf5 100644
--- a/PermissionController/res/values-ml/strings.xml
+++ b/PermissionController/res/values-ml/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"എപ്പോഴും എല്ലാം അനുവദിക്കുക"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"സ്ക്രീൻ ഓവർലേ കണ്ടെത്തി"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"ഈ അനുമതി ക്രമീകരണം മാറ്റുന്നതിന്, ക്രമീകരണം &gt; ആപ്പുകൾ എന്നതിൽ നിന്ന് നിങ്ങളാദ്യം സ്ക്രീൻ ഓവർലേ ഓഫാക്കേണ്ടതാണ്"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"ക്രമീകരണം തുറക്കുക"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{ഒരു ദിവസം}other{# ദിവസം}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{ഒരു മണിക്കൂർ}other{# മണിക്കൂർ}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{ഒരു മിനിറ്റ്}other{# മിനിറ്റ്}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{ഒരു സെക്കൻഡ്}other{# സെക്കൻഡ്}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# ദിവസം}other{# ദിവസം}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# മണിക്കൂർ}other{# മണിക്കൂർ}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# മിനിറ്റ്}other{# മിനിറ്റ്}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# സെക്കൻഡ്}other{# സെക്കൻഡ്}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"ഏതെങ്കിലും അനുമതി"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"ഏത് സമയത്തും"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"കഴിഞ്ഞ 7 ദിവസം"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"അവസാന 24 മണിക്കൂർ"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"കഴിഞ്ഞ ഒരു മണിക്കൂര്‍‌"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"കഴിഞ്ഞ 15 മിനിറ്റ്"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"അവസാന ഒരു മിനിറ്റ്"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{അവസാന # ദിവസം}other{അവസാന # ദിവസം}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{അവസാന # മണിക്കൂർ}other{അവസാന # മണിക്കൂർ}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{അവസാന # മിനിറ്റ്}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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"കഴിഞ്ഞ 24 മണിക്കൂറിനിടെ ഉപയോഗിച്ചിട്ടില്ല"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"കഴിഞ്ഞ 7 ദിവസത്തിനിടെ ഉപയോഗിച്ചിട്ടില്ല"</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{ഒരു ആപ്പ് ഉപയോഗിച്ചു}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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"എപ്പോഴും എല്ലാം അനുവദിക്കുക"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"എപ്പോഴും ചോദിക്കുക"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"അനുവദിക്കരുത്"</string>
<string name="precise_image_description" msgid="6349638632303619872">"കൃത്യമായ ലൊക്കേഷൻ"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g>, <xliff:g id="PERM_1">%2$s</xliff:g> എന്നിവയ്ക്കുള്ള അനുമതികൾ നീക്കം ചെയ്യപ്പെടും."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"നീക്കം ചെയ്യപ്പെടുന്ന അനുമതികൾ: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"അനുമതികൾ സ്വയമേവ മാനേജ് ചെയ്യുക"</string>
- <string name="off" msgid="1438489226422866263">"ഓഫാക്കുക"</string>
<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_tv_summary" msgid="3685907153054355671">"ഒരു ആപ്പ് കുറച്ച് മാസം ഉപയോഗിക്കാതിരുന്നാൽ:\n\n• നിങ്ങളുടെ ഡാറ്റ സംരക്ഷിക്കുന്നതിന് അനുമതികൾ നീക്കം ചെയ്യും\n• ഇടമുണ്ടാക്കാൻ താൽക്കാലിക ഫയലുകൾ നീക്കം ചെയ്യും\n\nവീണ്ടും അനുമതികൾ അനുവദിക്കാൻ ആപ്പ് തുറക്കുക."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"അവസാനം തുറന്നിട്ട് <xliff:g id="NUMBER">%s</xliff:g> മാസത്തിൽ കൂടുതലായവ"</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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"അനുവദിച്ചിട്ടില്ല"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"എല്ലാ ഫയലുകളും ആക്‌സസ് ചെയ്യാൻ കഴിയുന്ന കൂടുതൽ ആപ്പുകൾ കാണുക"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{ഒരു ദിവസം}other{# ദിവസം}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{ഒരു മണിക്കൂർ}other{# മണിക്കൂർ}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{ഒരു മിനിറ്റ്}other{# മിനിറ്റ്}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{ഒരു സെക്കൻഡ്}other{# സെക്കൻഡ്}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# മണിക്കൂർ}other{# മണിക്കൂർ}}"</string>
+ <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">"ഒരു ഉപയോഗിക്കാത്ത ആപ്പ്"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> ഉപയോഗിക്കാത്ത ആപ്പുകൾ"</string>
@@ -262,6 +265,9 @@
<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_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_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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android സിസ്റ്റം"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"സ്വകാര്യത പരിരക്ഷിക്കാൻ ആപ്പ് അനുമതികൾ നീക്കം ചെയ്തു"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"കുറച്ച് മാസങ്ങളായി <xliff:g id="APP_NAME">%s</xliff:g> ഉപയോഗിച്ചിട്ടില്ല. അവലോകനം ചെയ്യുന്നതിന് ടാപ്പ് ചെയ്യുക."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> എന്നതും മറ്റൊരു ആപ്പും കുറച്ച് മാസങ്ങളായി ഉപയോഗിച്ചിട്ടില്ല. അവലോകനം ചെയ്യുന്നതിന് ടാപ്പ് ചെയ്യുക."</string>
@@ -378,6 +397,10 @@
<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_short_label" msgid="8796604147546125285">"കുറിപ്പ് ആപ്പ്"</string>
+ <string name="role_notes_description" msgid="8496852798616883551">"നിങ്ങളുടെ ഉപകരണത്തിൽ കുറിപ്പുകൾ രേഖപ്പെടുത്താൻ അനുവദിക്കുന്ന ആപ്പുകൾ"</string>
+ <string name="role_notes_search_keywords" msgid="7710756695666744631">"കുറിപ്പുകൾ"</string>
<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>
@@ -452,6 +475,7 @@
<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_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_microphone" msgid="2825208549114811299">"ഓഡിയോ റെക്കോർഡ് ചെയ്യാൻ &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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"നിയന്ത്രിത അനുമതികൾ"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"ലൊക്കേഷൻ ആക്‌സസ് ചെയ്യാൻ കഴിയും"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"നിങ്ങളുടെ ലൊക്കേഷൻ ആക്‌സസ് ചെയ്യാൻ നിങ്ങളുടെ ഐടി അഡ്‌മിൻ <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"സുരക്ഷയും സ്വകാര്യതയും"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"സ്‌കാൻ ചെയ്യുക"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"സെൻസർ അനുമതികൾ"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"സ്വകാര്യതാ നിയന്ത്രണങ്ങൾ"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"അനുമതി നീക്കം ചെയ്തു"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"കൂടുതൽ ക്യാമറാ ഉപയോഗം കാണുക"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"കൂടുതൽ മൈക്രോഫോൺ ഉപയോഗം കാണുക"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"ക്യാമറാ അനുമതി നീക്കം ചെയ്യുക"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"മൈക്രോഫോൺ അനുമതി നീക്കം ചെയ്യുക"</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="manage_service_qs" msgid="7862555549364153805">"സേവനം മാനേജ് ചെയ്യുക"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"അനുമതികൾ മാനേജ് ചെയ്യുക"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"ഫോൺ കോൾ ഉപയോഗിക്കുന്നു"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"സുരക്ഷയും സ്വകാര്യതയും"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"നില പരിശോധിക്കുക"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"ഡെവലപ്പർ നടത്തുന്ന ആശയവിനിമയങ്ങൾ"</string>
+ <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="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="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="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>
</resources>
diff --git a/PermissionController/res/values-mn-v33/strings.xml b/PermissionController/res/values-mn-v33/strings.xml
index f63db6c49..327723433 100644
--- a/PermissionController/res/values-mn-v33/strings.xml
+++ b/PermissionController/res/values-mn-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Энэ аппыг танд Мэдэгдэл илгээхийг зөвшөөрөх бөгөөд үүнд таны Камер, Харилцагчид, Микрофон, Утас болон SMS-д хандах эрх өгнө"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Энэ аппад танд Мэдэгдэл илгээхийг зөвшөөрөх бөгөөд үүнд таны Камер, Харилцагчид, Files, Микрофон, Утас болон SMS-д хандах эрх өгнө"</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>
+ <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>
+ <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{Дэлгээд дахин нэг анхааруулга харах}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Хаах"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Сонголтуудыг дэлгэж харуулах"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Хураах"</string>
+ <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_gear_label" msgid="5175877094379694098">"Тохиргоо"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Мэдээлэл"</string>
</resources>
diff --git a/PermissionController/res/values-mn-v34/strings.xml b/PermissionController/res/values-mn-v34/strings.xml
new file mode 100644
index 000000000..fc5ac1818
--- /dev/null
+++ b/PermissionController/res/values-mn-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-mn/strings.xml b/PermissionController/res/values-mn/strings.xml
index c5ec87f1a..3332fe450 100644
--- a/PermissionController/res/values-mn/strings.xml
+++ b/PermissionController/res/values-mn/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"Бүгдийг үргэлж зөвшөөрөх"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Дэлгэцэд давхарлахыг илрүүллээ"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Энэ зөвшөөрлийн тохиргоог өөрчлөхийн тулд эхлээд Тохиргоо &gt; Аппууд хэсэгт дэлгэцэд давхарлахыг унтраах шаардлагатай."</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Тохиргоог нээх"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 өдөр}other{# өдөр}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 цаг}other{# цаг}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 мин}other{# мин}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 сек}other{# сек}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# хоног}other{# хоног}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# цаг}other{# цаг}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# мин}other{# мин}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# сек}other{# сек}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Дурын зөвшөөрөл"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Дурын хугацаа"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Сүүлийн 7 хоног"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Сүүлийн 24 цаг"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Сүүлийн 1 цаг"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Сүүлийн 15 минут"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Сүүлийн 1 минут"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Сүүлийн # хоног}other{Сүүлийн # хоног}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Сүүлийн # цаг}other{Сүүлийн # цаг}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Сүүлийн # минут}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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"Өнгөрсөн 24 цагт ашиглаагүй"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Өнгөрсөн 7 хоногт ашиглаагүй"</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_view_details" msgid="6675335735468752787">"Хяналтын самбараас бүгдийг нь харах"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Шүүсэн: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"Бүгдийг үргэлж зөвшөөрөх"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Тухай бүрд асуух"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Бүү зөвшөөр"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Нарийвчилсан байршил"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> болон <xliff:g id="PERM_1">%2$s</xliff:g> зөвшөөрлүүдийг хасна."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Хасах зөвшөөрлүүд: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Зөвшөөрлийг автоматаар удирдах"</string>
- <string name="off" msgid="1438489226422866263">"Унтраах"</string>
<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_tv_summary" msgid="3685907153054355671">"Хэрэв аппыг хэдэн сар ашиглаагүй бол:\n\n• Таны өгөгдлийг хамгаалахын тулд зөвшөөрлийг хасна\n• Сул зай гаргахын тулд түр зуурын файлууыг хасна\n\nЗөвшөөрлийг дахин олгохын тулд аппыг нээнэ үү."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Хамгийн сүүлд <xliff:g id="NUMBER">%s</xliff:g>-с олон сарын өмнө нээсэн"</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>
@@ -251,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 цаг}other{# цаг}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 минут}other{# минут}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 секунд}other{# секунд}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# цаг}other{# цаг}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<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_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_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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android систем"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Апп-н зөвшөөрлийг таны нууцлалыг хамгаалахын тулд хассан"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> аппыг хэдэн сарын турш ашиглаагүй байна. Шалгахын тулд товшино уу."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> болон өөр 1 аппыг хэдэн сарын турш ашиглаагүй байна. Шалгахын тулд товшино уу."</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"тэмдэглэл"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"Хяналттай зөвшөөрөл"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Байршилд хандах боломжтой"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Таны IT админ таны байршилд хандахыг <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"Аюулгүй байдал &amp; нууцлал"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Скан хийх"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"Мэдрэгчийн зөвшөөрөл"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Нууцлалын тохиргоо"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"Зөвшөөрлийг хассан"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Камерын бусад ашиглалтыг харах"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Микрофоны бусад ашиглалтыг харах"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Камерын зөвшөөрлийг хасах"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Микрофоны зөвшөөрлийг хасах"</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="manage_service_qs" msgid="7862555549364153805">"Үйлчилгээг удирдах"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Зөвшөөрлийг удирдах"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Утасны дуудлага ашиглаж байна"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Аюулгүй байдал &amp; нууцлал"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Төлөвийг шалгах"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Хөгжүүлэгчийн харилцаа холбоо"</string>
+ <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="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="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="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>
</resources>
diff --git a/PermissionController/res/values-mr-v33/strings.xml b/PermissionController/res/values-mr-v33/strings.xml
index 06b62f3ed..cea91a4b2 100644
--- a/PermissionController/res/values-mr-v33/strings.xml
+++ b/PermissionController/res/values-mr-v33/strings.xml
@@ -19,4 +19,28 @@
<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_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>
+ <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{विस्तार करा आणि आणखी एक सूचना पहा}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"बंद करा"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"विस्तार करून पर्याय दाखवा"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"कोलॅप्स करा"</string>
+ <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_gear_label" msgid="5175877094379694098">"सेटिंग्ज"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"माहिती"</string>
</resources>
diff --git a/PermissionController/res/values-mr-v34/strings.xml b/PermissionController/res/values-mr-v34/strings.xml
new file mode 100644
index 000000000..8c9152379
--- /dev/null
+++ b/PermissionController/res/values-mr-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-mr/strings.xml b/PermissionController/res/values-mr/strings.xml
index 8b4000903..18eccb6a7 100644
--- a/PermissionController/res/values-mr/strings.xml
+++ b/PermissionController/res/values-mr/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"नेहमी सर्वांना अनुमती द्या"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"स्क्रीन ओव्हरले आढळले"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"हे परवानगी सेटिंग बदलण्‍यासाठी, तुम्हाला सेटिंग्ज &gt; अ‍ॅप्स मधून स्क्रीन ओव्हरले बंद करावे लागेल"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"सेटिंग्ज उघडा"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"ॲप्सनी मागील सात दिवसांमध्ये तुमचे <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{एक दिवस}other{# दिवस}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{एक तास}other{# तास}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{एक मिनिट}other{# मिनिटे}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{एक सेकंद}other{# सेकंद}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# दिवस}other{# दिवस}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# तास}other{# तास}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# मिनिट}other{# मिनिटे}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# सेकंद}other{# सेकंद}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"कोणतीही परवानगी"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"कधीही"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"शेवटचे सात दिवस"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"गेल्या २४ तासात"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"शेवटचा एक तास"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"शेवटची १५ मिनिटे"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"शेवटचा एक मिनिट"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{शेवटचा # दिवस}other{शेवटचे # दिवस}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{मागील # तासामधील}other{मागील # तासांमधील}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{मागील # मिनिटामधील}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">"मागील सात दिवसांतील सर्वात अलीकडील अ‍ॅक्सेस"</string>
@@ -158,8 +161,8 @@
<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_preference_summary_not_used_24h" msgid="3087783232178611025">"मागील २४ तासांमध्ये न वापरलेली"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"मागील सात दिवसांमध्ये न वापरलेली"</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{एका अ‍ॅपने वापरल्या}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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"सर्वांना नेहमी अनुमती द्या"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"प्रत्येक वेळी विचारा"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"अनुमती देऊ नका"</string>
<string name="precise_image_description" msgid="6349638632303619872">"अचूक स्थान"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> आणि <xliff:g id="PERM_1">%2$s</xliff:g> परवानग्या काढून टाकल्या जातील."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"परवानग्या काढून टाकल्या जातील: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"परवानग्या आपोआप व्यवस्थापित करा"</string>
- <string name="off" msgid="1438489226422866263">"बंद करा"</string>
<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_tv_summary" msgid="3685907153054355671">"एखादे ॲप काही महिन्यांसाठी वापरले गेले नसल्यास:\n\n• तुमच्या डेटाचे संरक्षण करण्यासाठी परवानग्या काढून टाकल्या जातात\n• जागा मोकळी करण्याकरिता तात्पुरत्या फाइल काढून टाकल्या जातात\n\nपुन्हा परवानग्या देण्यासाठी, ॲप उघडा."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"शेवटची <xliff:g id="NUMBER">%s</xliff:g> महिन्यांपूर्वी उघडली गेली"</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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"अनुमती नाही"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"सर्व फाइलचा ॲक्सेस असलेली आणखी ॲप्स पहा"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{एक दिवस}other{# दिवस}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{एक तास}other{# तास}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{एक मिनिट}other{# मिनिटे}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{एक सेकंद}other{# सेकंद}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# तास}other{# तास}}"</string>
+ <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">"एक न वापरलेले ॲप"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> न वापरलेली अ‍ॅप्स"</string>
@@ -262,6 +265,9 @@
<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_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_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>
<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> &amp; <xliff:g id="PERMISSION_2">%3$s</xliff:g> चा अ‍ॅक्सेस दिला आहे"</string>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android सिस्‍टीम"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"गोपनीयता संरक्षित करण्यासाठी अ‍ॅप परवानग्या काढून टाकल्या"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> काही महिन्यांपासून वापरलेले नाही. परीक्षण करण्यासाठी टॅप करा."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> आणि एक इतर ॲप काही महिन्यांपासून वापरलेले नाही. परीक्षण करण्यासाठी टॅप करा."</string>
@@ -378,6 +397,10 @@
<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_description" msgid="8496852798616883551">"तुमच्या डिव्हाइसवर तुम्हाला टिपा घेण्याची अनुमती देणारी अ‍ॅप्स"</string>
+ <string name="role_notes_search_keywords" msgid="7710756695666744631">"टिपा"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"नियंत्रित परवानग्या"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"स्थान अ‍ॅक्सेस करता येऊ शकते"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"तुमचा आयटी ॲडमिन <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"सुरक्षा आणि गोपनीयता"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"स्कॅन करा"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"सेन्सर परवानग्या"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"गोपनीयता नियंत्रणे"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"परवानग्या काढून टाकल्या"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"कॅमेराचे आणखी वापर पहा"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"मायक्रोफोनचे आणखी वापर पहा"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"कॅमेरा परवानगी काढून टाका"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"मायक्रोफोन परवानगी काढून टाका"</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="manage_service_qs" msgid="7862555549364153805">"सेवा व्यवस्थापित करा"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"परवानग्या व्यवस्थापित करा"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"फोन कॉलद्वारे वापरले जात आहे"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"सुरक्षा आणि गोपनीयता"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"स्टेटस तपासा"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"डेव्हलपर संवाद"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Updated within the last day}=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>
</resources>
diff --git a/PermissionController/res/values-ms-v33/strings.xml b/PermissionController/res/values-ms-v33/strings.xml
index 7ff482562..d5540a429 100644
--- a/PermissionController/res/values-ms-v33/strings.xml
+++ b/PermissionController/res/values-ms-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Apl ini akan dibenarkan untuk menghantar Pemberitahuan kepada anda dan akan diberikan akses kepada Kamera, Kenalan, Mikrofon, Telefon dan SMS anda"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Apl ini akan dibenarkan menghantar Pemberitahuan kepada anda dan akan diberikan akses kepada Kamera, Kenalan, Fail, Mikrofon, Telefon dan SMS anda"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Apl dengan kebenaran ini boleh mengakses semua fail pada peranti ini"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Maklumat dasar kerja anda"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Tetapan diurus oleh pentadbir IT anda"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Kembangkan dan tunjukkan senarai"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Kuncupkan senarai dan sembunyikan tetapan"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Senarai. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Senarai. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Tindakan diperlukan. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Senaraikan item. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Tutup"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Kembangkan dan tunjukkan pilihan"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Kuncupkan"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Tukar. <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">"Togol"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Buka"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Semak tetapan"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Tetapan"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Maklumat"</string>
</resources>
diff --git a/PermissionController/res/values-ms-v34/strings.xml b/PermissionController/res/values-ms-v34/strings.xml
new file mode 100644
index 000000000..6fd21c7af
--- /dev/null
+++ b/PermissionController/res/values-ms-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Keselamatan &amp; privasi"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Kawalan"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Urus akses apl kepada data kesihatan"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Akses lokasi"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Untuk apl dan perkhidmatan. Jika tetapan ini dimatikan, data mikrofon mungkin masih dikongsi apabila anda memanggil nombor kecemasan"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Untuk apl dan perkhidmatan"</string>
+</resources>
diff --git a/PermissionController/res/values-ms/strings.xml b/PermissionController/res/values-ms/strings.xml
index 993333916..7e560fa73 100644
--- a/PermissionController/res/values-ms/strings.xml
+++ b/PermissionController/res/values-ms/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Kembali"</string>
<string name="available" msgid="6007778121920339498">"Tersedia"</string>
<string name="blocked" msgid="9195547604866033708">"Disekat"</string>
+ <string name="on" msgid="280241003226755921">"Hidup"</string>
+ <string name="off" msgid="1438489226422866263">"Mati"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Nyahpasang atau lumpuhkan"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Apl tidak ditemui"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Jangan benarkan"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Kekalkan “Semasa apl sedang digunakan”"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Simpan “Kali ini sahaja”"</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Jangan benarkan juga"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Tolak"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> daripada <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Tindanan skrin dikesan"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Untuk menukar tetapan kebenaran ini, anda perlu mematikan tindanan skrin daripada Tetapan &gt; Apl dahulu"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Buka tetapan"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Garis masa aplikasi menggunakan<xliff:g id="PERMGROUP">%1$s</xliff:g> anda dalam tempoh 7 hari yang lalu"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Apabila apl ini menggunakan kebenaran <xliff:g id="PERMGROUP">%1$s</xliff:g> anda"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Ketahui lebih lanjut"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Ketahui lebih lanjut tentang <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Kawal akses apl kepada <xliff:g id="PERMGROUP">%1$s</xliff:g> anda"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 hari}other{# hari}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 jam}other{# jam}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 saat}other{# saat}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# hari}other{# hari}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# jam}other{# jam}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# saat}other{# saat}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Sebarang kebenaran"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Pada bila-bila masa"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"7 hari yang lalu"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"24 jam yang lalu"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Sejam yang lalu"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"15 minit yang lalu"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"1 minit terakhir"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{# hari yang lalu}other{# hari yang lalu}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{# jam yang lalu}other{# jam yang lalu}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{# minit yang lalu}other{# minit yang lalu}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Tiada penggunaan kebenaran"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Akses terbaharu pada bila-bila masa"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Akses terbaharu dalam 7 hari terakhir"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Penggunaan kebenaran dalam 1 jam terakhir"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Penggunaan kebenaran dalam 15 minit terakhir"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Penggunaan kebenaran dalam 1 minit terakhir"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Tidak digunakan dalam tempoh 24 jam yang lalu"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Tidak digunakan dalam tempoh 7 hari yang lalu"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Tidak digunakan dalam # hari yang lalu}other{Tidak digunakan dalam # hari yang lalu}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Tidak digunakan dalam # jam yang lalu}other{Tidak digunakan dalam # jam yang lalu}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Digunakan oleh 1 apl}other{Digunakan oleh # apl}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Lihat semua dalam Papan Pemuka"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Ditapis mengikut: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Benarkan akses kepada media sahaja"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Benarkan sepanjang masa"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Benarkan hanya semasa menggunakan apl"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Sentiasa benarkan semua"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Tanya setiap kali"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Jangan benarkan"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Lokasi tepat"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> dan <xliff:g id="PERM_1">%2$s</xliff:g> kebenaran akan dialih keluar."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Kebenaran yang akan dialih keluar: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Urus kebenaran secara automatik"</string>
- <string name="off" msgid="1438489226422866263">"Mati"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Kebenaran <xliff:g id="PERMISSION_NAME">%s</xliff:g> dialih keluar"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Kebenaran <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> dan <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> dialih keluar"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> dan <xliff:g id="NUMBER">%2$s</xliff:g> kebenaran lain dialih keluar"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Apl yang tidak digunakan"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Jika apl tidak digunakan selama beberapa bulan:\n\n• Kebenaran dialih keluar untuk melindungi data anda\n• Pemberitahuan diberhentikan untuk menjimatkan bateri\n• Fail sementara dialih keluar untuk mengosongkan ruang\n\nUntuk memberikan kebenaran dan pemberitahuan lagi, buka apl tersebut."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Jika apl tidak digunakan selama beberapa bulan:\n\n• Kebenaran dialih keluar untuk melindungi data anda\n• Fail sementara dialih keluar untuk mengosongkan ruang\n\nUntuk memberikan kebenaran lagi, buka apl tersebut."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Terakhir dibuka lebih <xliff:g id="NUMBER">%s</xliff:g> bulan yang lalu"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Jika apl tidak digunakan selama sebulan:\n\n• Kebenaran akan dialih keluar untuk melindungi data anda\n• Fail sementara akan dialih keluar untuk mengosongkan ruang\n\nUntuk memberikan kebenaran semula, buka apl tersebut."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Terakhir dibuka lebih # bulan yang lalu}other{Terakhir dibuka lebih # bulan yang lalu}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Apl dibuka kali terakhir pada <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Terakhir dibuka <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Jika anda membenarkan pengurusan semua fail, apl ini boleh mengakses, mengubah suai dan memadamkan sebarang fail dalam storan umum pada peranti ini atau peranti storan yang disambungkan. Apl ini mungkin mengakses fail tanpa bertanya anda."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Tidak dibenarkan"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Lihat lagi apl yang boleh mengakses semua fail"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 hari}other{# hari}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 jam}other{# jam}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minit}other{# minit}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 saat}other{# saat}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# jam}other{# jam}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minit}other{# minit}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# saat}other{# saat}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Peringatan kebenaran"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 apl tidak digunakan"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> apl yang tidak digunakan"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Sesetengah apl tidak digunakan selama beberapa bulan. Ketik untuk menyemak."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# apl yang tidak digunakan}other{# apl yang tidak digunakan}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Kebenaran dan fail sementara telah dialih keluar dan pemberitahuan telah dihentikan. Ketik untuk menyemak."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Semak apl dengan kebenaran dialih keluar"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Untuk apl yang sudah lama tidak digunakan, kebenaran dan fail sementara dialih keluar dan pemberitahuan dihentikan."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Semak apl"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Semak kebenaran terbaharu"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Semasa memandu, anda memberi <xliff:g id="APP">%1$s</xliff:g> akses kepada <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Semasa memandu, anda memberi <xliff:g id="APP">%1$s</xliff:g> akses kepada <xliff:g id="PERMISSION_1">%2$s</xliff:g> &amp; <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Kebenaran dialih keluar untuk melindungi privasi anda"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> mendapat lokasi anda di latar belakang"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Apl ini boleh mengakses lokasi anda pada setiap masa. Ketik untuk menukar."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Semak apl yang mempunyai akses kepada pemberitahuan anda"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> boleh mengetepikan, bertindak dan mengakses kandungan dalam pemberitahuan anda"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Apl ini boleh mengetepikan, bertindak dan mengakses kandungan dalam pemberitahuan anda. Sesetengah apl memerlukan akses ini untuk berfungsi sewajarnya."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Alih keluar akses"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Lihat lebih banyak pilihan"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Akses dialih keluar"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Semak apl dengan akses peranti penuh"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> boleh melihat skrin anda dan melaksanakan tindakan pada peranti anda. Apl kebolehcapaian memerlukan akses jenis ini untuk berfungsi sewajarnya."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Apl ini boleh melihat skrin anda dan melaksanakan tindakan pada peranti anda. Apl kebolehcapaian memerlukan akses jenis ini untuk berfungsi sewajarnya, tetapi semak apl dan pastikan anda mempercayai apl."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Alih keluar akses"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Lihat apl yang mempunyai akses penuh"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Akses dialih keluar"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Sistem Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Kebenaran apl dialih keluar untuk melindungi privasi"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> tidak digunakan selama beberapa bulan. Ketik untuk menyemak."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> dan 1 apl lain tidak digunakan selama beberapa bulan. Ketik untuk menyemak."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan dibenarkan berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan dan Kalendar anda."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan dibenarkan untuk berinteraksi dengan pemberitahuan anda dan menstrim apl anda pada peranti tersambung."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Perkhidmatan ini berkongsi foto, media dan pemberitahuan anda daripada telefon anda ke peranti lain."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Apl nota lalai"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_microphone" msgid="2825208549114811299">"Benarkan &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; merakam audio?"</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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Kebenaran terkawal"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Lokasi dapat diakses"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Pentadbir IT anda membenarkan <xliff:g id="APP_NAME">%s</xliff:g> mengakses lokasi anda"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Untuk apl dan perkhidmatan"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Data mikrofon mungkin masih dikongsi apabila anda memanggil nombor kecemasan."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Tukar"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Keselamatan &amp; Privasi"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Imbas"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Keselamatan &amp; privasi"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Imbas peranti"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Ketepikan"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Ketepikan makluman ini?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Semak tetapan keselamatan dan privasi anda pada bila-bila masa untuk menambahkan lagi perlindungan"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Ketepikan"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Batal"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Tetapan"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Status keselamatan dan privasi. <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">"Tetapan Keselamatan"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Kebenaran Penderia"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Kawalan Privasi"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Kebenaran"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Keselamatan &amp; privasi"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Semak status"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Kawalan privasi anda"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Lagi tetapan"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Akses kamera"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Akses mikrofon"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Kebenaran dialih keluar"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Lihat lebih banyak penggunaan kamera"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Lihat lebih banyak penggunaan mikrofon"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Alih keluar kebenaran kamera"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Alih keluar kebenaran mikrofon"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Lihat penggunaan kamera terkini"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Lihat penggunaan mikrofon terkini"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Alih keluar kebenaran untuk apl ini"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Alih keluar kebenaran untuk apl ini"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Urus perkhidmatan"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Urus kebenaran"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Sedang digunakan oleh panggilan telefon"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Digunakan baru-baru ini oleh <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">"Sedang digunakan oleh <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">"Digunakan baru-baru ini oleh <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Keselamatan &amp; Privasi"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Semak status"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Sahkan"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Kembali"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Akses kepada fail lain juga akan dibenarkan"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Apl ini tidak menyokong versi terkini Android. Jika apl ini tidak boleh mengakses fail muzik dan audio, apl ini juga akan tidak dibenarkan untuk mengakses foto dan video."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Apl ini tidak menyokong versi terkini Android. Jika apl ini boleh mengakses foto dan video, apl ini juga akan dibenarkan untuk mengakses fail muzik dan audio."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Apl ini tidak menyokong versi terkini Android. Jika apl ini tidak boleh mengakses fail muzik dan audio, apl ini juga akan tidak dibenarkan untuk mengakses foto dan video."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Semak apl yang mempunyai akses lokasi latar"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> sentiasa boleh mengakses lokasi anda walaupun semasa apl ditutup"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Semak apl yang mempunyai akses lokasi latar"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Apl ini boleh mengakses lokasi anda pada bila-bila masa walaupun semasa apl ditutup.\n\nSesetengah apl keselamatan dan kecemasan memerlukan akses kepada lokasi anda di latar untuk berfungsi seperti yang dimaksudkan."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Akses diubah"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Lihat penggunaan lokasi terkini"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Kawalan privasi"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Akses kamera"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Akses mikrofon"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Untuk apl dan perkhidmatan"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Untuk apl dan perkhidmatan. Jika tetapan ini dimatikan, data mikrofon mungkin masih dikongsi apabila anda memanggil nombor kecemasan."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Lihat apl dan perkhidmatan yang mempunyai akses kepada lokasi"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Tunjukkan akses papan keratan"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Tunjukkan mesej apabila apl mengakses teks, imej atau kandungan lain yang telah anda salin"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Tunjukkan kata laluan"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Paparkan aksara seketika sambil anda menaip"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Amalan privasi data mungkin berbeza-beza berdasarkan versi apl, penggunaan, rantau dan umur anda. "<annotation id="link">"Lagi tentang perkongsian data"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Amalan data mungkin berbeza-beza berdasarkan versi apl, penggunaan, rantau dan umur anda."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Data lokasi anda"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Tukar akses apl ini dalam "<annotation id="link">"tetapan privasi"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Fungsi apl"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analitis"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Komunikasi pembangun"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Pengiklanan atau pemasaran"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Pencegahan penipuan, keselamatan dan pematuhan"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Pemeribadian"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Pengurusan akaun"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Pembangun apl ini memberikan maklumat tentang amalan perkongsian data mereka kepada gedung apl. Mereka mungkin mengemaskinikan maklumat tersebut dari semasa ke semasa.\n\nAmalan perkongsian data mungkin berbeza-beza berdasarkan versi apl, penggunaan, wilayah dan umur anda."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Ketahui tentang perkongsian data"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Data lokasi anda kini dikongsi dengan pihak ketiga"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Data lokasi anda kini dikongsi dengan pihak ketiga untuk pengiklanan atau pemasaran"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Dikemaskinikan pada hari terakhir}=1{Dikemaskinikan pada hari terakhir}other{Dikemaskinikan dalam masa # hari}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Tiada kemaskinian pada masa ini"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-my-v33/strings.xml b/PermissionController/res/values-my-v33/strings.xml
index ea198405d..33237070b 100644
--- a/PermissionController/res/values-my-v33/strings.xml
+++ b/PermissionController/res/values-my-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"‘အကြောင်းကြားချက်များ’ သင့်ထံပို့ခွင့်ကို ဤအက်ပ်အား ပေးမည်ဖြစ်ပြီး သင်၏ ‘ကင်မရာ’၊ ‘အဆက်အသွယ်များ’၊ ‘မိုက်ခရိုဖုန်း’၊ ‘ဖုန်း’ နှင့် ‘SMS စာတိုစနစ်’ တို့ကို သုံးခွင့်ပေးပါမည်"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"‘အကြောင်းကြားချက်များ’ သင့်ထံပို့ခွင့်ကို ဤအက်ပ်အား ပေးမည်ဖြစ်ပြီး သင်၏ ‘ကင်မရာ’၊ ‘အဆက်အသွယ်များ’၊ Files၊ ‘မိုက်ခရိုဖုန်း’၊ ‘ဖုန်း’ နှင့် ‘SMS စာတိုစနစ်’ တို့ကို သုံးခွင့်ပေးပါမည်"</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>
+ <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>
+ <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{ချဲ့ပြီး သတိပေးချက်နောက်တစ်ခု ကြည့်ရန်}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"ပိတ်ရန်"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"ရွေးစရာများကို ချဲ့ပြရန်"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"လျှော့ပြရန်"</string>
+ <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_gear_label" msgid="5175877094379694098">"ဆက်တင်များ"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"အချက်အလက်"</string>
</resources>
diff --git a/PermissionController/res/values-my-v34/strings.xml b/PermissionController/res/values-my-v34/strings.xml
new file mode 100644
index 000000000..4d4e03401
--- /dev/null
+++ b/PermissionController/res/values-my-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-my/strings.xml b/PermissionController/res/values-my/strings.xml
index 72e2f5810..f83657838 100644
--- a/PermissionController/res/values-my/strings.xml
+++ b/PermissionController/res/values-my/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,11 +32,16 @@
<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_always_allow_all" msgid="1719900027660252167">"အားလုံး အမြဲခွင့်ပြုရန်"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"ဖန်သားပြင်တွင် ထပ်ဆင့်ပြသခြင်းကို ရှာတွေ့ခဲ့သည်"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"ဤခွင့်ပြုချက် ဆက်တင်ကိုပြောင်းရန် သင်သည် ဆက်တင်များ &gt; အက်ပ်များသို့ သွား၍ ဖန်သားပြင်တွင် ထပ်ဆင့်ပြသခြင်းကို အရင်ဆုံး ပိတ်ရပါမည်"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"ဆက်တင်များ ဖွင့်ရန်"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"ပြီးခဲ့သည့် ၇ ရက်အတွင်း <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 ရက်}other{# ရက်}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 နာရီ}other{# နာရီ}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{၁ မိနစ်}other{# မိနစ်}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{၁ စက္ကန့်}other{# စက္ကန့်}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# ရက်}other{# ရက်}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# နာရီ}other{# နာရီ}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# မိနစ်}other{# မိနစ်}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# စက္ကန့်}other{# စက္ကန့်}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"မည်သည့် ခွင့်ပြုချက်မဆို"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"အချိန်မရွေး"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"ပြီးခဲ့သော ၇ ရက်"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"ပြီးခဲ့သော ၂၄ နာရီ"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"ပြီးခဲ့သော ၁ နာရီ"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"ပြီးခဲ့သော ၁၅ မိနစ်"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"ပြီးခဲ့သည့် ၁ မိနစ်"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{ပြီးခဲ့သော # ရက်}other{ပြီးခဲ့သော # ရက်}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{ပြီးခဲ့သော # နာရီ}other{ပြီးခဲ့သော # နာရီ}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{ပြီးခဲ့သော # မိနစ်}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">"ပြီးခဲ့သော ၇ ရက်အတွင်း လတ်တလော ဝင်သုံးမှု"</string>
@@ -158,8 +161,8 @@
<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_preference_summary_not_used_24h" msgid="3087783232178611025">"ပြီးခဲ့သည့် ၂၄ နာရီအတွင်း အသုံးမပြုပါ"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"ပြီးခဲ့သည့် ၇ ရက်အတွင်း အသုံးမပြုပါ"</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{အက်ပ် ၁ ခုက အသုံးပြုထားသည်}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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"အားလုံးကို အမြဲခွင့်ပြုရန်"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"အမြဲမေးရန်"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"ခွင့်မပြုပါ"</string>
<string name="precise_image_description" msgid="6349638632303619872">"နေရာအတိအကျ"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> နှင့် <xliff:g id="PERM_1">%2$s</xliff:g> ခွင့်ပြုချက်များကို ဖယ်ရှားလိုက်ပါမည်။"</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"ဖယ်ရှားလိုက်မည့် ခွင့်ပြုချက်များ− <xliff:g id="PERMS">%1$s</xliff:g>။"</string>
<string name="auto_manage_title" msgid="7693181026874842935">"ခွင့်ပြုချက်များ အလိုအလျောက် စီမံခြင်း"</string>
- <string name="off" msgid="1438489226422866263">"ပိတ်"</string>
<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_tv_summary" msgid="3685907153054355671">"အက်ပ်ကို လအနည်းငယ်ကြာ အသုံးမပြုပါက-\n\n• သင့်ဒေတာကိုကာကွယ်ရန် အက်ပ်ခွင့်ပြုချက်များ ဖယ်ရှားသည်\n• နေရာလွတ်ပြုလုပ်ရန် ၎င်း၏ယာယီဖိုင်များ ဖယ်ရှားသည်\n\nခွင့်ပြုချက်များပြန်ပေးရန် အက်ပ်ကို ဖွင့်နိုင်သည်။"</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"ပြီးခဲ့သော <xliff:g id="NUMBER">%s</xliff:g> လ ကျော်က နောက်ဆုံးဖွင့်ထားသည်"</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>
@@ -251,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 နာရီ}other{# နာရီ}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{၁ မိနစ်}other{# မိနစ်}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{၁ စက္ကန့်}other{# စက္ကန့်}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# နာရီ}other{# နာရီ}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<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_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_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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android စနစ်"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"ပုဂ္ဂိုလ်ရေးလုံခြုံစေရန် အက်ပ်ခွင့်ပြုချက်များ ဖယ်လိုက်သည်"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> ကို အသုံးမပြုသည်မှာ လအနည်းငယ် ရှိပါပြီ။ ပြန်ကြည့်ရန် တို့ပါ။"</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> နှင့် အခြားအက်ပ် ၁ ခုကို အသုံးမပြုသည်မှာ လအနည်းငယ် ရှိပါပြီ။ ပြန်ကြည့်ရန် တို့ပါ။"</string>
@@ -378,6 +397,10 @@
<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_short_label" msgid="8796604147546125285">"မှတ်စုရေးသောအက်ပ်"</string>
+ <string name="role_notes_description" msgid="8496852798616883551">"စက်ပစ္စည်းတွင် မှတ်စုရေးခွင့်ပြုသော အက်ပ်များ"</string>
+ <string name="role_notes_search_keywords" msgid="7710756695666744631">"မှတ်စုများ"</string>
<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>
@@ -452,6 +475,7 @@
<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_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_microphone" msgid="2825208549114811299">"&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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"ထိန်းချုပ်ထားသော ခွင့်ပြုချက်များ"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"တည်နေရာကို ဝင်ကြည့်နိုင်သည်"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"သင့် IT စီမံခန့်ခွဲသူက <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"လုံခြုံရေးနှင့် ကိုယ်ရေးဒေတာ"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"စကင်ဖတ်ရန်"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"အာရုံခံကိရိယာ ခွင့်ပြုချက်များ"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"ကန့်သတ်ရန် ဆက်တင်များ"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"ခွင့်ပြုချက် ဖယ်ရှားလိုက်သည်"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"ကင်မရာအသုံးပြုမှု ပိုမိုကြည့်ရန်"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"မိုက်ခရိုဖုန်းအသုံးပြုမှု ပိုမိုကြည့်ရန်"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"ကင်မရာခွင့်ပြုချက် ဖယ်ရှားရန်"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"မိုက်ခရိုဖုန်းခွင့်ပြုချက် ဖယ်ရှားရန်"</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="manage_service_qs" msgid="7862555549364153805">"ဝန်ဆောင်မှု စီမံခန့်ခွဲရန်"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"ခွင့်ပြုချက်များကို စီမံရန်"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"ဖုန်းခေါ်ဆိုမှုက အသုံးပြုနေသည်"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"လုံခြုံရေးနှင့် ကိုယ်ရေးဒေတာ"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"အခြေအနေ စစ်ဆေးပါ"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"ဆော့ဖ်ဝဲရေးသူဆိုင်ရာ ဆက်သွယ်မှုများ"</string>
+ <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="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="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="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>
</resources>
diff --git a/PermissionController/res/values-nb-v33/strings.xml b/PermissionController/res/values-nb-v33/strings.xml
index 7f336d0b4..570e99d27 100644
--- a/PermissionController/res/values-nb-v33/strings.xml
+++ b/PermissionController/res/values-nb-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Denne appen får tillatelse til å sende deg varsler og får tilgang til kamera, kontakter, mikrofon, telefon og SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Denne appen får tillatelse til å sende deg varsler og kan bruke kamera, kontakter, filer, mikrofon, telefon og SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Apper med denne tillatelsen kan bruke alle filer på denne enheten"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Informasjon om jobbretningslinjene dine"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Innstillingene administreres av IT-administratoren din"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Dobbelttrykk for å vise listen"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Skjule listen og innstillingene"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Liste. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Liste. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Handlinger kreves. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Listeelement. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Lukk"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Vis alternativer"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Skjul"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Bryter. <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">"Slå av/på"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Åpne"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Gå gjennom innstillingene"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Innstillinger"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Informasjon"</string>
</resources>
diff --git a/PermissionController/res/values-nb-v34/strings.xml b/PermissionController/res/values-nb-v34/strings.xml
new file mode 100644
index 000000000..a7bb456d5
--- /dev/null
+++ b/PermissionController/res/values-nb-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Sikkerhet og personvern"</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">"Administrer apptilgang til helsedata"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Posisjonstilgang"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"For apper og tjenester. Hvis denne innstillingen er av, kan mikrofondata fremdeles deles når du ringer et nødnummer"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"For apper og tjenester"</string>
+</resources>
diff --git a/PermissionController/res/values-nb/strings.xml b/PermissionController/res/values-nb/strings.xml
index 80c74d657..1e5f58453 100644
--- a/PermissionController/res/values-nb/strings.xml
+++ b/PermissionController/res/values-nb/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Tilbake"</string>
<string name="available" msgid="6007778121920339498">"Tilgjengelig"</string>
<string name="blocked" msgid="9195547604866033708">"Blokkert"</string>
+ <string name="on" msgid="280241003226755921">"På"</string>
+ <string name="off" msgid="1438489226422866263">"Av"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Avinstaller eller slå av"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Appen ble ikke funnet"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Ikke tillat"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Behold «Mens appen er i bruk»"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Behold «Bare denne gangen»"</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Ikke tillat likevel"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Avvis"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> av <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Skjermoverlegg oppdaget"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"For å endre denne tillatelsesinnstillingen må du først slå av skjermoverlegget fra Innstillinger &gt; Apper"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Åpne Innstillinger"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Tidslinje over når apper har brukt <xliff:g id="PERMGROUP">%1$s</xliff:g> de siste 7 dagene"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Når denne appen har brukt <xliff:g id="PERMGROUP">%1$s</xliff:g>-tillatelsen"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Finn ut mer"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Finn ut mer om <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Kontroller apptilgangen til <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 dag}other{# dager}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 time}other{# timer}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 sek}other{# sek}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# dag}other{# dager}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# time}other{# timer}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# sek}other{# sek}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Hvilken som helst tillatelse"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Når som helst"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"De siste 7 dagene"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"De siste 24 timene"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Den siste timen"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"De siste 15 minuttene"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Det siste minuttet"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Den siste dagen}other{De siste # dagene}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Den siste timen}other{De siste # timene}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Det siste minuttet}other{De siste # minuttene}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Ingen bruk av tillatelsen"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Siste tilgang når som helst"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Siste tilgang i løpet av de siste syv dagene"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Bruk av tillatelser den siste timen"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Bruk av tillatelser de siste 15 minuttene"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Bruk av tillatelser det siste minuttet"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Ikke brukt de siste 24 timene"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Ikke brukt i løpet av de siste 7 dagene"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Ikke brukt i løpet av den siste dagen}other{Ikke brukt i løpet av de siste # dagene}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Ikke brukt den siste timen}other{Ikke brukt de siste # timene}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Brukt av 1 app}other{Brukt av # apper}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Se alt i oversikten"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrert etter: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Har bare tilgang til medier"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Tillat hele tiden"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Bare tillat når appen brukes"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Tillat alltid alle"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Spør hver gang"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Ikke tillat"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Nøyaktig posisjon"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Tillatelsene <xliff:g id="PERM_0">%1$s</xliff:g> og <xliff:g id="PERM_1">%2$s</xliff:g> blir fjernet."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Disse tillatelsene blir fjernet: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Administrer tillatelser automatisk"</string>
- <string name="off" msgid="1438489226422866263">"Av"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Tillatelsen <xliff:g id="PERMISSION_NAME">%s</xliff:g> er fjernet"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Tillatelsene <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> og <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> er fjernet"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> og <xliff:g id="NUMBER">%2$s</xliff:g> andre tillatelser er fjernet"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Ubrukte apper"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Dette skjer hvis en app ikke brukes på noen måneder:\n\n• Tillatelser fjernes for å beskytte dataene dine.\n• Varsler stoppes for å spare batteri.\n• Midlertidige filer fjernes for å frigjøre plass.\n\nFor å gi tillatelser og tillate varsler igjen, åpne appen."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Dette skjer hvis en app ikke brukes på noen måneder:\n\n• Tillatelser fjernes for å beskytte dataene dine.\n• Midlertidige filer fjernes for å frigjøre plass.\n\nÅpne appen for å gi tillatelser igjen."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Sist åpnet for mer enn <xliff:g id="NUMBER">%s</xliff:g> måneder siden"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Dette skjer hvis en app ikke brukes i løpet av en måned:\n\n• Tillatelser fjernes for å beskytte dataene dine.\n• Midlertidige filer fjernes for å frigjøre plass.\n\nDu kan åpne appen for å gi tillatelser igjen."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Sist åpnet for over # måned siden}other{Sist åpnet for over # måneder siden}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Appen ble sist åpnet <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Sist åpnet <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Hvis du tillater administrering av alle filer, kan denne appen åpne, endre og slette alle filer i felles lagringsplass på denne enheten eller tilkoblede lagringsenheter. Appen kan åpne filer uten å spørre deg."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Ikke tillatt"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Se flere apper som kan bruke alle filer"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 dag}other{# dager}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 time}other{# timer}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minutt}other{# minutter}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 sekund}other{# sekunder}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# time}other{# timer}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minutt}other{# minutter}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# sekund}other{# sekunder}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Påminnelser om tillatelser"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"Én ubrukt app"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> ubrukte apper"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Enkelte apper er ikke brukt på noen måneder. Trykk for å gjennomgå."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# ubrukt app}other{# ubrukte apper}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Tillatelser og midlertidige filer er fjernet, og varsler er stoppet. Trykk for å gjennomgå."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Gjennomgå apper som har mistet tillatelser"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Tillatelser og midlertidige filer ble fjernet og varsler ble stoppet for noen apper du ikke har brukt på en stund."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Gjennomgå apper"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Sjekk nylige tillatelser"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Du ga <xliff:g id="APP">%1$s</xliff:g> tilgang til <xliff:g id="PERMISSION">%2$s</xliff:g> mens du kjørte"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Du ga <xliff:g id="APP">%1$s</xliff:g> tilgang til <xliff:g id="PERMISSION_1">%2$s</xliff:g> og <xliff:g id="PERMISSION_2">%3$s</xliff:g> mens du kjørte"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Tillatelser er fjernet for å ivareta personvernet ditt"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> fikk posisjonen din i bakgrunnen"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Denne appen har alltid tilgang til posisjonen din. Trykk for å endre."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Gjennomgangsapp med tilgang til varslene dine"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> kan avvise, utføre handlinger basert på og bruke innhold i varslene dine"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Denne appen kan avvise, utføre handlinger basert på og bruke innhold i varslene dine. Noen apper krever denne tilgangen for å fungere som de skal."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Fjern tilgang"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Se flere alternativer"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Tilgangen er fjernet"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Gjennomgå apper med full enhetstilgang"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> kan se skjermen og utføre handlinger på enheten. Tilgjengelighetsapper trenger denne typen tilgang for å fungere som de skal."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Denne appen kan se skjermen og utføre handlinger på enheten. Tilgjengelighetsapper trenger denne typen tilgang for å fungere som de skal, men du bør sjekke appen og sørge for at du stoler på den."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Fjern tilgang"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Se apper med full tilgang"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Tilgangen er fjernet"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android-system"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Apptillatelser er fjernet for å ivareta personvern"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> har ikke blitt brukt på noen måneder. Trykk for å gjennomgå."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> og én annen app har ikke blitt brukt på noen måneder. Trykk for å gjennomgå."</string>
@@ -378,6 +397,10 @@
<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 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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Kontrollerte tillatelser"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Posisjonen er tilgjengelig"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"IT-administratoren din tillater at <xliff:g id="APP_NAME">%s</xliff:g> får tilgang til posisjonen din"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"For apper og tjenester"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Mikrofondata kan fremdeles deles når du ringer et nødnummer."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Endre"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Sikkerhet og personvern"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Skann"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Sikkerhet og personvern"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Skann enheten"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Lukk"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Vil du lukke dette varselet?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Du kan når som helst gå gjennom sikkerhets- og personverninnstillingene dine for å legge til mer beskyttelse"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Lukk"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Avbryt"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Innstillinger"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Status for sikkerhet og personvern. <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">"Sikkerhetsinnstillinger"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Sensortillatelser"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Personverninnstillinger"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Tillatelser"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Sikkerhet og personvern"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Sjekk statusen"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Personverninnstillingene dine"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Flere innstillinger"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Kameratilgang"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Mikrofontilgang"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Tillatelsen er fjernet"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Se mer kamerabruk"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Se mer mikrofonbruk"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Fjern kameratillatelse"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Fjern mikrofontillatelse"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Se nylig bruk av kameraet"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Se nylig bruk av mikrofonen"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Fjern tillatelsen for denne appen"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Fjern tillatelsen for denne appen"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Administrer tjeneste"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Administrer tillatelser"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Blir brukt av telefonanrop"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Nylig brukt av <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">"Blir brukt av <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">"Nylig brukt av <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Sikkerhet og personvern"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Sjekk statusen"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Bekreft"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Tilbake"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Tilgang til andre filer tillates også"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Denne appen støtter ikke den nyeste versjonen av Android. Hvis denne appen ikke har tilgang til musikk- og lydfiler, har den heller ikke tilgang til bilder og videoer."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Denne appen støtter ikke den nyeste versjonen av Android. Hvis denne appen har tilgang til bilder og videoer, har den også tilgang til musikk- og lydfiler."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Denne appen støtter ikke den nyeste versjonen av Android. Hvis denne appen ikke har tilgang til musikk- og lydfiler, har den heller ikke tilgang til bilder og videoer."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Gjennomgå apper med tilgang til bakgrunnsposisjon"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> har alltid tilgang til posisjonen, selv når appen er lukket"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Gjennomgå apper med tilgang til bakgrunnsposisjon"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Denne appen kan alltid se hvor du er – selv når den er lukket.\n\nNoen apper for sikkerhet og nødssituasjoner trenger tilgang til posisjonen din i bakgrunnen for å fungere som de skal."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Tilgangen er endret"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Se nylig bruk av posisjon"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Personverninnstillinger"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Kameratilgang"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Mikrofontilgang"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"For apper og tjenester"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"For apper og tjenester. Hvis denne innstillingen er av, kan mikrofondata fremdeles deles når du ringer et nødnummer."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Se apper og tjenester som har tilgang til posisjon"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Vis tilgang til utklippstavlen"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Vis en melding når apper bruker tekst, bilder eller annet innhold du har kopiert"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Vis passord"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Vis tegnene et øyeblikk mens du skriver"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Databehandling kan variere basert på appversjon, bruk, region og alder. "<annotation id="link">"Mer informasjon om datadeling"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Databehandling kan variere basert på appversjon, bruk, region og alder."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Posisjonsdataene dine"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Du kan endre tilgangen denne appen har, i "<annotation id="link">"personverninnstillingene"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"appfunksjonalitet"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"statistikk"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"utviklerkommunikasjon"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"annonsering eller markedsføring"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"forebygging av svindel, sikkerhet og overholdelse av regler"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"personlig tilpasning"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"kontoadministrasjon"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Utviklerne av disse appene har gitt en appbutikk informasjon om praksisen sin for datadeling. De kan oppdatere den over tid.\n\nPraksisen for datadeling kan variere basert på appversjon, bruk, region og alder."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Finn ut mer om datadeling"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Nå deles posisjonsdataene dine med tredjeparter"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Nå deles posisjonsdataene dine med tredjeparter for annonserings- eller markedsføringsformål"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Oppdatert i løpet av den siste dagen}=1{Oppdatert i løpet av den siste dagen}other{Oppdatert i løpet av de siste # dagene}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Ingen oppdateringer for øyeblikket"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-ne-v33/strings.xml b/PermissionController/res/values-ne-v33/strings.xml
index fc3fecfbb..b16622bd0 100644
--- a/PermissionController/res/values-ne-v33/strings.xml
+++ b/PermissionController/res/values-ne-v33/strings.xml
@@ -19,4 +19,28 @@
<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="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>
+ <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>
+ <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{एक्स्पान्ड गरेर थप एउटा अलर्ट हेर्नुहोस्}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"बन्द गर्नुहोस्"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"एक्स्पान्ड गर्नुहोस् र विकल्पहरू देखाउनुहोस्"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"कोल्याप्स गर्नुहोस्"</string>
+ <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_gear_label" msgid="5175877094379694098">"सेटिङ"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"जानकारी"</string>
</resources>
diff --git a/PermissionController/res/values-ne-v34/strings.xml b/PermissionController/res/values-ne-v34/strings.xml
new file mode 100644
index 000000000..421c5a8e0
--- /dev/null
+++ b/PermissionController/res/values-ne-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-ne/strings.xml b/PermissionController/res/values-ne/strings.xml
index 5b6d5e9c8..c418348bd 100644
--- a/PermissionController/res/values-ne/strings.xml
+++ b/PermissionController/res/values-ne/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"सधैँ सबै अनुमति दिइयोस्"</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>
@@ -64,7 +71,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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"स्क्रिन ओभरले पत्ता लाग्यो"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"यो अनुमतिसम्बन्धी सेटिङ बदल्न तपाईंले पहिला सेटिङ &gt; एपमा गई स्क्रिन ओभरले निष्क्रिय पार्नु पर्छ।"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"सेटिङहरू खोल्नुहोस्"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"एपहरूले पछिल्ला ७ दिनमा कुन कुन समयमा तपाईंको <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{१ दिन}other{# दिन}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{१ घण्टा}other{# घण्टा}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{१ मिनेट}other{# मिनेट}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{१ सेकेन्ड}other{# सेकेन्ड}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# दिन}other{# दिन}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# घण्टा}other{# घण्टा}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# मिनेट}other{# मिनेट}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# सेकेन्ड}other{# सेकेन्ड}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"कुनै पनि अनुमति"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"कुनै पनि समय"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"पछिल्ला ७ दिन"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"पछिल्लो २४ घन्टा"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"पछिल्लो १ घन्टा"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"पछिल्लो १५ मिनेट"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"पछिल्लो १ मिनेट"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{पछिल्लो # दिन}other{पछिल्ला # दिन}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{पछिल्लो # घण्टा}other{पछिल्ला # घण्टा}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{पछिल्लो # मिनेट}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">"गत ७ दिनमा पछिल्लो पटक गरिएको पहुँच"</string>
@@ -158,8 +161,8 @@
<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_preference_summary_not_used_24h" msgid="3087783232178611025">"पछिल्लो २४ घण्टामा प्रयोग गरिएको छैन"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"पछिल्ला ७ दिनमा प्रयोग गरिएको छैन"</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{एउटा एप‌ले प्रयोग गरेको}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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"सधैँ सबै अनुमति दिइयोस्"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"प्रत्येक पटक सोधियोस्"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"अनुमति नदिइयोस्"</string>
<string name="precise_image_description" msgid="6349638632303619872">"सटीक स्थान"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> र <xliff:g id="PERM_1">%2$s</xliff:g> सम्बन्धी अनुमतिहरू हटाइने छन्।"</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"निम्न अनुमतिहरू हटाइने छन्: <xliff:g id="PERMS">%1$s</xliff:g>।"</string>
<string name="auto_manage_title" msgid="7693181026874842935">"अनुमतिहरू स्वतः व्यवस्थापन गरियोस्"</string>
- <string name="off" msgid="1438489226422866263">"निष्क्रिय"</string>
<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_tv_summary" msgid="3685907153054355671">"कुनै एप केही महिनादेखि चलाइएको छैन भने:\n\n• तपाईंको डेटा सुरक्षित राख्न उक्त एपलाई दिइएका अनुमति रद्द गरिन्छन्\n• ठाउँ खाली गर्न अस्थायी फाइलहरू हटाइन्छन्\n\nउक्त एपलाई फेरि ती अनुमति दिन र सो एपबाट सूचनाहरू प्राप्त गर्न सो एप खोल्नुहोस्।"</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"पछिल्लो पटक <xliff:g id="NUMBER">%s</xliff:g> महिनाभन्दा पहिले प्रयोग गरिएको"</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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"अनुमति नदिइएका"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"सबै फाइल हेर्ने र प्रयोग गर्ने अनुमति भएका थप एपहरू हेर्नुहोस्"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{१ दिन}other{# दिन}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{१ घण्टा}other{# घण्टा}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{१ मिनेट}other{# मिनेट}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{१ सेकेन्ड}other{# सेकेन्ड}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# घण्टा}other{# घण्टा}}"</string>
+ <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">"प्रयोग नगरिएको १ एप"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"प्रयोग नगरिएका <xliff:g id="NUMBER_OF_APPS">%s</xliff:g> एपहरू"</string>
@@ -262,6 +265,9 @@
<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_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_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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android सिस्टम"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"गोपनीयताको संरक्षण गर्न एपलाई दिइएका अनुमति रद्द गरिए"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"केही महिनादेखि <xliff:g id="APP_NAME">%s</xliff:g> प्रयोग भएको छैन। समीक्षा गर्न ट्याप गर्नुहोस्।"</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"केही महिनादेखि <xliff:g id="APP_NAME">%s</xliff:g> र अर्को १ एप प्रयोग भएका छैनन्। समीक्षा गर्न ट्याप गर्नुहोस्।"</string>
@@ -347,7 +366,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>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"नोटहरू"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"नियन्त्रित अनुमतिहरू"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"स्थानसम्बन्धी जानकारी हेरिन सक्छ"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"तपाईंका IT एडमिनले <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"सुरक्षा तथा गोपनीयता"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"स्क्यान गर्नुहोस्"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"सेन्सर प्रयोग गर्ने अनुमतिहरू"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"गोपनीयता नियन्त्रणहरू"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"अनुमति हटाइएको छ"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"क्यामेरा प्रयोग गर्ने थप एपहरू हेर्नुहोस्"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"माइक्रोफोन प्रयोग गर्ने थप एप हेर्नुहोस्"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"क्यामेरा प्रयोग गर्न दिइएको अनुमति हटाउनुहोस्"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"माइक्रोफोन प्रयोग गर्न दिइएको अनुमति हटाउनुहोस्"</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="manage_service_qs" msgid="7862555549364153805">"सेवा व्यवस्थित गर्नुहोस्"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"अनुमति व्यवस्थापन गर्नुहोस्"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"फोन कलले प्रयोग गरिरहेको छ"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"सुरक्षा तथा गोपनीयता"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"स्थिति जाँच गर्नुहोस्"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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">"Analytics"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"विकासकर्ताबाट जानकारी प्राप्त गर्ने"</string>
+ <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="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="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="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>
</resources>
diff --git a/PermissionController/res/values-night-v31/colors.xml b/PermissionController/res/values-night-v31/colors.xml
index a1858cdf2..2dcc99a58 100644
--- a/PermissionController/res/values-night-v31/colors.xml
+++ b/PermissionController/res/values-night-v31/colors.xml
@@ -14,13 +14,10 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<resources>
+<resources xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<color name="warning_surface">#333124</color>
<color name="warning_onsurface">#FDD663</color>
- <!-- Safety center colors -->
- <color name="safety_center_info">#5BB974</color>
- <color name="safety_center_recommend">#FCC934</color>
- <color name="safety_center_warn">#EE675C</color>
- <color name="safety_center_status_unfilled_wedge">#3C4043</color> <!-- Material Gray 800 @ 75% opacity -->
+ <!-- overviewBackground is not visible from mainline, so UX provided this alternative -->
+ <color name="permission_rationale_overview_background">@android:color/system_neutral1_600</color>
</resources> \ No newline at end of file
diff --git a/PermissionController/res/values-night-v33/themes.xml b/PermissionController/res/values-night-v33/themes.xml
new file mode 100644
index 000000000..6374ee088
--- /dev/null
+++ b/PermissionController/res/values-night-v33/themes.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.
+ -->
+
+<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>
+ <item name="colorAccentPrimary">@color/sc_accent_primary_dark</item>
+
+ <item name="colorScStatusInfo">@color/sc_status_info_dark</item>
+ <item name="colorScStatusRecommend">@color/sc_status_recommend_dark</item>
+ <item name="colorScStatusWarn">@color/sc_status_warn_dark</item>
+
+ <item name="colorScStatusBackgroundInfo">@color/sc_status_background_info_dark</item>
+ <item name="colorScStatusBackgroundRecommend">
+ @color/sc_status_background_recommend_dark
+ </item>
+ <item name="colorScStatusBackgroundWarn">@color/sc_status_background_warn_dark</item>
+
+ <item name="colorScIconInfo">@color/sc_icon_info_dark</item>
+ <item name="colorScIconRecommend">@color/sc_icon_recommend_dark</item>
+ <item name="colorScIconWarn">@color/sc_icon_warn_dark</item>
+ <item name="colorScIconNull">@color/sc_icon_null_dark</item>
+
+ <item name="colorScShieldAccent">@color/sc_shield_accent</item>
+
+
+ <item name="scStatusTitleAndSummaryContainerStyle">
+ @style/SafetyCenterStatusTitleAndSummaryContainer.Responsive
+ </item>
+ <item name="scStatusButtonStyle">@style/SafetyCenterStatusButton.Responsive</item>
+
+ <!-- Buttons -->
+ <item name="scActionButtonStyle">@style/SafetyCenterActionButton</item>
+ <item name="scSecondaryActionButtonStyle">@style/SafetyCenterActionButton.Secondary</item>
+
+ <item name="textColorScActionButton">@color/sc_primary_action_button_text</item>
+ <item name="textColorScSecondaryActionButton">?android:attr/textColorPrimary</item>
+
+ <item name="colorScOutlineButtonInfoBase">@color/sc_outline_button_info_base_dark</item>
+ <item name="colorScOutlineButtonRecommendBase">
+ @color/sc_outline_button_recommend_base_dark
+ </item>
+ <item name="colorScOutlineButtonWarnBase">@color/sc_outline_button_warn_base_dark</item>
+ </style>
+</resources> \ No newline at end of file
diff --git a/PermissionController/res/values-night-v34/colors.xml b/PermissionController/res/values-night-v34/colors.xml
new file mode 100644
index 000000000..cd076794b
--- /dev/null
+++ b/PermissionController/res/values-night-v34/colors.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>
+ <!-- colorAccentPrimaryVariant is not visible from mainline, so UX provided this alternative -->
+ <color name="permission_rationale_accent_primary_variant">@android:color/system_accent1_300</color>
+</resources>
diff --git a/PermissionController/res/values-night-v34/themes.xml b/PermissionController/res/values-night-v34/themes.xml
new file mode 100644
index 000000000..affc57027
--- /dev/null
+++ b/PermissionController/res/values-night-v34/themes.xml
@@ -0,0 +1,32 @@
+<?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>
+ <style name="Theme.PermissionRationaleDialog"
+ parent="@android:style/Theme.DeviceDefault.Dialog">
+ <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>
+</resources> \ No newline at end of file
diff --git a/PermissionController/res/values-night/colors.xml b/PermissionController/res/values-night/colors.xml
new file mode 100644
index 000000000..82d96ba05
--- /dev/null
+++ b/PermissionController/res/values-night/colors.xml
@@ -0,0 +1,22 @@
+<?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>
+ <!-- overviewBackground is not visible from mainline, so UX provided this alternative.
+ system_neutral1_600 is v31+ so use this placeholder provided by ux -->
+ <color name="permission_rationale_overview_background">#5F6368</color>
+</resources>
diff --git a/PermissionController/res/values-night/themes.xml b/PermissionController/res/values-night/themes.xml
index b4257ab4e..7ac9b190b 100644
--- a/PermissionController/res/values-night/themes.xml
+++ b/PermissionController/res/values-night/themes.xml
@@ -40,5 +40,5 @@
<item name="android:background">@color/divider_color_secondary</item>
</style>
- <style name="Theme.DeviceDefault.Dialog.Alert.DayNight" parent="@android:style/Theme.DeviceDefault.Dialog.Alert" />
+ <style name="Theme.DeviceDefault.Dialog.NoActionBar.DayNight" parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar" />
</resources>
diff --git a/PermissionController/res/values-nl-v33/strings.xml b/PermissionController/res/values-nl-v33/strings.xml
index 183d2b542..5b89f1135 100644
--- a/PermissionController/res/values-nl-v33/strings.xml
+++ b/PermissionController/res/values-nl-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Deze app mag jou meldingen sturen en krijgt toegang tot Camera, Contacten, Microfoon, Telefoon en Sms"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Deze app mag jou meldingen sturen en krijgt toegang tot Camera, Contacten, Bestanden, Microfoon, Telefoon en Sms"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Apps met dit recht hebben toegang tot alle bestanden op dit apparaat"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Informatie over je werkbeleid"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Instellingen beheerd door je IT-beheerder"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Uitvouwen en lijst tonen"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Lijst samenvouwen en instellingen verbergen"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Lijst. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Lijst. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Acties vereist. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>."</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Lijstitem. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Sluiten"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Uitvouwen en opties laten zien"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Samenvouwen"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Schakelaar. <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">"Schakelen"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Openen"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Instellingen checken"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Instellingen"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Informatie"</string>
</resources>
diff --git a/PermissionController/res/values-nl-v34/strings.xml b/PermissionController/res/values-nl-v34/strings.xml
new file mode 100644
index 000000000..b3265d254
--- /dev/null
+++ b/PermissionController/res/values-nl-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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">"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>
+</resources>
diff --git a/PermissionController/res/values-nl/strings.xml b/PermissionController/res/values-nl/strings.xml
index 91f1d50d1..f845b1de4 100644
--- a/PermissionController/res/values-nl/strings.xml
+++ b/PermissionController/res/values-nl/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Terug"</string>
<string name="available" msgid="6007778121920339498">"Beschikbaar"</string>
<string name="blocked" msgid="9195547604866033708">"Geblokkeerd"</string>
+ <string name="on" msgid="280241003226755921">"Aan"</string>
+ <string name="off" msgid="1438489226422866263">"Uit"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Verwijderen of uitzetten"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"App niet gevonden"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Niet toestaan"</string>
@@ -30,11 +32,16 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Instelling \'Terwijl de app wordt gebruikt\' behouden"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"\'Alleen deze keer\' behouden"</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Toch niet toestaan"</string>
<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>
@@ -107,9 +114,6 @@
<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="screen_overlay_title" msgid="6977038513913222078">"Schermoverlay gedetecteerd"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Als je deze instelling voor rechten wilt wijzigen, moet je eerst de schermoverlay uitzetten via Instellingen &gt; Apps"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Instellingen openen"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Tijdlijn van wanneer apps in de afgelopen 7 dagen je <xliff:g id="PERMGROUP">%1$s</xliff:g> hebben gebruikt"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Wanneer deze app het recht voor <xliff:g id="PERMGROUP">%1$s</xliff:g> heeft gebruikt"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Meer informatie"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Meer informatie over <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"App-toegang tot je <xliff:g id="PERMGROUP">%1$s</xliff:g> beheren"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 dag}other{# dagen}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 uur}other{# uur}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 sec}other{# sec}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# dag}other{# dagen}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# uur}other{# uur}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Minstens 1 recht"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Altijd"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Afgelopen 7 dagen"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Afgelopen 24 uur"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Afgelopen uur"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Afgelopen 15 minuten"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Afgelopen minuut"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Afgelopen dag}other{Afgelopen # dagen}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Afgelopen uur}other{Afgelopen # uur}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Afgelopen minuut}other{Afgelopen # minuten}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Geen rechtengebruik"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Laatste toegang"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Laatste toegang in de afgelopen zeven dagen"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Rechtengebruik in het afgelopen uur"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Rechtengebruik in de afgelopen 15 minuten"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Rechtengebruik in de afgelopen minuut"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Niet gebruikt in de afgelopen 24 uur"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Niet gebruikt in de afgelopen 7 dagen"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Niet gebruikt in de afgelopen dag}other{Niet gebruikt in de afgelopen # dagen}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Niet gebruikt in het afgelopen uur}other{Niet gebruikt in de afgelopen # uur}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Gebruikt door 1 app}other{Gebruikt door # apps}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Alles op dashboard tonen"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Gefilterd op: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Alleen toegang tot media toestaan"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Altijd toestaan"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Toestaan bij gebruik van app"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Altijd alles toestaan"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Altijd vragen"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Niet toestaan"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Exacte locatie"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Rechten voor <xliff:g id="PERM_0">%1$s</xliff:g> en <xliff:g id="PERM_1">%2$s</xliff:g> worden verwijderd."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Rechten die worden verwijderd: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Rechten automatisch beheren"</string>
- <string name="off" msgid="1438489226422866263">"Uit"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Recht voor <xliff:g id="PERMISSION_NAME">%s</xliff:g> verwijderd"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Rechten voor <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> en <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> verwijderd"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> en <xliff:g id="NUMBER">%2$s</xliff:g> andere rechten zijn verwijderd"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Niet-gebruikte apps"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Als je een app een paar maanden niet gebruikt, gebeurt het volgende:\n\n• De rechten worden ingetrokken om je gegevens te beschermen.\n• Meldingen worden stopgezet om de batterij te sparen.\n• Tijdelijke bestanden worden verwijderd om ruimte vrij te maken.\n\nOpen de app als je de rechten en meldingen weer wilt toestaan."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Als je een app een paar maanden niet gebruikt, gebeurt het volgende:\n\n• De rechten worden verwijderd om je gegevens te beschermen.\n• Tijdelijke bestanden worden verwijderd om ruimte vrij te maken.\n\nOpen de app als je de rechten weer wilt toestaan."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Meer dan <xliff:g id="NUMBER">%s</xliff:g> maanden geleden voor het laatst geopend"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Als je een app een maand niet gebruikt, gebeurt het volgende:\n\n• De rechten worden verwijderd om je gegevens te beschermen.\n• Tijdelijke bestanden worden verwijderd om ruimte vrij te maken.\n\nOpen de app als je de rechten weer wilt toestaan."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Meer dan # maand geleden voor het laatst geopend}other{Meer dan # maanden geleden voor het laatst geopend}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"App laatst geopend op <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Laatst geopend op <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Als je het beheer van alle bestanden toestaat, kan deze app alle bestanden in de algemene opslag van dit apparaat of gekoppelde opslagapparaten openen, bewerken en verwijderen. De app kan toegang tot bestanden krijgen zonder je dat te vragen."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Niet toegestaan"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Bekijk meer apps die toegang tot alle bestanden hebben."</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 dag}other{# dagen}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 uur}other{# uur}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minuut}other{# minuten}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 seconde}other{# seconden}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# uur}other{# uur}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minuut}other{# minuten}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# seconde}other{# seconden}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Herinneringen voor rechten"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 niet-gebruikte app"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> niet-gebruikte apps"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Bepaalde apps zijn al een paar maanden niet gebruikt. Tik om te bekijken."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# niet-gebruikte app}other{# niet-gebruikte apps}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Rechten en tijdelijke bestanden zijn verwijderd en meldingen zijn stopgezet. Tik om te bekijken."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Apps met verwijderde rechten bekijken"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Voor apps die je al een tijdje niet hebt gebruikt, zijn de rechten en tijdelijke bestanden verwijderd en zijn de meldingen gestopt."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Apps bekijken"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Recente rechten checken"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Tijdens het rijden heb je <xliff:g id="APP">%1$s</xliff:g> toegang gegeven tot <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Tijdens het rijden heb je <xliff:g id="APP">%1$s</xliff:g> toegang gegeven tot <xliff:g id="PERMISSION_1">%2$s</xliff:g> en <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"De rechten zijn verwijderd om je privacy te beschermen"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> had toegang tot je locatie op de achtergrond"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Deze app heeft altijd toegang tot je locatie. Tik om dit te wijzigen."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Apps met toegang tot je meldingen bekijken"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> kan je meldingen sluiten, erop reageren en toegang krijgen tot de inhoud van je meldingen"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Deze app kan je meldingen sluiten, erop reageren en toegang krijgen tot de inhoud van je meldingen. Sommige apps hebben deze toegang nodig om te werken zoals bedoeld."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Toegang intrekken"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Meer opties bekijken"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Toegang ingetrokken"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Apps met volledige apparaattoegang bekijken"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> kan je scherm bekijken en acties uitvoeren op je apparaat. Toegankelijkheidsapps hebben dit type toegang nodig om te werken zoals bedoeld."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Deze app kan je scherm bekijken en acties uitvoeren op je apparaat. Toegankelijkheidsapps hebben dit type toegang nodig om te werken zoals bedoeld, maar check wel of je de app vertrouwt."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Toegang intrekken"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Apps met volledige toegang bekijken"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Toegang ingetrokken"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android-systeem"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"App-rechten verwijderd om privacy te beschermen"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> is al een paar maanden niet gebruikt. Tik om dit te bekijken."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> en één andere app zijn al een paar maanden niet gebruikt. Tik om dit te bekijken."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> kan interactie hebben met je meldingen en toegang krijgen tot je rechten voor telefoon, sms, contacten en agenda."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> mag interactie hebben met je meldingen en je apps streamen naar het verbonden apparaat."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Deze service deelt foto\'s, media en meldingen van je telefoon met andere apparaten."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Standaard notitie-app"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Beheerde rechten"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Locatie is toegankelijk"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Je IT-beheerder verleent <xliff:g id="APP_NAME">%s</xliff:g> toegang tot je locatie"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Voor apps en services"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Microfoongegevens kunnen nog altijd worden gedeeld als je een alarmnummer belt."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Wijzigen"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Beveiliging en privacy"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Scannen"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Beveiliging en privacy"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Apparaat scannen"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Sluiten"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Deze melding sluiten?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Check je beveiligings- en privacyinstellingen wanneer je wilt om meer beveiliging toe te voegen"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Sluiten"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Annuleren"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Instellingen"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Beveiligings- en privacystatus. <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">"Beveiligingsinstellingen"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Sensorrechten"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Privacyopties"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Rechten"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Beveiliging en privacy"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Check status"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Je privacyopties"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Meer instellingen"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Cameratoegang"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Microfoontoegang"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Recht verwijderd"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Meer cameragebruik bekijken"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Meer microfoongebruik bekijken"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Camerarecht verwijderen"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Microfoonrecht verwijderen"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Recent cameragebruik bekijken"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Recent microfoongebruik bekijken"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Rechten verwijderen voor deze app"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Rechten verwijderen voor deze app"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Service beheren"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Rechten beheren"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Wordt gebruikt door telefoongesprek"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Recent gebruikt door <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">"Wordt gebruikt door <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">"Recent gebruikt door <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Beveiliging en privacy"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Check status"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Bevestigen"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Terug"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Toegang tot andere bestanden wordt ook toegestaan"</string>
@@ -537,4 +570,53 @@
<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">"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">"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>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Privacyopties"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Cameratoegang"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Microfoontoegang"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Voor apps en services"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"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="2328360561197430695">"Bekijk apps en services die toegang hebben tot die locatie"</string>
+ <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">"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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Gegevensprocedures kunnen variëren op basis van je app-versie, gebruik, regio en leeftijd. "<annotation id="link">"Meer informatie over gegevens delen"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Gegevensprocedures kunnen variëren op basis van je app-versie, gebruik, regio en leeftijd."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Je locatiegegevens"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Wijzig de toegang van deze app in de "<annotation id="link">"privacyinstellingen"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"App-functionaliteit"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analytics"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Berichten van de ontwikkelaar"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Advertenties of marketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Fraudepreventie, beveiliging en naleving"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalisatie"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Accountbeheer"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"De ontwikkelaars van deze apps hebben informatie gegeven aan een appstore over hun procedures voor gegevens delen. Ze kunnen deze informatie in de loop van de tijd updaten.\n\nProcedures voor gegevens delen kunnen verschillen op basis van je app-versie, gebruik, regio en leeftijd."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Meer informatie over gegevens delen"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Je locatiegegevens worden nu gedeeld met derden"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Je locatiegegevens worden nu gedeeld met derden voor advertentie- of marketingdoeleinden"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Geüpdatet in de afgelopen dag}=1{Geüpdatet in de afgelopen dag}other{Geüpdatet in de afgelopen # dagen}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Er zijn op dit moment geen updates"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-or-v33/strings.xml b/PermissionController/res/values-or-v33/strings.xml
index 8a1cff2c6..84c07b84e 100644
--- a/PermissionController/res/values-or-v33/strings.xml
+++ b/PermissionController/res/values-or-v33/strings.xml
@@ -19,4 +19,28 @@
<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="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>
+ <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>
+ <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{ବିସ୍ତାର କରି ଆଉ ଗୋଟିଏ ଆଲର୍ଟ ଦେଖନ୍ତୁ}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"ବିସ୍ତାର କରି ବିକଳ୍ପଗୁଡ଼ିକ ଦେଖାନ୍ତୁ"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
+ <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_gear_label" msgid="5175877094379694098">"ସେଟିଂସ"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"ସୂଚନା"</string>
</resources>
diff --git a/PermissionController/res/values-or-v34/strings.xml b/PermissionController/res/values-or-v34/strings.xml
new file mode 100644
index 000000000..2994a3f25
--- /dev/null
+++ b/PermissionController/res/values-or-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-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 cd86d9dfe..05fa1472a 100644
--- a/PermissionController/res/values-or/strings.xml
+++ b/PermissionController/res/values-or/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,11 +32,16 @@
<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_always_allow_all" msgid="1719900027660252167">"ସର୍ବଦା ସବୁକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"ସ୍କ୍ରୀନ୍‍ ଓଭର୍‌ଲେ ଚିହ୍ନଟ ହୋଇଛି"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"ଏହି ଅନୁମତି ସେଟିଙ୍ଗ ବଦଳାଇବାକୁ, ପ୍ରଥମେ ଆପଣଙ୍କୁ ସେଟିଂସ୍‍ରୁ ଓ ଆପ୍‌ରୁ ସ୍କ୍ରୀନ୍‍ ଓଭର୍‍ଲେ ବନ୍ଦ କରିବାକୁ ପଡିବ"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"ସେଟିଂସ୍‌ ଖୋଲନ୍ତୁ"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 ଦିନ}other{# ଦିନ}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 ଘଣ୍ଟା}other{# ଘଣ୍ଟା}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 ମିନିଟ}other{# ମିନିଟ}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 ସେକେଣ୍ଡ}other{# ସେକେଣ୍ଡ}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# ଦିନ}other{# ଦିନ}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# ଘଣ୍ଟା}other{# ଘଣ୍ଟା}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# ମିନିଟ}other{# ମିନିଟ}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# ସେକେଣ୍ଡ}other{# ସେକେଣ୍ଡ}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"ଯେକୌଣସି ଅନୁମତି"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"ଯେକୌଣସି ସମୟରେ"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"ଗତ 7 ଦିନ"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"ଗତ 24 ଘଣ୍ଟା"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"ଗତ 1 ଘଣ୍ଟା"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"ଗତ 15 ମିନିଟ୍"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"ଗତ 1 ମିନିଟ୍‌ରେ"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{ଗତ # ଦିନ}other{ଗତ # ଦିନ}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{ଗତ # ଘଣ୍ଟା}other{ଗତ # ଘଣ୍ଟା}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{ଗତ # ମିନିଟ}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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"ଗତ 24 ଘଣ୍ଟାରେ ବ୍ୟବହାର କରାଯାଇନାହିଁ"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"ଗତ 7 ଦିନରେ ବ୍ୟବହାର କରାଯାଇନାହିଁ"</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_view_details" msgid="6675335735468752787">"ଡ୍ୟାସ୍‍‍ବୋର୍ଡରେ ସବୁ ଦେଖନ୍ତୁ"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"<xliff:g id="PERM">%1$s</xliff:g> ଦ୍ବାରା ଫିଲ୍ଟର୍ କରାଯାଇଛି"</string>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"ସର୍ବଦା ସବୁକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"ପ୍ରତ୍ୟେକ ଥର ପଚାରନ୍ତୁ"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ"</string>
<string name="precise_image_description" msgid="6349638632303619872">"ସଠିକ୍ ଲୋକେସନ୍"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> ଏବଂ <xliff:g id="PERM_1">%2$s</xliff:g> ଅନୁମତିଗୁଡ଼ିକୁ କାଢ଼ି ଦିଆଯିବ।"</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"ଅନୁମତିଗୁଡ଼ିକୁ କାଢ଼ି ଦିଆଯିବ: <xliff:g id="PERMS">%1$s</xliff:g>।"</string>
<string name="auto_manage_title" msgid="7693181026874842935">"ଅନୁମତିଗୁଡ଼ିକୁ ସ୍ୱଚାଳିତ ଭାବେ ପରିଚାଳନା କର"</string>
- <string name="off" msgid="1438489226422866263">"ବନ୍ଦ ଅଛି"</string>
<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_tv_summary" msgid="3685907153054355671">"ଯଦି କୌଣସି ଆପକୁ କିଛି ମାସ ପାଇଁ ବ୍ୟବହାର କରାଯାଇନାହିଁ, ତେବେ:\n\n• ଆପଣଙ୍କ ଡାଟାକୁ ସୁରକ୍ଷିତ ରଖିବା ପାଇଁ ଅନୁମତିଗୁଡ଼ିକୁ କାଢ଼ି ଦିଆଯାଏ\n• ସ୍ପେସ ଖାଲି କରିବା ପାଇଁ ଅସ୍ଥାୟୀ ଫାଇଲଗୁଡ଼ିକୁ କାଢ଼ି ଦିଆଯାଏ\n\n• ପୁଣି ଅନୁମତିଗୁଡ଼ିକ ଦେବା ପାଇଁ, ଆପକୁ ଖୋଲନ୍ତୁ।"</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"ଗତଥର <xliff:g id="NUMBER">%s</xliff:g> ମାସ ପୂର୍ବେ ଖୋଲାଯାଇଥିଲା"</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>
@@ -251,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 ଘଣ୍ଟା}other{# ଘଣ୍ଟା}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 ମିନିଟ}other{# ମିନିଟ}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 ସେକେଣ୍ଡ}other{# ସେକେଣ୍ଡ}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# ଘଣ୍ଟା}other{# ଘଣ୍ଟା}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<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_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_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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android ସିଷ୍ଟମ"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"ଗୋପନୀୟତାକୁ ସୁରକ୍ଷା ଦେବା ପାଇଁ ଆପ୍ ଅନୁମତିଗୁଡ଼ିକ କାଢ଼ି ଦିଆଯାଇଛି"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g>କୁ କିଛି ମାସ ହେଲା ବ୍ୟବହାର କରାଯାଇନାହିଁ। ସମୀକ୍ଷା କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> ଏବଂ ଅନ୍ୟ 1ଟି ଆପ୍ କିଛି ମାସ ହେଲା ବ୍ୟବହାର କରାଯାଇନାହିଁ। ସମୀକ୍ଷା କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
@@ -378,6 +397,10 @@
<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_short_label" msgid="8796604147546125285">"ନୋଟ୍ସ ଆପ"</string>
+ <string name="role_notes_description" msgid="8496852798616883551">"ଆପଣଙ୍କ ଡିଭାଇସରେ ଆପଣଙ୍କୁ ନୋଟ ନେବା ପାଇଁ ଅନୁମତି ଦେଉଥିବା ଆପ୍ସ"</string>
+ <string name="role_notes_search_keywords" msgid="7710756695666744631">"ନୋଟ"</string>
<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>
@@ -403,7 +426,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>
@@ -452,6 +475,7 @@
<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_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_microphone" msgid="2825208549114811299">"&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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"ନିୟନ୍ତ୍ରିତ ଅନୁରୋଧଗୁଡ଼ିକ"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"ଲୋକେସନ୍ ଆକ୍ସେସ୍ କରାଯାଇପାରିବ"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"ଆପଣଙ୍କ IT ଆଡମିନ୍ <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"ସୁରକ୍ଷା ଏବଂ ଗୋପନୀୟତା"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"ସ୍କାନ କରନ୍ତୁ"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"ସେନ୍ସର ଅନୁମତିଗୁଡ଼ିକ"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"ଗୋପନୀୟତା ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"ଅନୁମତିକୁ କାଢ଼ି ଦିଆଯାଇଛି"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"କ୍ୟାମେରାର ଅଧିକ ବ୍ୟବହାର ଦେଖନ୍ତୁ"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"ମାଇକ୍ରୋଫୋନର ଅଧିକ ବ୍ୟବହାର ଦେଖନ୍ତୁ"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"କ୍ୟାମେରା ଅନୁମତି କାଢ଼ି ଦିଅନ୍ତୁ"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"ମାଇକ୍ରୋଫୋନ ଅନୁମତି କାଢ଼ି ଦିଅନ୍ତୁ"</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="manage_service_qs" msgid="7862555549364153805">"ସେବା ପରିଚାଳନା କରନ୍ତୁ"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"ଅନୁମତିଗୁଡ଼ିକୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"ଫୋନ କଲ ଦ୍ୱାରା ବ୍ୟବହାର କରାଯାଉଛି"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"ସୁରକ୍ଷା ଏବଂ ଗୋପନୀୟତା"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"ସ୍ଥିତି ଯାଞ୍ଚ କରନ୍ତୁ"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"ଡେଭେଲପର କମ୍ୟୁନିକେସନ"</string>
+ <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="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="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="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>
</resources>
diff --git a/PermissionController/res/values-pa-v33/strings.xml b/PermissionController/res/values-pa-v33/strings.xml
index e893c5bbc..03e18ae50 100644
--- a/PermissionController/res/values-pa-v33/strings.xml
+++ b/PermissionController/res/values-pa-v33/strings.xml
@@ -19,4 +19,28 @@
<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="work_policy_title" msgid="832967780713677409">"ਤੁਹਾਡੀ ਕਾਰਜ ਨੀਤੀ ਸੰਬੰਧੀ ਜਾਣਕਾਰੀ"</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>
+ <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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"ਬੰਦ ਕਰੋ"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"ਵਿਸਤਾਰ ਕਰੋ ਅਤੇ ਵਿਕਲਪ ਦਿਖਾਓ"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"ਸਮੇਟੋ"</string>
+ <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_gear_label" msgid="5175877094379694098">"ਸੈਟਿੰਗਾਂ"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"ਜਾਣਕਾਰੀ"</string>
</resources>
diff --git a/PermissionController/res/values-pa-v34/strings.xml b/PermissionController/res/values-pa-v34/strings.xml
new file mode 100644
index 000000000..c0b70fb57
--- /dev/null
+++ b/PermissionController/res/values-pa-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-pa/strings.xml b/PermissionController/res/values-pa/strings.xml
index 394453047..f4e26680c 100644
--- a/PermissionController/res/values-pa/strings.xml
+++ b/PermissionController/res/values-pa/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"ਹਮੇਸ਼ਾਂ ਸਭ ਨੂੰ ਆਗਿਆ ਦਿਓ"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"ਸਕ੍ਰੀਨ ਓਵਰਲੇਅ ਦਾ ਪਤਾ ਲੱਗਿਆ"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"ਇਸ ਇਜ਼ਾਜਤ ਸੈਟਿੰਗ ਨੂੰ ਬਦਲਣ ਲਈ, ਤੁਹਾਨੂੰ ਪਹਿਲਾਂ ਸੈਟਿੰਗਾਂ &gt; ਐਪਾਂ ਤੋਂ ਸਕ੍ਰੀਨ ਓਵਰਲੇਅ ਬੰਦ ਕਰਨਾ ਪਵੇਗਾ"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹੋ"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 ਦਿਨ}one{# ਦਿਨ}other{# ਦਿਨ}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 ਘੰਟਾ}one{# ਘੰਟਾ}other{# ਘੰਟੇ}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 ਮਿੰਟ}one{# ਮਿੰਟ}other{# ਮਿੰਟ}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 ਸਕਿੰਟ}one{# ਸਕਿੰਟ}other{# ਸਕਿੰਟ}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# ਦਿਨ}one{# ਦਿਨ}other{# ਦਿਨ}}"</string>
+ <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_time" msgid="3802087027301631827">"ਕਿਸੇ ਵੀ ਵੇਲੇ"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"ਪਿਛਲੇ 7 ਦਿਨ"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"ਪਿਛਲੇ 24 ਘੰਟੇ"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"ਪਿਛਲਾ 1 ਘੰਟਾ"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"ਪਿਛਲੇ 15 ਮਿੰਟ"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"ਪਿਛਲੇ 1 ਮਿੰਟ"</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>
+ <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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"ਪਿਛਲੇ 24 ਘੰਟਿਆਂ ਵਿੱਚ ਵਰਤੀਆਂ ਨਹੀਂ ਗਈਆਂ"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"ਪਿਛਲੇ 7 ਦਿਨਾਂ ਵਿੱਚ ਵਰਤੀਆਂ ਨਹੀਂ ਗਈਆਂ"</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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"ਹਮੇਸ਼ਾਂ ਸਭ ਦੀ ਇਜਾਜ਼ਤ ਹੈ"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"ਹਰ ਵਾਰ ਪੁੱਛੋ"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"ਨਾ ਕਰਨ ਦਿਓ"</string>
<string name="precise_image_description" msgid="6349638632303619872">"ਸਹੀ ਟਿਕਾਣਾ"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> ਅਤੇ <xliff:g id="PERM_1">%2$s</xliff:g> ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"ਹਟਾ ਦਿੱਤੀਆਂ ਜਾਣ ਵਾਲੀਆਂ ਇਜਾਜ਼ਤਾਂ: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"ਇਜਾਜ਼ਤਾਂ ਦਾ ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
- <string name="off" msgid="1438489226422866263">"ਬੰਦ"</string>
<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_tv_summary" msgid="3685907153054355671">"ਜੇ ਕਿਸੇ ਐਪ ਨੂੰ ਕੁਝ ਮਹੀਨਿਆਂ ਤੱਕ ਵਰਤਿਆ ਨਹੀਂ ਜਾਂਦਾ ਹੈ, ਤਾਂ:\n\n• ਤੁਹਾਡੇ ਡਾਟੇ ਦੀ ਸੁਰੱਖਿਆ ਕਰਨ ਲਈ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਂਦਾ ਹੈ\n• ਜਗ੍ਹਾ ਖਾਲੀ ਕਰਨ ਲਈ ਅਸਥਾਈ ਫ਼ਾਈਲਾਂ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਂਦਾ ਹੈ\n\nਦੁਬਾਰਾ ਇਜਾਜ਼ਤਾਂ ਦੇਣ ਲਈ, ਐਪ ਖੋਲ੍ਹੋ।"</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"ਪਿਛਲੀ ਵਾਰ <xliff:g id="NUMBER">%s</xliff:g> ਤੋਂ ਵੱਧ ਮਹੀਨੇ ਪਹਿਲਾਂ ਖੋਲ੍ਹੀਆਂ ਗਈਆਂ"</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>
<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,9 +254,9 @@
<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{# ਦਿਨ}other{# ਦਿਨ}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 ਘੰਟਾ}one{# ਘੰਟਾ}other{# ਘੰਟੇ}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 ਮਿੰਟ}one{# ਮਿੰਟ}other{# ਮਿੰਟ}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 ਸਕਿੰਟ}one{# ਸਕਿੰਟ}other{# ਸਕਿੰਟ}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# ਘੰਟਾ}one{# ਘੰਟਾ}other{# ਘੰਟੇ}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# ਮਿੰਟ}one{# ਮਿੰਟ}other{# ਮਿੰਟ}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# ਸਕਿੰਟ}one{# ਸਕਿੰਟ}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>
@@ -262,6 +265,9 @@
<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>
+ <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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android ਸਿਸਟਮ"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"ਪਰਦੇਦਾਰੀ ਸੁਰੱਖਿਆ ਲਈ ਐਪ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਹਟਾਇਆ ਗਿਆ"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> ਨੂੰ ਕੁਝ ਮਹੀਨਿਆਂ ਤੋਂ ਵਰਤਿਆ ਨਹੀਂ ਗਿਆ। ਸਮੀਖਿਆ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> ਅਤੇ 1 ਹੋਰ ਐਪ ਨੂੰ ਕੁਝ ਮਹੀਨਿਆਂ ਤੋਂ ਵਰਤਿਆ ਨਹੀਂ ਗਿਆ। ਸਮੀਖਿਆ ਲਈ ਟੈਪ ਕਰੋ।"</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"ਨੋਟ-ਕਥਨ"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"ਨਿਯੰਤਰਿਤ ਇਜਾਜ਼ਤਾਂ"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"ਤੁਹਾਡਾ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"ਸੁਰੱਖਿਆ ਅਤੇ ਪਰਦੇਦਾਰੀ"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"ਸਕੈਨ ਕਰੋ"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"ਸੈਂਸਰ ਇਜਾਜ਼ਤਾਂ"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"ਪਰਦੇਦਾਰੀ ਕੰਟਰੋਲ"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"ਇਜਾਜ਼ਤ ਹਟਾਈ ਗਈ"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"ਕੈਮਰੇ ਦੀ ਜ਼ਿਆਦਾ ਵਰਤੋਂ ਬਾਰੇ ਦੇਖੋ"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਦੀ ਜ਼ਿਆਦਾ ਵਰਤੋਂ ਬਾਰੇ ਦੇਖੋ"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"ਕੈਮਰਾ ਇਜਾਜ਼ਤ ਹਟਾਓ"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਇਜਾਜ਼ਤ ਹਟਾਓ"</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="manage_service_qs" msgid="7862555549364153805">"ਸੇਵਾ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"ਇਜਾਜ਼ਤਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"ਫ਼ੋਨ ਕਾਲ ਦੁਆਰਾ ਵਰਤਿਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"ਸੁਰੱਖਿਆ ਅਤੇ ਪਰਦੇਦਾਰੀ"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"ਸਥਿਤੀ ਦੀ ਜਾਂਚ ਕਰੋ"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"ਵਿਕਾਸਕਾਰ ਸੰਚਾਰ"</string>
+ <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="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="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="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>
</resources>
diff --git a/PermissionController/res/values-pl-v33/strings.xml b/PermissionController/res/values-pl-v33/strings.xml
index d2474c94c..a6cdbd775 100644
--- a/PermissionController/res/values-pl-v33/strings.xml
+++ b/PermissionController/res/values-pl-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Ta aplikacja będzie mogła wysyłać Ci powiadomienia i będzie miała dostęp do aparatu, mikrofonu, kontaktów, telefonu i SMS-ów"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Ta aplikacja będzie mogła wysyłać Ci powiadomienia i będzie miała dostęp do aparatu, mikrofonu, kontaktów, plików, telefonu i SMS-ów"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Aplikacje z tym uprawnieniem mogą korzystać ze wszystkich plików na tym urządzeniu"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Informacje o zasadach służbowych"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Ustawienia, którymi zarządza administrator IT"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Rozwiń i pokaż listę"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Zwiń listę i ukryj ustawienia"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Lista. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Lista. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Wymagane działanie. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Pozycja na liście. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Zamknij"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Rozwiń i pokaż opcje"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Zwiń"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Przełącznik. <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">"Przełączyć"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Otwórz"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Sprawdź ustawienia"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Ustawienia"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Informacje"</string>
</resources>
diff --git a/PermissionController/res/values-pl-v34/strings.xml b/PermissionController/res/values-pl-v34/strings.xml
new file mode 100644
index 000000000..b69bf4c4f
--- /dev/null
+++ b/PermissionController/res/values-pl-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Bezpieczeństwo i prywatność"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Ustawienia"</string>
+ <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">"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 d7b7c2d77..cab2d9d2e 100644
--- a/PermissionController/res/values-pl/strings.xml
+++ b/PermissionController/res/values-pl/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Wstecz"</string>
<string name="available" msgid="6007778121920339498">"Odblokowany"</string>
<string name="blocked" msgid="9195547604866033708">"Zablokowany"</string>
+ <string name="on" msgid="280241003226755921">"Włączona"</string>
+ <string name="off" msgid="1438489226422866263">"Wyłączono"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Odinstaluj lub wyłącz"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Nie znaleziono aplikacji"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Nie zezwalaj"</string>
@@ -30,11 +32,16 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Zachowaj „Podczas używania aplikacji”"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Zachowaj „Tylko tym razem”"</string>
<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_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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Wykryto nakładkę ekranową"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Aby zmodyfikować te uprawnienia, musisz najpierw wyłączyć nakładkę ekranową, klikając Ustawienia &gt; Aplikacje"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Otwórz ustawienia"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"<xliff:g id="PERMGROUP">%1$s</xliff:g> – czas używania przez aplikacje w ciągu ostatnich 7 dni"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Kiedy ta aplikacja używała uprawnień z grupy <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Więcej informacji"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Więcej informacji o: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Kontroluj dostęp aplikacji do: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 dzień}few{# dni}many{# dni}other{# dnia}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 godzina}few{# godziny}many{# godzin}other{# godziny}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}few{# min}many{# min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 s}few{# s}many{# s}other{# s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# dzień}few{# dni}many{# dni}other{# dnia}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# godzina}few{# godziny}many{# godzin}other{# godziny}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}few{# min}many{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}few{# s}many{# s}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Dowolne uprawnienie"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Dowolny czas"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Ostatnie 7 dni"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Ostatnie 24 godziny"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Ostatnia godzina"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Ostatnie 15 minut"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Ostatnia minuta"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Ostatni dzień}few{Ostatnie # dni}many{Ostatnie # dni}other{Ostatnie # dnia}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Ostatnia godzina}few{Ostatnie # godz.}many{Ostatnie # godz.}other{Ostatnie # godz.}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Ostatnia minuta}few{Ostatnie # minuty}many{Ostatnie # minut}other{Ostatnie # minuty}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Brak użycia uprawnień"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Ostatni dostęp w dowolnym okresie"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Najnowsze użycie w ciągu ostatnich 7 dni"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Użycie uprawnień w ciągu ostatniej godziny"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Użycie uprawnień w ciągu ostatnich 15 minut"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Użycie uprawnień w ciągu ostatniej minuty"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Nie używano w ciągu ostatnich 24 godzin"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Nie używano w ciągu ostatnich 7 dni"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Nie używano w ciągu ostatniego dnia}few{Nie używano w ciągu ostatnich # dni}many{Nie używano w ciągu ostatnich # dni}other{Nie używano w ciągu ostatniej # dnia}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Nie używano w ciągu ostatniej godziny}few{Nie używano w ciągu ostatnich # godzin}many{Nie używano w ciągu ostatnich # godzin}other{Nie używano w ciągu ostatnich # godzin}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Uprawnienie używane przez 1 aplikację}few{Uprawnienie używane przez # aplikacje}many{Uprawnienie używane przez # aplikacji}other{Uprawnienie używane przez # aplikacji}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Pokaż wszystko w panelu"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrowane według: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Pozwól na dostęp tylko do multimediów"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Zawsze zezwalaj"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Zezwalaj tylko podczas używania aplikacji"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Zawsze zezwalaj na wszystko"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Zawsze pytaj"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Nie zezwalaj"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Dokładna lokalizacja"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Te uprawnienia zostaną usunięte: <xliff:g id="PERM_0">%1$s</xliff:g> i <xliff:g id="PERM_1">%2$s</xliff:g>."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Uprawnienia, które zostaną usunięte: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Automatyczne zarządzanie uprawnieniami"</string>
- <string name="off" msgid="1438489226422866263">"Wyłączono"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Usunięto uprawnienie <xliff:g id="PERMISSION_NAME">%s</xliff:g>"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Usunięto uprawnienia: <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> oraz <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g>"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Usunięto uprawnienia: <xliff:g id="PERMISSION_NAME">%1$s</xliff:g> oraz kilka innych (<xliff:g id="NUMBER">%2$s</xliff:g>)"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Nieużywane aplikacje"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Jeśli aplikacja jest nieużywana od kilku miesięcy:\n\n• aby chronić Twoje dane, odbieramy jej uprawnienia;\n• zatrzymujemy powiadomienia, aby oszczędzać baterię;\n• usuwamy pliki tymczasowe, aby zwolnić miejsce.\n\nAby ponownie przyznać uprawnienia i zezwolić na powiadomienia, otwórz aplikację."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Jeśli aplikacja jest nieużywana od kilku miesięcy:\n\n• aby chronić Twoje dane, odbieramy jej uprawnienia;\n• usuwamy pliki tymczasowe, aby zwolnić miejsce.\n\nAby ponownie przyznać uprawnienia, otwórz aplikację."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Ostatnio otwarte ponad <xliff:g id="NUMBER">%s</xliff:g> mies. temu"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Jeśli aplikacja jest nieużywana przez miesiąc:\n\n• aby chronić Twoje dane, odbieramy jej uprawnienia;\n• usuwamy pliki tymczasowe, aby zwolnić miejsce.\n\nAby ponownie przyznać uprawnienia, otwórz aplikację."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Ostatnio otwarte ponad miesiąc temu}few{Ostatnio otwarte ponad # miesiące temu}many{Ostatnio otwarte ponad # miesięcy temu}other{Ostatnio otwarte ponad # miesiąca temu}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Aplikacja została ostatnio otwarta <xliff:g id="DATE">%s</xliff:g>"</string>
<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 mają <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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Nie mają dostępu"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Zobacz więcej aplikacji z dostępem do wszystkich plików"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 dzień}few{# dni}many{# dni}other{# dnia}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 godzina}few{# godziny}many{# godzin}other{# godziny}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minuta}few{# minuty}many{# minut}other{# minuty}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 sekunda}few{# sekundy}many{# sekund}other{# sekundy}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# godzina}few{# godziny}many{# godzin}other{# godziny}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minuta}few{# minuty}many{# minut}other{# minuty}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# sekunda}few{# sekundy}many{# sekund}other{# sekundy}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Przypomnienia o uprawnieniach"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 nieużywana aplikacja"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"Nieużywane aplikacje (<xliff:g id="NUMBER_OF_APPS">%s</xliff:g>)"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Niektóre aplikacje nie były używane od kilku miesięcy. Kliknij, by sprawdzić."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# nieużywana aplikacja}few{# nieużywane aplikacje}many{# nieużywanych aplikacji}other{# nieużywanej aplikacji}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Uprawnienia i pliki tymczasowe zostały usunięte, a powiadomienia zostały zatrzymane. Kliknij, aby sprawdzić."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Zweryfikuj aplikacje, których uprawnienia usunięto"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Usunięto uprawnienia i pliki tymczasowe oraz zatrzymano powiadomienia w przypadku aplikacji, z których nie korzystasz już przez jakiś czas."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Przejrzyj aplikacje"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Sprawdź ostatnie uprawnienia"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Podczas jazdy przyznałeś(-aś) aplikacji <xliff:g id="APP">%1$s</xliff:g> te uprawnienia: <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Podczas jazdy przyznałeś(-aś) aplikacji <xliff:g id="APP">%1$s</xliff:g> te uprawnienia: <xliff:g id="PERMISSION_1">%2$s</xliff:g> i <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Usunięto uprawnienia, by chronić Twoją prywatność."</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"Aplikacja <xliff:g id="APP_NAME">%s</xliff:g> uzyskała dostęp do Twojej lokalizacji w tle"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Ta aplikacja może zawsze uzyskać dostęp do Twojej lokalizacji. Kliknij, by to zmienić."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Zweryfikuj aplikacje z dostępem do powiadomień"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"Aplikacja <xliff:g id="APP_NAME">%s</xliff:g> może odrzucać treści w powiadomieniach, korzystać z nich oraz wykonywać dotyczące ich działania"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Ta aplikacja może odrzucać treści w powiadomieniach, korzystać z nich oraz wykonywać zawarte w nich działania. Niektóre aplikacje wymagają takiego dostępu, aby działać prawidłowo."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Usuń dostęp"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Pokaż więcej opcji"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Dostęp usunięty"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Zweryfikuj aplikację z pełnym dostępem do urządzenia"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> może wyświetlać Twój ekran i wykonywać działania na Twoim urządzeniu. Aplikacje z ułatwieniami dostępu potrzebują tego typu dostępu, aby funkcjonować prawidłowo."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Ta aplikacja może wyświetlać Twój ekran i wykonywać działania na Twoim urządzeniu. Aplikacje z ułatwieniami dostępu potrzebują tego typu dostępu, aby działać prawidłowo, ale sprawdź aplikację i upewnij się, że jej ufasz."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Anuluj dostęp"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Wyświetl aplikacje z pełnym dostępem"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Dostęp usunięty"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"System Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Usunięto uprawnienia aplikacji, by chronić prywatność"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Aplikacja <xliff:g id="APP_NAME">%s</xliff:g> nie była używana od kilku miesięcy. Kliknij, by sprawdzić."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"Aplikacja <xliff:g id="APP_NAME">%s</xliff:g> i jeszcze 1 aplikacja nie były używane od kilku miesięcy. Kliknij, by sprawdzić."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> będzie mogła korzystać z powiadomień oraz uprawnień dotyczących Telefonu, SMS-ów, Kontaktów i Kalendarza."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> będzie mogła korzystać z powiadomień oraz odtwarzać strumieniowo dane z aplikacji na połączonych urządzeniach."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Ta usługa udostępnia Twoje zdjęcia, multimedia i powiadomienia z telefonu innym urządzeniom."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Domyślna aplikacja do notatek"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Pozwolenia kontrolowane"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Można użyć lokalizacji"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Administrator IT zezwala aplikacji <xliff:g id="APP_NAME">%s</xliff:g> na dostęp do Twojej lokalizacji"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"dla aplikacji i usług"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Dane z mikrofonu mogą być udostępniane, kiedy dzwonisz na numer alarmowy."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Zmień"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Bezpieczeństwo i prywatność"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Skanuj"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Bezpieczeństwo i prywatność"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Przeskanuj urządzenie"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Odrzuć"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Zamknąć ten alert?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Sprawdź ustawienia zabezpieczeń i prywatności w dowolnym momencie, aby zwiększyć bezpieczeństwo"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Zamknij"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Anuluj"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Ustawienia"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Stan bezpieczeństwa i prywatności. <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">"Ustawienia zabezpieczeń"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Uprawnienia dotyczące czujnika"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Ustawienia prywatności"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Uprawnienia"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Bezpieczeństwo i prywatność"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Sprawdź stan"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Ustawienia prywatności"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Więcej ustawień"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Dostęp do aparatu"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Dostęp do mikrofonu"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Usunięto uprawnienia"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Zobacz więcej informacji o wykorzystaniu aparatu"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Zobacz więcej informacji o wykorzystaniu mikrofonu"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Usuń uprawnienia dotyczące aparatu"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Usuń uprawnienia dotyczące mikrofonu"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Zobacz ostatnie przypadki użycia aparatu"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Zobacz ostatnie przypadki użycia mikrofonu"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Wycofaj uprawnienie tej aplikacji"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Wycofaj uprawnienie tej aplikacji"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Zarządzaj usługą"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Zarządzanie uprawnieniami"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Używane przez rozmowę telefoniczną"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Ostatnio używane przez aplikację <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">"Używane przez aplikację <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">"Ostatnio używane przez aplikację <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Bezpieczeństwo i prywatność"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Sprawdź stan"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Potwierdź"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Wstecz"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Dostęp do innych plików również będzie możliwy"</string>
@@ -537,4 +570,53 @@
<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 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 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">"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>
+ <string name="show_password_title" msgid="2877269286984684659">"Pokazuj hasła"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Wpisywane znaki są przez chwilę wyświetlane"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Sposoby postępowania z danymi mogą się różnić w zależności od wersji aplikacji, jej użycia, regionu i wieku użytkownika. "<annotation id="link">"Więcej o udostępnianiu danych"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Sposoby postępowania z danymi mogą się różnić w zależności od wersji aplikacji, jej użycia, regionu i wieku użytkownika."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Twoje dane o lokalizacji"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Dostęp tej aplikacji możesz zmienić w "<annotation id="link">"ustawieniach prywatności"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Funkcje aplikacji"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Statystyki"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Informacje od dewelopera"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Cele marketingowe"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Zapobieganie oszustwom, bezpieczeństwo i zgodność z przepisami"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalizacja"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Zarządzanie kontem"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Deweloperzy tych aplikacji zamieścili w sklepie z aplikacjami informacje o swoich sposobach udostępniania danych. Co jakiś czas mogą wprowadzać w nich zmiany.\n\nSposoby udostępniania danych mogą się różnić w zależności od wersji aplikacji, jej użycia, regionu i wieku użytkownika."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Więcej informacji o udostępnianiu danych"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Twoje dane o lokalizacji są teraz udostępniane innym podmiotom"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Twoje dane o lokalizacji są teraz udostępniane innym podmiotom w celach marketingowych"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Zaktualizowano w ostatnim dniu}=1{Zaktualizowano w ostatnim dniu}few{Zaktualizowano w ostatnich # dniach}many{Zaktualizowano w ostatnich # dniach}other{Zaktualizowano w ostatnich # dnia}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Obecnie nie ma żadnych aktualizacji"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-pt-rBR-v33/strings.xml b/PermissionController/res/values-pt-rBR-v33/strings.xml
index 789bd290c..aeda06c8f 100644
--- a/PermissionController/res/values-pt-rBR-v33/strings.xml
+++ b/PermissionController/res/values-pt-rBR-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Este app terá permissão para enviar notificações e poderá acessar contatos, câmera, microfone, telefone e SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Este app vai poder enviar notificações e acessar contatos, câmera, arquivos, microfone, telefone e SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Apps com esta permissão podem acessar todos os arquivos neste dispositivo."</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Informações sobre sua política de trabalho"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Configurações gerenciadas pelo administrador de TI"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Abrir e mostrar lista"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Fechar lista e ocultar configurações"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Lista. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Lista. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Ações necessárias. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Item da lista. <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">"Mais alertas"</string>
+ <string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Alertas dispensados"</string>
+ <string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Abra para ver mais um alerta}one{Abra para ver mais # alerta}many{Abra para ver mais # de alertas}other{Abra para ver mais # alertas}}"</string>
+ <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 configurações que podem adicionar mais proteção ao seu dispositivo"</string>
+ <string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Configurações rápidas de segurança e privacidade"</string>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Fechar"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Abrir e mostrar opções"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Fechar"</string>
+ <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­çõ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-v34/strings.xml b/PermissionController/res/values-pt-rBR-v34/strings.xml
new file mode 100644
index 000000000..6e77e0432
--- /dev/null
+++ b/PermissionController/res/values-pt-rBR-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Segurança e privacidade"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Controles"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Conexão Saúde"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Gerenciar o acesso de apps aos dados de saúde"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Acesso ao local"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Para apps e serviços. Se esta configuração estiver desativada, os dados do microfone ainda poderão ser compartilhados quando você ligar para um número de emergência"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Para apps e serviços"</string>
+</resources>
diff --git a/PermissionController/res/values-pt-rBR/strings.xml b/PermissionController/res/values-pt-rBR/strings.xml
index 6c890d7ee..73de80954 100644
--- a/PermissionController/res/values-pt-rBR/strings.xml
+++ b/PermissionController/res/values-pt-rBR/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Voltar"</string>
<string name="available" msgid="6007778121920339498">"Disponível"</string>
<string name="blocked" msgid="9195547604866033708">"Bloqueado"</string>
+ <string name="on" msgid="280241003226755921">"Ativado"</string>
+ <string name="off" msgid="1438489226422866263">"Desativar"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Desinstalar ou desativar"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"App não encontrado"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Não permitir"</string>
@@ -30,11 +32,16 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Manter \"Enquanto o app estiver em uso\""</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Manter \"Apenas esta vez\""</string>
<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">"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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Sobreposição de tela detectada"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Para alterar a configuração dessa permissão, primeiro você precisa desativar a sobreposição de tela em \"Config.\" &gt; \"Apps\""</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Abrir configurações"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Linha do tempo de quando apps usaram a permissão de <xliff:g id="PERMGROUP">%1$s</xliff:g> nos últimos sete dias"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Quando esse app usou a permissão <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Saiba mais"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Saiba mais sobre esta permissão: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Controle o acesso do app ao seguinte grupo de permissões: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 dia}one{# dia}many{# dias}other{# dias}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 hora}one{# hora}many{# horas}other{# horas}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1min}one{#min}many{#min}other{#min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1s}one{#s}many{#s}other{#s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# dia}one{# dia}many{# de dias}other{# dias}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# hora}one{# hora}many{# de horas}other{# horas}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}one{# min}many{# de min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{#s}one{#s}many{# de segundos}other{#s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Qualquer permissão"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Qualquer horário"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Últimos 7 dias"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Últimas 24 horas"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Última hora"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Últimos 15 minutos"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Último minuto"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{No último dia}one{No último # dia}many{Nos últimos # de dias}other{Nos últimos # dias}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Na última # hora}one{Na última # hora}many{Nas últimas # de horas}other{Nas últimas # horas}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{No último # minuto}one{No último # minuto}many{Nos últimos # de minutos}other{Nos últimos # minutos}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Nenhum uso de permissões"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Acesso mais recente em qualquer momento"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Acesso mais recente nos últimos sete dias"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Uso da permissão na última hora"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Uso da permissão nos últimos 15 minutos"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Uso da permissão no último minuto"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Permissão não usada nas últimas 24 horas"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Permissão não usada nos últimos sete dias"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Não usado no último # dia}one{Não usado no último # dia}many{Não usado nos últimos # de dias}other{Não usado nos últimos # dias}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Não usado na última # hora}one{Não usado na última # hora}many{Não usado nas últimas # de horas}other{Não usado nas últimas # horas}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Permissões usadas por 1 app}one{Permissões usadas por # app}many{Permissões usadas por # apps}other{Permissões usadas por # apps}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Ver tudo no painel"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrado por: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Permitir acesso apenas a arquivos de mídia"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Permitir o tempo todo"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Permitir durante o uso do app"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Sempre permitir tudo"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Perguntar sempre"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Não permitir"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Local exato"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"As permissões <xliff:g id="PERM_0">%1$s</xliff:g> e <xliff:g id="PERM_1">%2$s</xliff:g> serão removidas."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Permissões que serão removidas: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Gerenciar permissões automaticamente"</string>
- <string name="off" msgid="1438489226422866263">"Desativar"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Permissão <xliff:g id="PERMISSION_NAME">%s</xliff:g> removida"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Permissões <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> e <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> removidas"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> e mais <xliff:g id="NUMBER">%2$s</xliff:g> permissões removidas"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Apps não usados"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Se um app fica sem uso por alguns meses:\n\n• as permissões são removidas para proteger seus dados;\n• as notificações são interrompidas para economizar bateria;\n• os arquivos temporários são removidos para liberar espaço.\n\nPara retomar as permissões e notificações, abra o app."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Se um app ficar sem uso por alguns meses:\n\n• as permissões serão removidas para proteger seus dados;\n• os arquivos temporários serão removidos para liberar espaço.\n\nPara dar as permissões novamente, abra o app."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Abertos pela última vez há mais de <xliff:g id="NUMBER">%s</xliff:g> meses"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Quando um app fica sem uso por um mês:\n\n• As permissões são removidas para proteger seus dados.\n• Os arquivos temporários são removidos para liberar espaço.\n\nSe quiser conceder as permissões novamente, abra o app."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Usado pela última vez há mais de # mês}one{Usado pela última vez há mais de # mês}many{Usado pela última vez há mais de # de meses}other{Usado pela última vez há mais de # meses}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"App aberto pela última vez em <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Aberto pela última vez em <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Se você permitir o gerenciamento de todos os arquivos, o app poderá acessar, modificar e excluir qualquer arquivo no armazenamento comum do dispositivo ou no armazenamento de dispositivos conectados. O app poderá acessar arquivos sem pedir autorização."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Não permitido"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Veja mais apps que têm acesso a todos os arquivos"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 dia}one{# dia}many{# dias}other{# dias}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 hora}one{# hora}many{# horas}other{# horas}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minuto}one{# minuto}many{# minutos}other{# minutos}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 segundo}one{# segundo}many{# segundos}other{# segundos}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# hora}one{# hora}many{# de horas}other{# horas}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minuto}one{# minuto}many{# de minutos}other{# minutos}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# segundo}one{# segundo}many{# de segundos}other{# segundos}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Lembretes de permissões"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 app não usado"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> apps não usados"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Alguns apps não foram usados nos últimos meses. Toque para revisar."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# app não usado}one{# app não usado}many{# apps não usados}other{# apps não usados}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"As permissões e os arquivos temporários foram removidos, e as notificações foram interrompidas. Toque para revisar."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Revisar apps com permissões removidas"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Para apps que você não usa há algum tempo, as permissões e os arquivos temporários foram removidos, e as notificações foram interrompidas."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Revisar apps"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Conferir as permissões recentes"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Enquanto dirigia, você deu ao app <xliff:g id="APP">%1$s</xliff:g> acesso a: <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Enquanto dirigia, você deu ao app <xliff:g id="APP">%1$s</xliff:g> acesso a: <xliff:g id="PERMISSION_1">%2$s</xliff:g> e <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"As permissões foram removidas para proteger sua privacidade"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"O app <xliff:g id="APP_NAME">%s</xliff:g> tem acesso à sua localização em segundo plano"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Este app pode acessar sua localização a qualquer momento. Toque para alterar."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Revisar app com acesso às suas notificações"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"O app <xliff:g id="APP_NAME">%s</xliff:g> pode dispensar, executar ações e acessar o conteúdo das suas notificações"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Este app pode dispensar, executar ações e acessar o conteúdo das suas notificações. Alguns apps exigem esse acesso para funcionar como o esperado."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Remover acesso"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Ver mais opções"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Acesso removido"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Revisar app com acesso total ao dispositivo"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"O <xliff:g id="APP_NAME">%s</xliff:g> pode ver sua tela e realizar ações no seu dispositivo. Os apps de acessibilidade precisam desse tipo de acesso para funcionar como o esperado."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Este app pode ver sua tela e realizar ações no seu dispositivo. Os apps de acessibilidade precisam desse tipo de acesso para funcionar como o esperado, mas confira o app e confirme se você confia nele."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Remover o acesso"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Ver apps com acesso total"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Acesso removido"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Sistema Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Permissões de apps removidas para proteger a privacidade"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"O app <xliff:g id="APP_NAME">%s</xliff:g> não foi usado nos últimos meses. Toque para analisar."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> e mais um app não foram usados nos últimos meses. Toque para analisar."</string>
@@ -350,7 +369,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>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e fazer streaming de outros apps para os dispositivos conectados."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Este serviço compartilha fotos, mídia e notificações do smartphone com outros dispositivos."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"App de notas padrão"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Permissões controladas"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"A localização pode ser acessada"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"O administrador de TI permitiu o acesso do app <xliff:g id="APP_NAME">%s</xliff:g> à sua localização"</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>
<string name="other_permissions_label" msgid="8986184335503271992">"Outras permissões"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Permissões usadas pelo sistema"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Permissões usadas apenas pelos aplicativos do sistema."</string>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Para apps e serviços"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Os dados do microfone ainda poderão ser compartilhados quando você ligar para um número de emergência."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Mudar"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Segurança e privacidade"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Escanear"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Segurança e privacidade"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Verificar dispositivo"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Dispensar"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Dispensar o alerta?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Revise suas configurações de segurança e privacidade a qualquer momento para aumentar a proteção"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Dispensar"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Cancelar"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Configurações"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Status de segurança e privacidade. <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">"Configurações de segurança"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Permissões do sensor"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Controles de privacidade"</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">"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>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Acesso ao microfone"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Permissão removida"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Ver mais usos da câmera"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Ver mais usos do microfone"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Remover permissão da câmera"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Remover permissão do microfone"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Ver o uso recente da câmera"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Ver o uso recente do microfone"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Remover permissão deste app"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Remover permissão deste app"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Gerenciar serviço"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Gerenciar permissões"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Em uso pela chamada telefônica"</string>
@@ -517,8 +552,6 @@
<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>
<string name="recent_app_usage_2_qs" msgid="3591205954235694403">"Usada recentemente 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>
- <string name="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Segurança e privacidade"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Checar status"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Confirmar"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Voltar"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"O acesso a outros arquivos também será permitido"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Este app não tem suporte à versão mais recente do Android. Se ele não puder acessar arquivos de áudio e música, também não vai poder acessar fotos e vídeos."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Este app não tem suporte à versão mais recente do Android. Se ele puder acessar fotos e vídeos, também vai poder acessar arquivos de áudio e música."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Este app não tem suporte à versão mais recente do Android. Se ele não puder acessar arquivos de áudio e música, também não vai poder acessar fotos e vídeos."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Revisar apps com acesso à localização em segundo plano"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"O <xliff:g id="APP_NAME">%s</xliff:g> sempre pode acessar seu local, mesmo quando está fechado."</string>
+ <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">"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>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Para apps e serviços"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Para apps e serviços. Se esta configuração estiver desativada, os dados do microfone ainda poderão ser compartilhados quando você ligar para um número de emergência."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Veja apps e serviços que têm acesso à localização"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Mostrar acesso à área de transferência"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Mostrar uma mensagem quando os apps acessarem textos, imagens ou outros conteúdos copiados"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Mostrar senhas"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Mostrar os caracteres rapidamente enquanto você digita"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"As práticas relacionadas a dados podem variar de acordo com a versão do app e com a idade, uso e região do usuário. "<annotation id="link">"Mais informações sobre o compartilhamento de dados"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"As práticas relacionadas a dados podem variar de acordo com a versão do app e com a idade, uso e região do usuário."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Seus dados de local"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Mude o acesso do app nas "<annotation id="link">"configurações de privacidade"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Funcionalidade do app"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Análise"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Mensagens do desenvolvedor"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Publicidade ou marketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Segurança, conformidade e prevenção de fraudes"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalização"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Gerenciamento da conta"</string>
+ <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="data_sharing_updates_title" msgid="7996933386875213859">"Atualizações no compartilhamento de 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>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Seus dados de local agora são compartilhados com terceiros"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Seus dados de local agora são compartilhados com terceiros para fins de publicidade ou marketing"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Atualizado nas últimas 24 horas}=1{Atualizado nas últimas 24 horas}one{Atualizado há # dia}many{Atualizado há # de dias}other{Atualizado há # dias}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Não há atualizações no momento"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-pt-rPT-v33/strings.xml b/PermissionController/res/values-pt-rPT-v33/strings.xml
index ce6c64f80..a228677bf 100644
--- a/PermissionController/res/values-pt-rPT-v33/strings.xml
+++ b/PermissionController/res/values-pt-rPT-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Esta app fica autorizada a enviar-lhe notificações e é-lhe concedido acesso à sua Câmara, Contactos, Microfone, Telefone e SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Esta app fica autorizada a enviar-lhe notificações e é-lhe concedido acesso à sua Câmara, Contactos, Ficheiros, Microfone, Telefone e SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"As apps com esta autorização podem aceder a todos os ficheiros neste dispositivo"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"As suas informações da política de trabalho"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Definições geridas pelo seu administrador de TI"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Expandir e mostrar lista"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Reduzir lista e ocultar definições"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Lista. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Lista. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Ações necessárias. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Item de lista. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Fechar"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Expandir e mostrar opções"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Reduzir"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Interruptor. <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">"Ativar/desativar"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Abrir"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Rever definições"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Definições"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Informações"</string>
</resources>
diff --git a/PermissionController/res/values-pt-rPT-v34/strings.xml b/PermissionController/res/values-pt-rPT-v34/strings.xml
new file mode 100644
index 000000000..2f7ce1be2
--- /dev/null
+++ b/PermissionController/res/values-pt-rPT-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Segurança e privacidade"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Controlos"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Saúde Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Faça a gestão do acesso de apps a dados de saúde"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Acesso à localização"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Para apps e serviços. Se esta definição estiver desativada, os dados do microfone ainda podem ser partilhados quando ligar para um número de emergência"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Para apps e serviços"</string>
+</resources>
diff --git a/PermissionController/res/values-pt-rPT/strings.xml b/PermissionController/res/values-pt-rPT/strings.xml
index 3452722bc..012608eee 100644
--- a/PermissionController/res/values-pt-rPT/strings.xml
+++ b/PermissionController/res/values-pt-rPT/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Anterior"</string>
<string name="available" msgid="6007778121920339498">"Disponível"</string>
<string name="blocked" msgid="9195547604866033708">"Bloqueado"</string>
+ <string name="on" msgid="280241003226755921">"Ativado"</string>
+ <string name="off" msgid="1438489226422866263">"Desativar"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Desinstalar ou desativar"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Aplicação não encontrada"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Não permitir"</string>
@@ -30,11 +32,16 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Manter \"Enquanto a app está a ser utilizada”"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Manter “Apenas desta vez”"</string>
<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_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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Sobreposição de ecrã detetada"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Para alterar esta definição de autorização, primeiro tem de desativar a sobreposição do ecrã em Definições &gt; Apps"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Abrir definições"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Linha cronológica da utilização de <xliff:g id="PERMGROUP">%1$s</xliff:g> por apps nos últimos 7 dias"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Quando esta app utilizou a sua autorização de <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Saiba mais"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Saiba mais sobre <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Controle o acesso de apps ao grupo <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 dia}many{# dias}other{# dias}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 hora}many{# horas}other{# horas}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}many{# min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 s}many{# s}other{# s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# dia}many{# dias}other{# dias}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# hora}many{# horas}other{# horas}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}many{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}many{# s}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Qualquer autorização"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Em qualquer altura"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Últimos 7 dias"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Últimas 24 horas"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Última hora"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Últimos 15 minutos"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Último minuto"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{# dia anterior}many{# dias anteriores}other{# dias anteriores}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{# hora anterior}many{# horas anteriores}other{# horas anteriores}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{# minuto anterior}many{# minutos anteriores}other{# minutos anteriores}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Autorizações não utilizadas"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Acesso mais recente em qualquer altura"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Acesso mais recente nos últimos 7 dias"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Utilização das autorizações na última hora"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Utilização das autorizações nos últimos 15 minutos"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Utilização das autorizações no último minuto"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Sem utilização nas últimas 24 horas"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Não utilizada nos últimos 7 dias"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Não usada há # dia}many{Não usada há # dias}other{Não usada há # dias}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Não usada há # hora}many{Não usada há # horas}other{Não usada há # horas}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Utilização: 1 app}many{Utilização: # apps}other{Utilização: # apps}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Ver tudo no painel de controlo"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrado por: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Permitir apenas o acesso ao conteúdo multimédia"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Permitir sempre"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Permitir apenas enquanto uso a app"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Permitir sempre tudo"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Perguntar sempre"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Não permitir"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Localização exata"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"As autorizações <xliff:g id="PERM_0">%1$s</xliff:g> e <xliff:g id="PERM_1">%2$s</xliff:g> serão removidas."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Autorizações que serão removidas: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Gira as autorizações automaticamente"</string>
- <string name="off" msgid="1438489226422866263">"Desativar"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Autorização de <xliff:g id="PERMISSION_NAME">%s</xliff:g> removida."</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Autorizações de <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> e <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> removidas."</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Autorização de <xliff:g id="PERMISSION_NAME">%1$s</xliff:g> e mais <xliff:g id="NUMBER">%2$s</xliff:g> autorizações removidas."</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Apps não usadas"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Se uma app não for usada durante alguns meses:\n\n• As autorizações são removidas para proteger os seus dados\n• As notificações são interrompidas para poupar bateria\n• Os ficheiros temporários são removidos para libertar espaço\n\nPara voltar a permitir autorizações e notificações, abra a app."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Se uma app não for usada durante alguns meses:\n\n• As autorizações são removidas para proteger os seus dados\n• Os ficheiros temporários são removidos para libertar espaço\n\nPara voltar a permitir autorizações, abra a app."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Abertas pela última vez há mais de <xliff:g id="NUMBER">%s</xliff:g> meses"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Se uma app não for usada durante um mês:\n\n• As autorizações são removidas para proteger os seus dados\n• Os ficheiros temporários são removidos para libertar espaço\n\nPara voltar a permitir autorizações, abra a app."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Abertas pela última vez há mais de # mês}many{Abertas pela última vez há mais de # de meses}other{Abertas pela última vez há mais de # meses}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"A app foi aberta pela última vez a <xliff:g id="DATE">%s</xliff:g>."</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Último acesso a <xliff:g id="DATE">%s</xliff:g>."</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Se permitir a gestão de todos os ficheiros, esta app pode aceder, modificar e eliminar todos os ficheiros no armazenamento comum neste dispositivo ou nos dispositivos de armazenamento associados. A app pode aceder aos ficheiros sem lhe pedir autorização."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Não permitidas"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Veja mais apps que podem aceder a todos os ficheiros"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 dia}many{# dias}other{# dias}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 hora}many{# horas}other{# horas}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minuto}many{# minutos}other{# minutos}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 segundo}many{# segundos}other{# segundos}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# hora}many{# horas}other{# horas}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minuto}many{# minutos}other{# minutos}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# segundo}many{# segundos}other{# segundos}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Lembretes de autorização"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 app não utilizada"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> apps não utilizadas"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Algumas apps não são utilizadas há alguns meses. Toque para rever."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# app não utilizada}many{# apps não utilizadas}other{# apps não utilizadas}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"As autorizações e os ficheiros temporários foram removidos e as notificações foram interrompidas. Toque para rever."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Reveja as apps com as autorizações removidas"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Para as apps que não usa há algum tempo, as autorizações e os ficheiros temporários foram removidos e as notificações foram paradas."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Rever apps"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Verifique as autorizações recentes"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Durante a condução, deu à app <xliff:g id="APP">%1$s</xliff:g> acesso à autorização de <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Durante a condução, deu à app <xliff:g id="APP">%1$s</xliff:g> acesso à autorização de <xliff:g id="PERMISSION_1">%2$s</xliff:g> e <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Autorizações removidas para proteger a sua privacidade."</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"A app <xliff:g id="APP_NAME">%s</xliff:g> obteve a sua localização em segundo plano"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Esta app consegue aceder sempre à sua localização. Toque para alterar."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Reveja a app com acesso às suas notificações"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"A app <xliff:g id="APP_NAME">%s</xliff:g> pode ignorar, interagir com e aceder ao conteúdo nas suas notificações"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Esta app pode ignorar, interagir com e aceder ao conteúdo nas suas notificações. Algumas apps precisam deste acesso para funcionar conforme previsto."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Remover acesso"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Ver mais opções"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Acesso removido"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Reveja a app com acesso total ao dispositivo"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"A app <xliff:g id="APP_NAME">%s</xliff:g> pode ver o seu ecrã e realizar ações no seu dispositivo. As apps de acessibilidade precisam deste tipo de acesso para funcionar conforme previsto."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Esta app pode ver o seu ecrã e realizar ações no seu dispositivo. As apps de acessibilidade precisam deste tipo de acesso para funcionarem conforme previsto, mas verifique a app e confirme que confia na mesma."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Remover acesso"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Ver apps com acesso total"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Acesso removido"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Sistema Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Autorizações da app removidas para proteger a privacidade"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"A app <xliff:g id="APP_NAME">%s</xliff:g> não é utilizada há alguns meses. Toque para rever."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"A app <xliff:g id="APP_NAME">%s</xliff:g> e mais 1 app não são utilizadas há alguns meses. Toque para rever."</string>
@@ -334,41 +353,41 @@
<string name="role_browser_label" msgid="2877796144554070207">"App navegador predefinida"</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">"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>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com as suas notificações e aceder às autorizações do Telefone, SMS, Contactos e Calendário."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com as suas notificações e fazer stream das suas apps para o dispositivo ligado."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Este serviço partilha as fotos, o conteúdo multimédia e as notificações do seu telemóvel com outros dispositivos."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"App de notas predefinida"</string>
+ <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>
<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>
@@ -414,11 +437,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>
@@ -437,8 +460,8 @@
<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="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="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="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>
@@ -452,19 +475,20 @@
<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_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_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_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="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="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="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_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="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="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="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_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_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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Autorizações controladas"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"É possível aceder à localização"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"O seu administrador de TI está a permitir que a app <xliff:g id="APP_NAME">%s</xliff:g> aceda à sua localização"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Para apps e serviços"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Os dados do microfone ainda podem ser partilhados quando ligar para um número de emergência."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Alterar"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Segurança e privacidade"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Procurar"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Segurança e privacidade"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Analisar dispositivo"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Ignorar"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Ignorar este alerta?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Analise as suas definições de privacidade e segurança em qualquer altura para adicionar mais proteção"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Ignorar"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Cancelar"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Definições"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Estado de segurança e privacidade. <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">"Definições de segurança"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Autorizações do sensor"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Controlos de privacidade"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Autorizaçõ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">"Rever estado"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Controlos de privacidade"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Mais definições"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Acesso à câmara"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Acesso ao microfone"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Autorização removida"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Ver mais utilizações da câmara"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Ver mais utilizações do microfone"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Remover autorização da câmara"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Remover autorização do microfone"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Ver a utilização recente da câmara"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Ver a utilização recente do microfone"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Remover autorização para esta app"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Remover autorização para esta app"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Gerir serviço"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Gerir autorizações"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Em utilização pela chamada telefónica"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Utilizado recentemente pela app <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 utilização pela app <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">"Utilizado recentemente pela app <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Segurança e privacidade"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Rever estado"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Confirmar"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Anterior"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Também vai ter autorização para aceder a outros ficheiros"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Esta app não suporta a versão mais recente do Android. Se esta app não conseguir aceder a ficheiros de áudio e música, também não vai ter autorização para aceder a fotos nem vídeos."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Esta app não suporta a versão mais recente do Android. Se esta app conseguir aceder a fotos e vídeos, também vai ter autorização para aceder a ficheiros de áudio e música."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Esta app não suporta a versão mais recente do Android. Se esta app não conseguir aceder a ficheiros de áudio e música, também não vai ter autorização para aceder a fotos nem vídeos."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Reveja a app com acesso à localização em segundo plano"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"A app <xliff:g id="APP_NAME">%s</xliff:g> pode aceder sempre à sua localização, mesmo quando a app está fechada"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Reveja a app com acesso à localização em segundo plano"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Esta app pode aceder sempre à sua localização, mesmo quando está fechada.\n\nAlgumas apps de segurança e emergência precisam de acesso à sua localização em segundo plano para funcionarem como esperado."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Acesso alterado"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Ver utilização da localização recente"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Controlos de privacidade"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Acesso à câmara"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Acesso ao microfone"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Para apps e serviços"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Para apps e serviços. Se esta definição estiver desativada, os dados do microfone ainda podem ser partilhados quando ligar para um número de emergência."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Veja as apps e os serviços que têm acesso à localização"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Mostrar acesso à área de transferência"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Apresente uma mensagem quando as apps acedem a texto, imagens ou outro conteúdo que copiou"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Mostrar palavras-passe"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Apresente rapidamente os carateres ao escrever"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"As práticas de dados podem variar consoante a versão da app, a utilização, a região e a idade. "<annotation id="link">"Mais informações sobre a partilha de dados"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"As práticas de dados podem variar consoante a versão da app, a utilização, a região e a idade."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Os seus dados de localização"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Altere o acesso desta app nas "<annotation id="link">"definições de privacidade"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Funcionalidade da app"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Estatísticas"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Comunicações do programador"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Publicidade ou marketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Prevenção de fraudes, segurança e conformidade"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalização"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Gestão da conta"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Os programadores destas apps deram informações sobre as respetivas práticas de partilha de dados a uma loja de apps. Podem atualizá-las ao longo do tempo.\n\nAs práticas de partilha de dados podem variar consoante a versão da app, a utilização, a região e a idade."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Saiba mais sobre a partilha de dados"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Os seus dados de localização são agora partilhados com terceiros"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Os seus dados de localização são agora partilhados com terceiros para fins de publicidade ou marketing"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Atualizado no último dia}=1{Atualizado no último dia}many{Atualizado em # de dias}other{Atualizado em # dias}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Nenhuma atualização neste momento"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-pt-v33/strings.xml b/PermissionController/res/values-pt-v33/strings.xml
index 789bd290c..aeda06c8f 100644
--- a/PermissionController/res/values-pt-v33/strings.xml
+++ b/PermissionController/res/values-pt-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Este app terá permissão para enviar notificações e poderá acessar contatos, câmera, microfone, telefone e SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Este app vai poder enviar notificações e acessar contatos, câmera, arquivos, microfone, telefone e SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Apps com esta permissão podem acessar todos os arquivos neste dispositivo."</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Informações sobre sua política de trabalho"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Configurações gerenciadas pelo administrador de TI"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Abrir e mostrar lista"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Fechar lista e ocultar configurações"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Lista. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Lista. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Ações necessárias. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Item da lista. <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">"Mais alertas"</string>
+ <string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Alertas dispensados"</string>
+ <string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Abra para ver mais um alerta}one{Abra para ver mais # alerta}many{Abra para ver mais # de alertas}other{Abra para ver mais # alertas}}"</string>
+ <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 configurações que podem adicionar mais proteção ao seu dispositivo"</string>
+ <string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Configurações rápidas de segurança e privacidade"</string>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Fechar"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Abrir e mostrar opções"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Fechar"</string>
+ <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­çõ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-v34/strings.xml b/PermissionController/res/values-pt-v34/strings.xml
new file mode 100644
index 000000000..6e77e0432
--- /dev/null
+++ b/PermissionController/res/values-pt-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Segurança e privacidade"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Controles"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Conexão Saúde"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Gerenciar o acesso de apps aos dados de saúde"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Acesso ao local"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Para apps e serviços. Se esta configuração estiver desativada, os dados do microfone ainda poderão ser compartilhados quando você ligar para um número de emergência"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Para apps e serviços"</string>
+</resources>
diff --git a/PermissionController/res/values-pt/strings.xml b/PermissionController/res/values-pt/strings.xml
index 6c890d7ee..73de80954 100644
--- a/PermissionController/res/values-pt/strings.xml
+++ b/PermissionController/res/values-pt/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Voltar"</string>
<string name="available" msgid="6007778121920339498">"Disponível"</string>
<string name="blocked" msgid="9195547604866033708">"Bloqueado"</string>
+ <string name="on" msgid="280241003226755921">"Ativado"</string>
+ <string name="off" msgid="1438489226422866263">"Desativar"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Desinstalar ou desativar"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"App não encontrado"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Não permitir"</string>
@@ -30,11 +32,16 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Manter \"Enquanto o app estiver em uso\""</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Manter \"Apenas esta vez\""</string>
<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">"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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Sobreposição de tela detectada"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Para alterar a configuração dessa permissão, primeiro você precisa desativar a sobreposição de tela em \"Config.\" &gt; \"Apps\""</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Abrir configurações"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Linha do tempo de quando apps usaram a permissão de <xliff:g id="PERMGROUP">%1$s</xliff:g> nos últimos sete dias"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Quando esse app usou a permissão <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Saiba mais"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Saiba mais sobre esta permissão: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Controle o acesso do app ao seguinte grupo de permissões: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 dia}one{# dia}many{# dias}other{# dias}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 hora}one{# hora}many{# horas}other{# horas}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1min}one{#min}many{#min}other{#min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1s}one{#s}many{#s}other{#s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# dia}one{# dia}many{# de dias}other{# dias}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# hora}one{# hora}many{# de horas}other{# horas}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}one{# min}many{# de min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{#s}one{#s}many{# de segundos}other{#s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Qualquer permissão"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Qualquer horário"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Últimos 7 dias"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Últimas 24 horas"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Última hora"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Últimos 15 minutos"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Último minuto"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{No último dia}one{No último # dia}many{Nos últimos # de dias}other{Nos últimos # dias}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Na última # hora}one{Na última # hora}many{Nas últimas # de horas}other{Nas últimas # horas}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{No último # minuto}one{No último # minuto}many{Nos últimos # de minutos}other{Nos últimos # minutos}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Nenhum uso de permissões"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Acesso mais recente em qualquer momento"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Acesso mais recente nos últimos sete dias"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Uso da permissão na última hora"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Uso da permissão nos últimos 15 minutos"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Uso da permissão no último minuto"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Permissão não usada nas últimas 24 horas"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Permissão não usada nos últimos sete dias"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Não usado no último # dia}one{Não usado no último # dia}many{Não usado nos últimos # de dias}other{Não usado nos últimos # dias}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Não usado na última # hora}one{Não usado na última # hora}many{Não usado nas últimas # de horas}other{Não usado nas últimas # horas}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Permissões usadas por 1 app}one{Permissões usadas por # app}many{Permissões usadas por # apps}other{Permissões usadas por # apps}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Ver tudo no painel"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrado por: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Permitir acesso apenas a arquivos de mídia"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Permitir o tempo todo"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Permitir durante o uso do app"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Sempre permitir tudo"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Perguntar sempre"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Não permitir"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Local exato"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"As permissões <xliff:g id="PERM_0">%1$s</xliff:g> e <xliff:g id="PERM_1">%2$s</xliff:g> serão removidas."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Permissões que serão removidas: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Gerenciar permissões automaticamente"</string>
- <string name="off" msgid="1438489226422866263">"Desativar"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Permissão <xliff:g id="PERMISSION_NAME">%s</xliff:g> removida"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Permissões <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> e <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> removidas"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> e mais <xliff:g id="NUMBER">%2$s</xliff:g> permissões removidas"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Apps não usados"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Se um app fica sem uso por alguns meses:\n\n• as permissões são removidas para proteger seus dados;\n• as notificações são interrompidas para economizar bateria;\n• os arquivos temporários são removidos para liberar espaço.\n\nPara retomar as permissões e notificações, abra o app."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Se um app ficar sem uso por alguns meses:\n\n• as permissões serão removidas para proteger seus dados;\n• os arquivos temporários serão removidos para liberar espaço.\n\nPara dar as permissões novamente, abra o app."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Abertos pela última vez há mais de <xliff:g id="NUMBER">%s</xliff:g> meses"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Quando um app fica sem uso por um mês:\n\n• As permissões são removidas para proteger seus dados.\n• Os arquivos temporários são removidos para liberar espaço.\n\nSe quiser conceder as permissões novamente, abra o app."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Usado pela última vez há mais de # mês}one{Usado pela última vez há mais de # mês}many{Usado pela última vez há mais de # de meses}other{Usado pela última vez há mais de # meses}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"App aberto pela última vez em <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Aberto pela última vez em <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Se você permitir o gerenciamento de todos os arquivos, o app poderá acessar, modificar e excluir qualquer arquivo no armazenamento comum do dispositivo ou no armazenamento de dispositivos conectados. O app poderá acessar arquivos sem pedir autorização."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Não permitido"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Veja mais apps que têm acesso a todos os arquivos"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 dia}one{# dia}many{# dias}other{# dias}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 hora}one{# hora}many{# horas}other{# horas}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minuto}one{# minuto}many{# minutos}other{# minutos}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 segundo}one{# segundo}many{# segundos}other{# segundos}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# hora}one{# hora}many{# de horas}other{# horas}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minuto}one{# minuto}many{# de minutos}other{# minutos}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# segundo}one{# segundo}many{# de segundos}other{# segundos}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Lembretes de permissões"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 app não usado"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> apps não usados"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Alguns apps não foram usados nos últimos meses. Toque para revisar."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# app não usado}one{# app não usado}many{# apps não usados}other{# apps não usados}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"As permissões e os arquivos temporários foram removidos, e as notificações foram interrompidas. Toque para revisar."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Revisar apps com permissões removidas"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Para apps que você não usa há algum tempo, as permissões e os arquivos temporários foram removidos, e as notificações foram interrompidas."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Revisar apps"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Conferir as permissões recentes"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Enquanto dirigia, você deu ao app <xliff:g id="APP">%1$s</xliff:g> acesso a: <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Enquanto dirigia, você deu ao app <xliff:g id="APP">%1$s</xliff:g> acesso a: <xliff:g id="PERMISSION_1">%2$s</xliff:g> e <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"As permissões foram removidas para proteger sua privacidade"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"O app <xliff:g id="APP_NAME">%s</xliff:g> tem acesso à sua localização em segundo plano"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Este app pode acessar sua localização a qualquer momento. Toque para alterar."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Revisar app com acesso às suas notificações"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"O app <xliff:g id="APP_NAME">%s</xliff:g> pode dispensar, executar ações e acessar o conteúdo das suas notificações"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Este app pode dispensar, executar ações e acessar o conteúdo das suas notificações. Alguns apps exigem esse acesso para funcionar como o esperado."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Remover acesso"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Ver mais opções"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Acesso removido"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Revisar app com acesso total ao dispositivo"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"O <xliff:g id="APP_NAME">%s</xliff:g> pode ver sua tela e realizar ações no seu dispositivo. Os apps de acessibilidade precisam desse tipo de acesso para funcionar como o esperado."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Este app pode ver sua tela e realizar ações no seu dispositivo. Os apps de acessibilidade precisam desse tipo de acesso para funcionar como o esperado, mas confira o app e confirme se você confia nele."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Remover o acesso"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Ver apps com acesso total"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Acesso removido"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Sistema Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Permissões de apps removidas para proteger a privacidade"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"O app <xliff:g id="APP_NAME">%s</xliff:g> não foi usado nos últimos meses. Toque para analisar."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> e mais um app não foram usados nos últimos meses. Toque para analisar."</string>
@@ -350,7 +369,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>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e fazer streaming de outros apps para os dispositivos conectados."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Este serviço compartilha fotos, mídia e notificações do smartphone com outros dispositivos."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"App de notas padrão"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Permissões controladas"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"A localização pode ser acessada"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"O administrador de TI permitiu o acesso do app <xliff:g id="APP_NAME">%s</xliff:g> à sua localização"</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>
<string name="other_permissions_label" msgid="8986184335503271992">"Outras permissões"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Permissões usadas pelo sistema"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Permissões usadas apenas pelos aplicativos do sistema."</string>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Para apps e serviços"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Os dados do microfone ainda poderão ser compartilhados quando você ligar para um número de emergência."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Mudar"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Segurança e privacidade"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Escanear"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Segurança e privacidade"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Verificar dispositivo"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Dispensar"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Dispensar o alerta?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Revise suas configurações de segurança e privacidade a qualquer momento para aumentar a proteção"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Dispensar"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Cancelar"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Configurações"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Status de segurança e privacidade. <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">"Configurações de segurança"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Permissões do sensor"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Controles de privacidade"</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">"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>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Acesso ao microfone"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Permissão removida"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Ver mais usos da câmera"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Ver mais usos do microfone"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Remover permissão da câmera"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Remover permissão do microfone"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Ver o uso recente da câmera"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Ver o uso recente do microfone"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Remover permissão deste app"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Remover permissão deste app"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Gerenciar serviço"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Gerenciar permissões"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Em uso pela chamada telefônica"</string>
@@ -517,8 +552,6 @@
<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>
<string name="recent_app_usage_2_qs" msgid="3591205954235694403">"Usada recentemente 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>
- <string name="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Segurança e privacidade"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Checar status"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Confirmar"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Voltar"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"O acesso a outros arquivos também será permitido"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Este app não tem suporte à versão mais recente do Android. Se ele não puder acessar arquivos de áudio e música, também não vai poder acessar fotos e vídeos."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Este app não tem suporte à versão mais recente do Android. Se ele puder acessar fotos e vídeos, também vai poder acessar arquivos de áudio e música."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Este app não tem suporte à versão mais recente do Android. Se ele não puder acessar arquivos de áudio e música, também não vai poder acessar fotos e vídeos."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Revisar apps com acesso à localização em segundo plano"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"O <xliff:g id="APP_NAME">%s</xliff:g> sempre pode acessar seu local, mesmo quando está fechado."</string>
+ <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">"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>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Para apps e serviços"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Para apps e serviços. Se esta configuração estiver desativada, os dados do microfone ainda poderão ser compartilhados quando você ligar para um número de emergência."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Veja apps e serviços que têm acesso à localização"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Mostrar acesso à área de transferência"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Mostrar uma mensagem quando os apps acessarem textos, imagens ou outros conteúdos copiados"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Mostrar senhas"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Mostrar os caracteres rapidamente enquanto você digita"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"As práticas relacionadas a dados podem variar de acordo com a versão do app e com a idade, uso e região do usuário. "<annotation id="link">"Mais informações sobre o compartilhamento de dados"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"As práticas relacionadas a dados podem variar de acordo com a versão do app e com a idade, uso e região do usuário."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Seus dados de local"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Mude o acesso do app nas "<annotation id="link">"configurações de privacidade"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Funcionalidade do app"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Análise"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Mensagens do desenvolvedor"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Publicidade ou marketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Segurança, conformidade e prevenção de fraudes"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalização"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Gerenciamento da conta"</string>
+ <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="data_sharing_updates_title" msgid="7996933386875213859">"Atualizações no compartilhamento de 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>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Seus dados de local agora são compartilhados com terceiros"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Seus dados de local agora são compartilhados com terceiros para fins de publicidade ou marketing"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Atualizado nas últimas 24 horas}=1{Atualizado nas últimas 24 horas}one{Atualizado há # dia}many{Atualizado há # de dias}other{Atualizado há # dias}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Não há atualizações no momento"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-ro-v33/strings.xml b/PermissionController/res/values-ro-v33/strings.xml
index 05e9984a3..a32a32db5 100644
--- a/PermissionController/res/values-ro-v33/strings.xml
+++ b/PermissionController/res/values-ro-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Aplicația va putea să-ți trimită notificări și va avea acces la Camera foto, Agendă, Microfon, Telefon și SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Aplicația va putea să-ți trimită notificări și va avea acces la Camera foto, Agendă, Fișiere, Microfon, Telefon și SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Aplicațiile cu această permisiune pot accesa toate fișierele de pe dispozitiv"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Informații despre politica de serviciu"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Setări gestionate de administratorul IT"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Extinde și afișează lista"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Restrânge lista și ascunde setările"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Listă. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Listă. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Acțiuni necesare. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Articol din listă. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Închide"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Extinde și afișează opțiunile"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Restrânge"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Comutator. <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">"Comută"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Deschide"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Verifică setările"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Setări"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Informații"</string>
</resources>
diff --git a/PermissionController/res/values-ro-v34/strings.xml b/PermissionController/res/values-ro-v34/strings.xml
new file mode 100644
index 000000000..e57e8c91a
--- /dev/null
+++ b/PermissionController/res/values-ro-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Securitate și confidențialitate"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Comenzi"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Gestionează accesul aplicației la datele despre sănătate"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Accesul la locație"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Pentru aplicații și servicii. Chiar dacă setarea este dezactivată, datele de la microfon pot fi trimise când apelezi un număr de urgență."</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Pentru aplicații și servicii"</string>
+</resources>
diff --git a/PermissionController/res/values-ro/strings.xml b/PermissionController/res/values-ro/strings.xml
index 6cee9e94f..defbf3177 100644
--- a/PermissionController/res/values-ro/strings.xml
+++ b/PermissionController/res/values-ro/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Înapoi"</string>
<string name="available" msgid="6007778121920339498">"Disponibil"</string>
<string name="blocked" msgid="9195547604866033708">"Blocat"</string>
+ <string name="on" msgid="280241003226755921">"Activat"</string>
+ <string name="off" msgid="1438489226422866263">"Dezactivat"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Dezinstalează sau dezactivează"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Aplicația nu a fost găsită"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Nu permite"</string>
@@ -30,11 +32,16 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Păstrează opțiunea „Când aplicația este folosită”"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Păstrează „Doar de data aceasta”"</string>
<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_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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"S-a detectat suprapunerea pe ecran"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Ca să schimbi această setare pentru permisiuni, mai întâi trebuie să dezactivezi suprapunerea pe ecran din Setări &gt; Aplicații"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Deschide setările"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Momentele din ultimele șapte zile în care aplicațiile au folosit grupul de permisiuni <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Când această aplicație a folosit permisiunea <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Află mai multe"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Află mai multe despre <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Controlează accesul aplicației la <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{O zi}few{# zile}other{# de zile}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{O oră}few{# ore}other{# de ore}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min.}few{# min.}other{# min.}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{O sec.}few{# sec.}other{# sec.}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# zi}few{# zile}other{# de zile}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# oră}few{# ore}other{# de ore}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min.}few{# min.}other{# min.}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}few{# s}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Orice permisiune"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Oricând"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Ultimele 7 zile"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Ultimele 24 de ore"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Ultima oră"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Ultimele 15 minute"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Ultimul minut"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Ultima zi}few{Ultimele # zile}other{Ultimele # de zile}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Ultima oră}few{Ultimele # ore}other{Ultimele # de ore}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Ultimul minut}few{Ultimele # minute}other{Ultimele # de minute}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Nicio permisiune folosită"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Cel mai recent acces oricând"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Cea mai recentă accesare din ultimele șapte zile"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Folosirea permisiunii în ultima oră"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Folosirea permisiunii în ultimele 15 minute"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Folosirea permisiunii în ultimul minut"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Nu s-a(u) folosit în ultimele 24 de ore"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Nu a fost folosită în ultimele șapte zile"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Permisiunea nu a fost folosită în ultima zi}few{Permisiunea nu a fost folosită în ultimele # zile}other{Permisiunea nu a fost folosită în ultimele # de zile}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Permisiunea nu a fost folosită în ultima oră}few{Permisiunea nu a fost folosită în ultimele # ore}other{Permisiunea nu a fost folosită în ultimele # de ore}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Folosit(ă) de o aplicație}few{Folosit(ă) de # aplicații}other{Folosit(ă) de # de aplicații}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Vezi totul în Tabloul de bord"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrat după: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Permite accesul numai la fișierele media"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Permite întotdeauna"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Permite numai când folosești aplicația"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Permite-le întotdeauna pe toate"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Întreabă de fiecare dată"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Nu permite"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Locația exactă"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Permisiunile <xliff:g id="PERM_0">%1$s</xliff:g> și <xliff:g id="PERM_1">%2$s</xliff:g> vor fi eliminate."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Permisiunile care vor fi eliminate: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Gestionează automat permisiunile"</string>
- <string name="off" msgid="1438489226422866263">"Dezactivat"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Permisiunea <xliff:g id="PERMISSION_NAME">%s</xliff:g> a fost eliminată"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Permisiunile <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> și <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> au fost eliminate"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Permisiunea <xliff:g id="PERMISSION_NAME">%1$s</xliff:g> și încă <xliff:g id="NUMBER">%2$s</xliff:g> permisiuni au fost eliminate"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Aplicații nefolosite"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Dacă o aplicație nu este folosită timp de câteva luni:\n\n• permisiunile sunt eliminate pentru a-ți proteja datele;\n• notificările sunt dezactivate pentru a economisi baterie;\n• fișierele temporare sunt eliminate pentru a elibera spațiu.\n\nPentru a acorda permisiuni și a permite notificări, deschide aplicația."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Dacă o aplicație nu e folosită timp de câteva luni:\n\n• permisiunile sunt eliminate pentru a-ți proteja datele;\n• fișierele temporare sunt eliminate pentru a elibera spațiu.\n\nPentru a acorda permisiuni din nou, deschide aplicația."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Data ultimei deschideri: cu peste <xliff:g id="NUMBER">%s</xliff:g> luni în urmă"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Dacă o aplicație nu este folosită timp o lună:\n\n• permisiunile sunt eliminate pentru a-ți proteja datele;\n• fișierele temporare sunt eliminate pentru a elibera spațiu.\n\nPentru a acorda permisiuni din nou, deschide aplicația."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Data ultimei deschideri: cu peste # lună în urmă}few{Data ultimei deschideri: cu peste # luni în urmă}other{Data ultimei deschideri: cu peste # de luni în urmă}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Aplicația a fost deschisă ultima dată pe <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Data ultimei deschideri: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Dacă permiți gestionarea tuturor fișierelor, aplicația poate să acceseze, să modifice și să șteargă orice fișiere din spațiul de stocare comun de pe acest dispozitiv sau de pe dispozitivele de stocare conectate. Aplicația poate accesa fișierele fără a cere permisiunea."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Nepermise"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Vezi mai multe aplicații care pot accesa toate fișierele"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{O zi}few{# zile}other{# de zile}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{O oră}few{# ore}other{# de ore}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{Un minut}few{# minute}other{# de minute}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{O secundă}few{# secunde}other{# de secunde}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# oră}few{# ore}other{# de ore}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minut}few{# minute}other{# de minute}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# secundă}few{# secunde}other{# de secunde}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Mementouri de permisiune"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"O aplicație nefolosită"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> aplicații nefolosite"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Unele aplicații nu au fost folosite de câteva luni. Atinge pentru a examina."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# aplicație nefolosită}few{# aplicații nefolosite}other{# de aplicații nefolosite}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Permisiunile și fișierele temporare au fost eliminate și notificările au fost dezactivate. Atinge pentru a examina."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Verifică aplicațiile cu permisiuni eliminate"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Pentru aplicațiile pe care nu le-ai folosit de ceva vreme, permisiunile și fișierele temporare au fost eliminate și notificările au fost dezactivate."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Verifică aplicațiile"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Verifică permisiunile recente"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"În timpul condusului ai permis accesul <xliff:g id="APP">%1$s</xliff:g> la <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"În timpul condusului ai permis accesul <xliff:g id="APP">%1$s</xliff:g> la <xliff:g id="PERMISSION_1">%2$s</xliff:g> și la <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Permisiunile au fost eliminate pentru a-ți proteja confidențialitatea"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> ți-a obținut locația în fundal"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Această aplicație îți poate accesa întotdeauna locația. Atinge ca să modifici."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Verifică aplicația cu acces la notificări"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> poate să închidă, să facă acțiuni în legătură cu conținutul notificărilor și să-l acceseze"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Aplicația poate să închidă, să facă acțiuni în legătură cu conținutul notificărilor și să-l acceseze. Unele aplicații au nevoie de acest tip de acces pentru a funcționa corect."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Elimină accesul"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Afișează mai multe opțiuni"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Acces eliminat"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Verifică aplicația cu acces complet la dispozitiv"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> poate să vadă ecranul și să facă acțiuni pe dispozitiv. Aplicațiile de accesibilitate au nevoie de acest tip de acces pentru a funcționa corect."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Aplicația poate să vadă ecranul și să facă acțiuni pe dispozitiv. Aplicațiile de accesibilitate au nevoie de acest tip de acces pentru a funcționa corect, dar verifică aplicația și asigură-te că e de încredere."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Elimină accesul"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Vezi aplicațiile cu acces complet"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Acces eliminat"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Sistemul Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Permisiunile pentru aplicație s-au eliminat pentru confidențialitate"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Aplicația <xliff:g id="APP_NAME">%s</xliff:g> nu a fost folosită de câteva luni. Atinge pentru a examina."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> și încă o aplicație nu au fost folosite de câteva luni. Atinge pentru a examina."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> va putea să interacționeze cu notificările și să-ți acceseze permisiunile pentru Telefon, SMS-uri, Agendă și Calendar."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> va putea să interacționeze cu notificările și să redea în stream conținutul din aplicații pe dispozitivul conectat."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Acest serviciu trimite fotografiile, conținutul media și notificările de pe telefon pe alte dispozitive."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Aplicația prestabilită pentru note"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Permisiuni controlate"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Locația poate fi accesată"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Administratorul IT permite aplicației <xliff:g id="APP_NAME">%s</xliff:g> să-ți acceseze locația"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Pentru aplicații și servicii"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Datele de la microfon pot fi totuși trimise când suni la un număr de urgență."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Modifică"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Securitate, confidențialitate"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Caută"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Securitate și confidențialitate"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Scanează dispozitivul"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Închide"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Închizi alerta?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Examinează oricând setările de securitate și confidențialitate, ca să adaugi mai multă protecție"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Închide"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Anulează"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Setări"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Starea de securitate și confidențialitate. <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">"Setări de securitate"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Permisiuni pentru senzori"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Opțiuni de confidențialitate"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Permisiuni"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Securitate și confidențialitate"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Verifică starea"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Opțiuni de confidențialitate"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Mai multe setări"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Acces la cameră"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Acces la microfon"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Permisiunea a fost eliminată"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Vezi alte aplicații care folosesc camera"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Vezi alte aplicații care folosesc microfonul"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Elimină permisiunea pentru cameră"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Elimină permisiunea pentru microfon"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Vezi date despre folosirea recentă a camerei"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Vezi date despre folosirea recentă a microfonului"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Elimină permisiunea pentru această aplicație"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Elimină permisiunea pentru această aplicație"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Gestionează serviciul"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Gestionează permisiunile"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Este folosit de un apel telefonic"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Folosit recent de <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">"Este folosit de <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">"Folosit recent de <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Securitate, confidențialitate"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Verifică starea"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Confirm"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Înapoi"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Va fi permis și accesul la alte fișiere"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Aplicația nu acceptă cea mai recentă versiune Android. Dacă aplicația nu poate accesa muzică și fișiere audio, nu va putea să acceseze fotografii și videoclipuri."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Aplicația nu acceptă cea mai recentă versiune Android. Dacă aplicația poate accesa fotografii și videoclipuri, va putea să acceseze și muzică și fișiere audio."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Aplicația nu acceptă cea mai recentă versiune Android. Dacă aplicația nu poate accesa muzică și fișiere audio, nu va putea să acceseze fotografii și videoclipuri."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Verifică aplicația cu acces la locație în fundal"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> îți poate accesa în permanență locația, chiar și când aplicația e închisă"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Verifică aplicația cu acces la locație în fundal"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Aplicația îți poate accesa în permanență locația, chiar și când este închisă.\n\nUnele aplicații pentru siguranță și urgențe necesită acces la locație în fundal pentru a funcționa corect."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Permisiunea de acces a fost schimbată"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Vezi folosirea recentă a locației"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Opțiuni de confidențialitate"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Acces la cameră"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Acces la microfon"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Pentru aplicații și servicii"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Pentru aplicații și servicii. Chiar dacă setarea e dezactivată, datele de la microfon pot fi trimise când suni la un număr de urgență."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Vezi aplicațiile și serviciile care au acces la locație"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Afișează accesările clipboardului"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Afișează un mesaj când aplicațiile accesează text, imagini sau alte tipuri de conținut pe care le-ai copiat"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Afișează parolele"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Caracterele se afișează pentru scurt timp, pe măsură ce tastezi"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Practicile privind datele pot varia în funcție de versiunea aplicației, de modul de utilizare a acesteia, de regiune și de vârsta ta. "<annotation id="link">"Mai multe despre permiterea accesului la date"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Practicile privind datele pot varia în funcție de versiunea aplicației, de modul de utilizare a acesteia, de regiune și de vârsta ta."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Datele privind locația ta"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Schimbă accesul acestei aplicații în "<annotation id="link">"setările de confidențialitate"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Funcționalitatea aplicației"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Date statistice"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Comunicări ale dezvoltatorilor"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Publicitate sau marketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Prevenirea fraudei, securitate și conformitate"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalizare"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Gestionarea contului"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Dezvoltatorii acestor aplicații au oferit unui magazin de aplicații informații despre practicile lor de permitere a accesului la date. Acestea se pot actualiza în timp.\n\nPracticile de permitere a accesului la date pot varia în funcție de versiunea aplicației, de modul de utilizare, de regiune și de vârstă."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Află despre permiterea accesului la date"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Terții au acum acces la datele tale privind locațiile"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Terții au acum acces la datele tale privind locațiile în scopuri de publicitate sau de marketing"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Actualizări în ultima zi}=1{Actualizări în ultima zi}few{Actualizări în ultimele # zile}other{Actualizări în ultimele # de zile}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Nicio actualizare momentan"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-ru-v33/strings.xml b/PermissionController/res/values-ru-v33/strings.xml
index 77d42bee7..a13e4e8d5 100644
--- a/PermissionController/res/values-ru-v33/strings.xml
+++ b/PermissionController/res/values-ru-v33/strings.xml
@@ -19,4 +19,28 @@
<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="work_policy_title" msgid="832967780713677409">"Сведения о правилах организации"</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>
+ <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{Разверните, чтобы увидеть ещё # оповещение}few{Разверните, чтобы увидеть ещё # оповещения}many{Разверните, чтобы увидеть ещё # оповещений}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Закрыть"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Развернуть и показать параметры"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Свернуть"</string>
+ <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_gear_label" msgid="5175877094379694098">"Настройки"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Информация"</string>
</resources>
diff --git a/PermissionController/res/values-ru-v34/strings.xml b/PermissionController/res/values-ru-v34/strings.xml
new file mode 100644
index 000000000..64a927b69
--- /dev/null
+++ b/PermissionController/res/values-ru-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-ru/strings.xml b/PermissionController/res/values-ru/strings.xml
index c224b514f..fa9bd96af 100644
--- a/PermissionController/res/values-ru/strings.xml
+++ b/PermissionController/res/values-ru/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"Постоянный полный доступ"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Включен экранный оверлей"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Чтобы предоставить или отозвать разрешение, сначала отключите экранный оверлей. Для этого откройте \"Настройки\" и выберите \"Приложения\"."</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Открыть настройки"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 день}one{# день}few{# дня}many{# дней}other{# дня}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 час}one{# час}few{# часа}many{# часов}other{# часа}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 минута}one{# минута}few{# минуты}many{# минут}other{# минуты}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 секунда}one{# секунда}few{# секунды}many{# секунд}other{# секунды}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# день}one{# день}few{# дня}many{# дней}other{# дня}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# час}one{# час}few{# часа}many{# часов}other{# часа}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# минута}one{# минута}few{# минуты}many{# минут}other{# минуты}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# секунда}one{# секунда}few{# секунды}many{# секунд}other{# секунды}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Все разрешения"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Все время"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Последние 7 дней"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Последние 24 часа"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Последний час"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Последние 15 минут"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Последняя минута"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{За последний # день}one{За последний # день}few{За последние # дня}many{За последние # дней}other{За последние # дня}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{За последний # час}one{За последний # час}few{За последние # часа}many{За последние # часов}other{За последние # часа}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{За последнюю # минуту}one{За последнюю # минуту}few{За последние # минуты}many{За последние # минут}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>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Разрешения, использованные за последний час"</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">"Разрешения, использованные за последнюю минуту"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Не использовалось последние 24 часа"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Не использовалось последние 7 дней"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{С момента последнего использования прошел # день}one{С момента последнего использования прошел # день}few{С момента последнего использования прошло # дня}many{С момента последнего использования прошло # дней}other{С момента последнего использования прошло # дня}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{С момента последнего использования прошел # час}one{С момента последнего использования прошел # час}few{С момента последнего использования прошло # часа}many{С момента последнего использования прошло # часов}other{С момента последнего использования прошло # часа}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Использует 1 приложение}one{Использует # приложение}few{Используют # приложения}many{Используют # приложений}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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"Постоянный полный доступ"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Спрашивать каждый раз"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Запретить"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Точное местоположение"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Разрешения \"<xliff:g id="PERM_0">%1$s</xliff:g>\" и \"<xliff:g id="PERM_1">%2$s</xliff:g>\" будут отозваны"</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Разрешения, которые будут отозваны: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Автоматическое управление разрешениями"</string>
- <string name="off" msgid="1438489226422866263">"Отключить"</string>
<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_tv_summary" msgid="3685907153054355671">"Если вы не пользовались приложением несколько месяцев:\n\n• разрешения будут отключены для защиты ваших данных;\n• временные файлы будут удалены, чтобы освободить место.\n\nЧтобы заново предоставить разрешения, откройте приложение."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Использовались более <xliff:g id="NUMBER">%s</xliff:g> мес. назад"</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{Использовались более # месяца назад}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>
<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,17 +254,20 @@
<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="3447767892295843282">"{count,plural, =1{1 час}one{# час}few{# часа}many{# часов}other{# часа}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 минута}one{# минута}few{# минуты}many{# минут}other{# минуты}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 секунда}one{# секунда}few{# секунды}many{# секунд}other{# секунды}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# час}one{# час}few{# часа}many{# часов}other{# часа}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# минута}one{# минута}few{# минуты}many{# минут}other{# минуты}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# секунда}one{# секунда}few{# секунды}many{# секунд}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_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>
+ <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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Система Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Разрешения для приложения отозваны в целях защиты данных"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Вы уже несколько месяцев не пользовались приложением \"<xliff:g id="APP_NAME">%s</xliff:g>\". Нажмите, чтобы посмотреть подробности."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"Вы уже несколько месяцев не пользовались некоторыми приложениями: \"<xliff:g id="APP_NAME">%s</xliff:g>\" и ещё одним. Нажмите, чтобы посмотреть подробности."</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"заметки"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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">"Разрешить <xliff:g id="APP_NAME">%1$s</xliff:g> отправлять уведомления?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Контролируемые разрешения"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Приложению доступны ваши геоданные"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Администратор разрешил приложению \"<xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"Защита и конфиденциальность"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Сканировать"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"Доступ к датчикам"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Настройки конфиденциальности"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"Разрешение отозвано"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Ещё данные по использованию камеры"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Ещё данные по использованию микрофона"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Закрыть доступ к камере"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Закрыть доступ к микрофону"</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="manage_service_qs" msgid="7862555549364153805">"Настроить сервис"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Управление разрешениями"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Используется во время телефонного звонка"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Безопасность и конфиденциальность"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Проверьте статус."</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Связь с разработчиком"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Обновлено за последний день}=1{Обновлено за последний день}one{Обновлено за последний # день}few{Обновлено за последние # дня}many{Обновлено за последние # дней}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>
</resources>
diff --git a/PermissionController/res/values-si-v33/strings.xml b/PermissionController/res/values-si-v33/strings.xml
index f73c751e9..b3d1ab958 100644
--- a/PermissionController/res/values-si-v33/strings.xml
+++ b/PermissionController/res/values-si-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"මෙම යෙදුමට ඔබට දැනුම්දීම් එවීමට ඉඩ දෙනු ඇති අතර, ඔබගේ කැමරාව, සම්බන්ධතා, මයික්‍රෆෝනය, දුරකථනය සහ SMS වෙත ප්‍රවේශය ලබා දෙනු ඇත"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"මෙම යෙදුමට ඔබට දැනුම්දීම් එවීමට ඉඩ දෙනු ඇති අතර, ඔබගේ කැමරාව, සම්බන්ධතා, Files, මයික්‍රෆෝනය, දුරකථනය සහ SMS වෙත ප්‍රවේශය ලබා දෙනු ඇත"</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>
+ <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>
+ <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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"වසන්න"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"පුළුල් කර විකල්ප පෙන්වන්න"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"හකුළන්න"</string>
+ <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_gear_label" msgid="5175877094379694098">"සැකසීම්"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"තොරතුරු"</string>
</resources>
diff --git a/PermissionController/res/values-si-v34/strings.xml b/PermissionController/res/values-si-v34/strings.xml
new file mode 100644
index 000000000..26121467a
--- /dev/null
+++ b/PermissionController/res/values-si-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-si/strings.xml b/PermissionController/res/values-si/strings.xml
index 006a20f72..1899c6e70 100644
--- a/PermissionController/res/values-si/strings.xml
+++ b/PermissionController/res/values-si/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"සැම විටම සියල්ලට ඉඩ දෙන්න"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"තිර උඩැතිරියක් අනාවරණය කරන ලදි"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"මෙම අවසර සැකසීම වෙනස් කිරීම සඳහා, ඔබට මුලින්ම සැකසීම් &gt; යෙදුම් වෙතින් තිර උඩැතිරිය අක්‍රිය කර යුතුයි"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"සැකසීම් විවෘත කරන්න"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{දින 1ක්}one{දින #ක්}other{දින #ක්}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{පැය 1ක්}one{පැය #ක්}other{පැය #ක්}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{මිනි 1ක්}one{මිනි #ක්}other{මිනි #ක්}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{තත් 1ක්}one{තත් #ක්}other{තත් #ක්}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# දිනක්}one{දින #ක්}other{දින #ක්}}"</string>
+ <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_time" msgid="3802087027301631827">"ඕනෑම වේලාවක"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"පසුගිය දින 7"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"පසුගිය පැය 24"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"පසුගිය පැය 1"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"පසුගිය මිනිත්තු 15"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"පසුගිය විනාඩි 1"</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>
+ <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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"පසුගිය පැය 24 තුළ භාවිත කර නැත"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"පසුගිය දින 7 තුළ භාවිත කර නැත"</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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"සැම විටම සියල්ලට ඉඩ දෙන්න"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"සෑම විටම ඉල්ලන්න"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"ඉඩ නොදෙන්න"</string>
<string name="precise_image_description" msgid="6349638632303619872">"ඉතා නිවැරදි ස්ථානය"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"අවසර <xliff:g id="PERM_0">%1$s</xliff:g> සහ <xliff:g id="PERM_1">%2$s</xliff:g> ඉවත් කරනු ඇත."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"ඉවත් කරනු ලබන අවසර: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"ස්වයංක්‍රියව අවසර කළමනාකරණය කරන්න"</string>
- <string name="off" msgid="1438489226422866263">"ක්‍රියාවිරහිතයි"</string>
<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_tv_summary" msgid="3685907153054355671">"යෙදුමක් මාස කිහිපයක් භාවිත නොකළහොත්:\n\n• ඔබගේ දත්ත ආරක්ෂා කිරීමට අවසර ඉවත් කෙරේ\n• ඉඩ නිදහස් කිරීමට තාවකාලික ගොනු ඉවත් කෙරේ\n\nනැවත අවසරවලට ඉඩ දීමට, යෙදුම විවෘත කරන්න."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"අවසන් වරට විවෘත කළේ මාස <xliff:g id="NUMBER">%s</xliff:g>කට පෙරය"</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>
<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,9 +254,9 @@
<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{දින #ක්}other{දින #ක්}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{පැය 1ක්}one{පැය #ක්}other{පැය #ක්}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{මිනිත්තු 1ක්}one{මිනිත්තු #ක්}other{මිනිත්තු #ක්}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{තත්පර 1ක්}one{තත්පර #ක්}other{තත්පර #ක්}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{පැය #ක්}one{පැය #ක්}other{පැය #ක්}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{මිනිත්තු #ක්}one{මිනිත්තු #ක්}other{මිනිත්තු #ක්}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{තත්පර #}one{තත්පර #}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>
@@ -262,6 +265,9 @@
<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>
+ <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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android පද්ධතිය"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"රහස්‍යතාව ආරක්ෂා කිරීමට යෙදුම් අවසර ඉවත් කර ඇත"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> මාස කීපයක් තුළ භාවිත කර නැත. සමාලෝචනය කිරීමට තට්ටු කරන්න."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> සහ තවත් යෙදුම් 1ක් මාස කීපයක් තුළ භාවිත කර නැත. සමාලෝචනය කිරීමට තට්ටු කරන්න."</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"සටහන්"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"පාලිත අවසර"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"ස්ථානය ප්‍රවේශ විය හැකිය"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"ඔබේ IT පරිපාලක <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"ආරක්ෂාව සහ පෞද්ගලිකත්වය"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"ස්කෑන් කරන්න"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"සංවේදක අවසර"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"පෞද්ගලිකත්ව පාලන"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"අවසරය ඉවත් කරන ලදි"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"තවත් කැමරා භාවිතය බලන්න"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"තවත් මයික්‍රෆෝන භාවිතය බලන්න"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"කැමරා අවසරය ඉවත් කරන්න"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"මයික්‍රෆෝන අවසරය ඉවත් කරන්න"</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="manage_service_qs" msgid="7862555549364153805">"සේවය කළමනාකරණය කරන්න"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"අවසර කළමනාකරණය කරන්න"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"දුරකථන ඇමතුම මගින් භාවිත කරමින් ඇත"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"ආරක්ෂාව සහ පෞද්ගලිකත්වය"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"තත්ත්වය පරික්ෂා කරන්න"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"සංවර්ධක සන්නිවේදන"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{පසුගිය දින තුළ යාවත්කාලීන කරන ලදි}=1{පසුගිය දින තුළ යාවත්කාලීන කරන ලදි}one{දින #ක් තුළ යාවත්කාලීන කරන ලදි}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>
</resources>
diff --git a/PermissionController/res/values-sk-v33/strings.xml b/PermissionController/res/values-sk-v33/strings.xml
index 50bf2e474..f36fd1089 100644
--- a/PermissionController/res/values-sk-v33/strings.xml
+++ b/PermissionController/res/values-sk-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Táto aplikácia bude mať povolené odosielať vám upozornenia a bude jej udelený prístup k vašej kamere, kontaktom, mikrofónu, telefónu aj správam SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Táto aplikácia bude mať povolené odosielať vám upozornenia a bude jej udelený prístup k vašej kamere, kontaktom, súborom, mikrofónu, telefónu aj správam SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Aplikácie s týmto povolením majú prístup k všetkým súborom v tomto zariadení"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Informácie o pracovných pravidlách"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Nastavenia spravované vaším správcom IT"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Rozbaliť a zobraziť zoznam"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Zbaliť zoznam a skryť nastavenia"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Zoznam. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Zoznam. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Vyžaduje sa akcia. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>."</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Položka zoznamu. <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">"Ďalšie upozornenia"</string>
+ <string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Odmietnuté upozornenia"</string>
+ <string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Po rozbalení sa zobrazí jedno ďalšie upozornenie}few{Po rozbalení sa zobrazia # ďalšie upozornenia}many{Expand and see # more alerts}other{Po rozbalení sa zobrazí # ďalších upozornení}}"</string>
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Upozornenie. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
+ <string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Akcia je dokončená"</string>
+ <string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Skontrolujte nastavenia, ktoré môžu pridať ochranu do vášho zariadenia"</string>
+ <string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Rýchle nastavenia zabezpečenia a ochrany súkromia"</string>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Zavrieť"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Rozbaliť a zobraziť možnosti"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Zbaliť"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Prepnite. <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">"Prepnúť"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Otvoriť"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Skontrolovať nastavenia"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Nastavenia"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Informácie"</string>
</resources>
diff --git a/PermissionController/res/values-sk-v34/strings.xml b/PermissionController/res/values-sk-v34/strings.xml
new file mode 100644
index 000000000..5f84f5059
--- /dev/null
+++ b/PermissionController/res/values-sk-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Zabezpečenie a ochrana súkromia"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Ovládanie"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Dáta o zdraví"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Správa prístupu aplikácie k údajom o zdraví"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Prístup k polohe"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"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="6846532794702613851">"Pre aplikácie a služby"</string>
+</resources>
diff --git a/PermissionController/res/values-sk/strings.xml b/PermissionController/res/values-sk/strings.xml
index 57e3d4ca9..ae8ea524c 100644
--- a/PermissionController/res/values-sk/strings.xml
+++ b/PermissionController/res/values-sk/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Späť"</string>
<string name="available" msgid="6007778121920339498">"Dostupné"</string>
<string name="blocked" msgid="9195547604866033708">"Blokované"</string>
+ <string name="on" msgid="280241003226755921">"Zapnuté"</string>
+ <string name="off" msgid="1438489226422866263">"Vypnuté"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Odinštalovať alebo deaktivovať"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Aplikácia sa nenašla"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Nepovoliť"</string>
@@ -30,10 +32,15 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Ponechať Počas používania aplikácie"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Ponechať možnosť Iba tentokrát"</string>
<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_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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Bolo zistené prekrytie obrazovky"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Ak chcete zmeniť nastavenie tohto povolenia, musíte najprv v časti Nastavenia &gt; Aplikácie vypnúť prekrytie obrazovky"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Otvoriť nastavenia"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"<xliff:g id="PERMGROUP">%1$s</xliff:g> – časová os používania aplikáciami za posledných 7 dní"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Keď táto aplikácia používala povolenie <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Ďalšie informácie"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Ďalšie informácie o skupine povolení <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Ovládanie prístupu aplikácií k skupine <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 deň}few{# dni}many{# dňa}other{# dní}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 hodina}few{# hodiny}many{# hodiny}other{# hodín}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}few{# min}many{# min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 s}few{# s}many{# s}other{# s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# deň}few{# dni}many{# dňa}other{# dní}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# hodina}few{# hodiny}many{# hodiny}other{# hodín}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}few{# min}many{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}few{# s}many{# s}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Všetky povolenia"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Kedykoľvek"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Posledných 7 dní"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Posledných 24 hodín"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Posledná 1 hodina"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Posledných 15 minút"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Posledná 1 minúta"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Posledný # deň}few{Posledné # dni}many{Posledných # dňa}other{Posledných # dní}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Posledná # hodina}few{Posledné # hodiny}many{Posledných # hodiny}other{Posledných # hodín}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Posledná # minúta}few{Posledné # minúty}many{Posledných # minúty}other{Posledných # minút}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Žiadne využitie povolení"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Posledný prístup kedykoľvek"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Posledný prístup za posledných sedem dní"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Používanie povolení za poslednú hodinu"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Používanie povolení za posledných 15 minút"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Používanie povolení za poslednú minútu"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Nepoužité za posledných 24 hodín"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Nepoužité za posledných 7 dní"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Nepoužité za posledný # deň}few{Nepoužité za posledné # dni}many{Nepoužité za posledných # dňa}other{Nepoužité za posledných # dní}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Nepoužité za poslednú # hodinu}few{Nepoužité za posledné # hodiny}many{Nepoužité za posledných # hodiny}other{Nepoužité za posledných # hodín}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Používa 1 aplikácia}few{Používajú # aplikácie}many{Used by # apps}other{Používa # aplikácií}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Zobraziť všetko v hlavnom paneli"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrované podľa: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Povoliť prístup iba k médiám"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Povoliť vždy"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Povoliť iba pri používaní aplikácie"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Vždy povoliť všetko"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Vždy sa opýtať"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Nepovoliť"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Presná poloha"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Povolenia <xliff:g id="PERM_0">%1$s</xliff:g> a <xliff:g id="PERM_1">%2$s</xliff:g> budú odstránené."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Povolenia, ktoré budú odstránené: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Automatické spravovanie povolení"</string>
- <string name="off" msgid="1438489226422866263">"Vypnuté"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Bolo odstránené povolenie <xliff:g id="PERMISSION_NAME">%s</xliff:g>"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Boli odstránené povolenia <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> a <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g>"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Bolo odstránené povolenie <xliff:g id="PERMISSION_NAME">%1$s</xliff:g> a ďalšie (<xliff:g id="NUMBER">%2$s</xliff:g>)"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Nepoužívané aplikácie"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Ak aplikácia nebola používaná niekoľko mesiacov:\n\n• povolenia budú z dôvodu ochrany vašich údajov odstránené,\n• upozornenia sa zastavia, aby sa šetrila batéria,\n• dočasné súbory budú odstránené, aby sa uvoľnilo miesto.\n\nAk budete chcieť povolenia a upozornenia znova aktivovať, otvorte aplikáciu."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Ak aplikácia nebola používaná niekoľko mesiacov:\n\n• povolenia budú z dôvodu ochrany vašich údajov odstránené;\n• dočasné súbory budú odstránené, aby sa uvoľnilo miesto.\n\nAk budete chcieť povolenia znova udeliť, otvorte aplikáciu."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Naposledy otvorené pred viac ako <xliff:g id="NUMBER">%s</xliff:g> mesiacmi"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Ak aplikácia nebola použitá mesiac:\n\n• povolenia budú z dôvodu ochrany vašich údajov odstránené;\n• dočasné súbory budú odstránené, aby sa uvoľnilo miesto.\n\nAk budete chcieť povolenia znova udeliť, otvorte aplikáciu."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Naposledy otvorené pred viac než # mesiacom}few{Naposledy otvorené pred viac než # mesiacmi}many{Naposledy otvorené pred viac než # mesiaca}other{Naposledy otvorené pred viac než # mesiacmi}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Aplikácia bola naposledy otvorená <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Naposledy otvorená <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Ak povolíte správu všetkých súborov, táto aplikácia môže používať, upravovať a odstraňovať všetky súbory v spoločnom úložisku tohto zariadenia alebo pripojených ukladacích zariadeniach. Súbory môže používať bez toho, aby sa vás na to spýtala."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Nepovolené"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Zobraziť ďalšie aplikácie s prístupom k všetkým súborom"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 deň}few{# dni}many{# dňa}other{# dní}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 hodina}few{# hodiny}many{# hodiny}other{# hodín}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minúta}few{# minúty}many{# minúty}other{# minút}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 sekunda}few{# sekundy}many{# sekundy}other{# sekúnd}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# hodina}few{# hodiny}many{# hodiny}other{# hodín}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minúta}few{# minúty}many{# minúty}other{# minút}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# sekunda}few{# sekundy}many{# sekundy}other{# sekúnd}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Pripomenutia povolení"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 nepoužívaná aplikácia"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"Nepoužívané aplikácie: <xliff:g id="NUMBER_OF_APPS">%s</xliff:g>"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Niektoré aplikácie ste niekoľko mesiacov nepoužili. Skontrolujte to klepnutím."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# nepoužívaná aplikácia}few{# nepoužívané aplikácie}many{# unused apps}other{# nepoužívaných aplikácií}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Povolenia a dočasné súbory boli odstránené a upozornenia boli zastavené. Skontrolujte to klepnutím."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Skontrolujte aplikácie s odstránenými povoleniami"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"V prípade aplikácií, ktoré ste dlhšie nepoužívali, boli povolenia a dočasné súbory odstránené a upozornenia deaktivované."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Skontrolovať aplikácie"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Skontrolujte nedávne povolenia"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Počas jazdy ste udelili aplikácii <xliff:g id="APP">%1$s</xliff:g> povolenie <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Počas jazdy ste udelili aplikácii <xliff:g id="APP">%1$s</xliff:g> prístup k povoleniam <xliff:g id="PERMISSION_1">%2$s</xliff:g> &amp; <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Povolenia boli odstránené na zaistenie ochrany vášho súkromia"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"Aplikácia <xliff:g id="APP_NAME">%s</xliff:g> získala vašu polohu na pozadí"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Táto aplikácia má neobmedzený prístup k polohe. Klepnutím to zmeníte."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Skontrolujte aplikáciu s prístupom k upozorneniam"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> môže zavrieť a použiť vaše upozornenia, ale aj získať prístup k ich obsahu"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Táto aplikácia môže zavrieť a použiť vaše upozornenia, ale aj získať prístup k ich obsahu. Niektoré aplikácie vyžadujú tento prístup, aby mohli správne fungovať."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Odstrániť prístup"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Zobraziť viac možností"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Prístup bol odstránený"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Skontrolujte aplikáciu s úplným prístupom k zariadeniu"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> si môže zobraziť vašu obrazovku a vykonávať akcie vo vašom zariadení. Aplikácie dostupnosti vyžadujú tento typ prístupu, aby mohli správne fungovať."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Táto aplikácia si môže zobraziť vašu obrazovku a vykonávať akcie vo vašom zariadení. Aplikácie dostupnosti vyžadujú tento typ prístupu, aby mohli správne fungovať. Aplikáciu však skontrolujte a uistite sa, že je pre vás dôveryhodná."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Odstrániť prístup"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Zobraziť aplikácie s úplným prístupom"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Prístup bol odstránený"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Systém Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Povolenia apl. boli odstránené na zaistenie ochrany súkromia"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Aplikácia <xliff:g id="APP_NAME">%s</xliff:g> nebola niekoľko mesiacov používaná. Skontrolujte to klepnutím."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> a 1 ďalšia aplikácia neboli niekoľko mesiacov používané. Skontrolujte to klepnutím."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a získa prístup k telefónu, SMS, kontaktom a kalendáru."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a streamovať vaše aplikácie do pripojeného zariadenia."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Táto služba zdieľa fotky, médiá a upozornenia z vášho telefónu do iných zariadení."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Predvol. aplikácia na poznámky"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Ovládané povolenia"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Polohu je možné používať"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Váš správca IT povoľuje aplikácii <xliff:g id="APP_NAME">%s</xliff:g> používať vašu polohu"</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>
<string name="other_permissions_label" msgid="8986184335503271992">"Ďalšie povolenia"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Povolenia používané systémom"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Povolenia používané iba systémovými aplikáciami."</string>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"V prípade aplikácií a služieb"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Keď zavoláte na tiesňovú linku, môžu sa stále zdieľať údaje mikrofónu."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Zmeniť"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Zabezpeč. a ochrana súkromia"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Skontrolovať"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Zabezpečenie, ochrana súkromia"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Skontrolovať zariadenie"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Zavrieť"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Chcete zavrieť toto upozornenie?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Kedykoľvek si môžete skontrolovať nastavenia zabezpečenia a ochrany súkromia a ochranu zlepšiť"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Zavrieť"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Zrušiť"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Nastavenia"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Stav zabezpečenia a ochrany súkromia. <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">"Nastavenia zabezpečenia"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Povolenia pre senzory"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Nastavenia ochrany súkromia"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Povolenia"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Zabezpečenie a ochrana súkromia"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Skontrolovať stav"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Nastavenia ochrany súkromia"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Ďalšie nastavenia"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Prístup ku kamere"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Prístup k mikrofónu"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Bolo odstránené povolenie"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Zobraziť ďalšie využitie kamery"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Zobraziť ďalšie využitie mikrofónu"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Odstrániť povolenie pre kameru"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Odstrániť povolenie pre mikrofón"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Zobraziť nedávne používanie kamery"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Zobraziť nedávne používanie mikrofónu"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Odstrániť povolenie pre túto aplikáciu"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Odstrániť povolenie pre túto aplikáciu"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Spravovať službu"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Spravovať povolenia"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Využíva telefonický hovor"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Nedávno využila aplikácia <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">"Využíva aplikácia <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">"Nedávno využila aplikácia <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Zabezpečenie a ochrana súkromia"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Skontrolovať stav"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Potvrdiť"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Späť"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Bude povolený aj prístup k ďalším súborom"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Táto aplikácia nepodporuje najnovšiu verziu Androidu. Ak táto aplikácia nemá prístup k hudobným a zvukovým súborom, nebude ho mať ani k fotkám a videám."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Táto aplikácia nepodporuje najnovšiu verziu Androidu. Ak má táto aplikácia prístup k fotkám a videám, bude ho mať aj k hudobným a zvukovým súborom."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Táto aplikácia nepodporuje najnovšiu verziu Androidu. Ak táto aplikácia nemá prístup k hudobným a zvukovým súborom, nebude ho mať ani k fotkám a videám."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Skontrolujte aplikáciu s prístupom k určovaniu polohy na pozadí"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"Aplikácia <xliff:g id="APP_NAME">%s</xliff:g> má neobmedzený prístup k vašej polohe, a to aj vtedy, keď je zavretá"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Skontrolujte aplikáciu s prístupom k určovaniu polohy na pozadí"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Táto aplikácia má neobmedzený prístup k polohe, a to aj vtedy, keď je zavretá.\n\nNiektoré bezpečnostné a tiesňové aplikácie vyžadujú prístup k vašej polohe na pozadí, aby fungovali, ako majú."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Prístup bol zmenený"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Zobraziť nedávne používanie polohy"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Nastavenia ochrany súkromia"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Prístup ku kamere"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Prístup k mikrofónu"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Pre aplikácie a služby"</string>
+ <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ď 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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Nakladanie s údajmi sa môže líšiť v závislosti od verzie a používania aplikácie, ako aj regiónu a veku používateľa. "<annotation id="link">"Ďalšie informácie o zdieľaní údajov"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Nakladanie s údajmi sa môže líšiť v závislosti od verzie a používania aplikácie, ako aj regiónu a veku používateľa."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Údaje o vašej polohe"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Prístup tejto aplikácie môžete zmeniť v "<annotation id="link">"nastaveniach ochrany súkromia"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Funkcie aplikácie"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analytika"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Komunikácie vývojára"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Reklama alebo marketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Prevencia podvodov, zabezpečenie a dodržiavanie pravidiel"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Prispôsobenie"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Správa účtu"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Vývojári týchto aplikácií poskytli informácie o ich postupoch zdieľania údajov v obchode s aplikáciami. Priebežne ich môžu aktualizovať.\n\nPostupy zdieľania údajov sa môžu líšiť v závislosti od verzie a používania vašej aplikácie, ako aj regiónu a veku jej používateľa."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Ďalšie informácie o zdieľaní údajov"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Údaje o vašej polohe sa teraz zdieľajú s tretími stranami"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Údaje o vašej polohe sa teraz zdieľajú s tretími stranami na účely reklamy a marketingu"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Aktualizované v priebehu uplynulého dňa}=1{Aktualizované v priebehu uplynulého dňa}few{Aktualizované v priebehu uplynulých # dní}many{Aktualizované v priebehu uplynulej # dňa}other{Aktualizované v priebehu uplynulých # dní}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Momentálne neprebehli žiadne aktualizácie"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-sl-v33/strings.xml b/PermissionController/res/values-sl-v33/strings.xml
index fbdca368c..6bc0748fb 100644
--- a/PermissionController/res/values-sl-v33/strings.xml
+++ b/PermissionController/res/values-sl-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Ta aplikacija vam bo lahko pošiljala obvestila ter bo imela dostop do fotoaparata, stikov, mikrofona, telefona in sporočil SMS."</string>
<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="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>
+ <string name="safety_center_entry_group_with_actions_needed_content_description" msgid="2708884606775932657">"Seznam. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Potrebno je ukrepanje. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Element na seznamu. <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">"Več opozoril"</string>
+ <string name="safety_center_dismissed_issues_card_title" msgid="2340129842725145733">"Opuščena opozorila"</string>
+ <string name="safety_center_more_issues_card_expand_action" msgid="7109451851052272946">"{count,plural, =1{Razširi in prikaži še eno opozorilo}one{Razširi in prikaži še # opozorilo}two{Razširi in prikaži še # opozorili}few{Razširi in prikaži še # opozorila}other{Razširi in prikaži še # opozoril}}"</string>
+ <string name="safety_center_issue_card_prefix_content_description" msgid="1447445289637043544">"Opozorilo. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>"</string>
+ <string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Dejanje končano"</string>
+ <string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Preverite nastavitve, ki lahko izboljšajo varnost naprave."</string>
+ <string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Hitre nastavitve varnosti in zasebnosti"</string>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Zapri"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Razširi in pokaži možnosti"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Strni"</string>
+ <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">"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
new file mode 100644
index 000000000..18afff3d1
--- /dev/null
+++ b/PermissionController/res/values-sl-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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>
+</resources>
diff --git a/PermissionController/res/values-sl/strings.xml b/PermissionController/res/values-sl/strings.xml
index 7222fd53a..5265a0724 100644
--- a/PermissionController/res/values-sl/strings.xml
+++ b/PermissionController/res/values-sl/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Nazaj"</string>
<string name="available" msgid="6007778121920339498">"Na voljo"</string>
<string name="blocked" msgid="9195547604866033708">"Blokirano"</string>
+ <string name="on" msgid="280241003226755921">"Vklopljeno"</string>
+ <string name="off" msgid="1438489226422866263">"Izklopi"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Odmesti ali onemogoči"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Aplikacije ni mogoče najti"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Ne dovoli"</string>
@@ -30,10 +32,15 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Obdrži »Ko je aplikacija v uporabi«"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Obdrži »Samo tokrat«"</string>
<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_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>
@@ -107,9 +114,6 @@
<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="screen_overlay_title" msgid="6977038513913222078">"Zaznano prekrivanje zaslona"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Če želite spremeniti nastavitev tega dovoljenja, morate najprej izklopiti prekrivanje zaslona v »Nastavitve &gt; Aplikacije«"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Odpri nastavitve"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Časovna os uporabe dovoljenja »<xliff:g id="PERMGROUP">%1$s</xliff:g>« po aplikacijah v zadnjih 7 dneh."</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Uporaba dovoljenja »<xliff:g id="PERMGROUP">%1$s</xliff:g>« za to aplikacijo"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Več o tem"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Preberite več o storitvi <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Upravljanje dostopa aplikacij do: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 dan}one{# dan}two{# dneva}few{# dni}other{# dni}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 ura}one{# ura}two{# uri}few{# ure}other{# ur}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}one{# min}two{# min}few{# min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 s}one{# s}two{# s}few{# s}other{# s}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# dan}one{# dan}two{# dneva}few{# dni}other{# dni}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# ura}one{# ura}two{# uri}few{# ure}other{# ur}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}one{# min}two{# min}few{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# s}one{# s}two{# s}few{# s}other{# s}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Katero koli dovoljenje"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Kadar koli"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Zadnjih 7 dni"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Zadnjih 24 ur"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Zadnja ura"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Zadnjih 15 minut"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Zadnja minuta"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Zadnji # dan}one{Zadnji # dan}two{Zadnja # dneva}few{Zadnje # dni}other{Zadnjih # dni}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Zadnja # ura}one{Zadnja # ura}two{Zadnji # uri}few{Zadnje # ure}other{Zadnjih # ur}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Zadnja # minuta}one{Zadnja # minuta}two{Zadnji # minuti}few{Zadnje # minute}other{Zadnjih # minut}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Ni uporabe dovoljenj"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Zadnja uporaba kadar koli"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Zadnja uporaba v zadnjih 7 dneh"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Uporaba dovoljenj v zadnji uri"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Uporaba dovoljenj v zadnjih 15 minutah"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Uporaba dovoljenj v zadnji minuti"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Brez uporabe v zadnjih 24 urah"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Brez uporabe v zadnjih 7 dneh"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Brez uporabe v zadnjem # dnevu}one{Brez uporabe v zadnjem # dnevu}two{Brez uporabe v zadnjih # dneh}few{Brez uporabe v zadnjih # dneh}other{Brez uporabe v zadnjih # dneh}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Brez uporabe v zadnji # uri}one{Brez uporabe v zadnji # uri}two{Brez uporabe v zadnjih # urah}few{Brez uporabe v zadnjih # urah}other{Brez uporabe v zadnjih # urah}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Uporablja 1 aplikacija}one{Uporablja # aplikacija}two{Uporabljata # aplikaciji}few{Uporabljajo # aplikacije}other{Uporablja # aplikacij}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Prikaži vse na nadzorni plošči"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrirano po: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Dovoli samo dostop do predstavnosti"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Vedno dovoli"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Dovoli samo med uporabo aplikacije"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Vedno dovoli vse"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Vedno vprašaj"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Ne dovoli"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Natančna lokacija"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Dovoljenji <xliff:g id="PERM_0">%1$s</xliff:g> in <xliff:g id="PERM_1">%2$s</xliff:g> bosta odstranjeni."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Dovoljenja, ki bodo odstranjena: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Samodejno upravljanje dovoljenj"</string>
- <string name="off" msgid="1438489226422866263">"Izklopi"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Odstranjeno je bilo dovoljenje <xliff:g id="PERMISSION_NAME">%s</xliff:g>"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Odstranjeni sta bili dovoljenji <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> in <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g>"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Odstranjeno je bilo dovoljenje <xliff:g id="PERMISSION_NAME">%1$s</xliff:g> in še toliko drugih: <xliff:g id="NUMBER">%2$s</xliff:g>"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Neuporabljene aplikacije"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Po nekaj mesecih neuporabe aplikacije se zgodi to:\n\n• Dovoljenja se odstranijo, da se zaščiti vaša zasebnost.\n• Obvestila se zaustavijo, da varčujete z energijo baterije.\n• Začasne datoteke se odstranijo, da se sprosti prostor.\n\nČe želite znova omogočiti dovoljenja in obvestila, odprite aplikacijo."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Po nekaj mesecih neuporabe aplikacije se zgodi to:\n\n• Dovoljenja se odstranijo, da se zaščiti vaša zasebnost.\n• Začasne datoteke se odstranijo, da se sprosti prostor.\n\nČe želite znova omogočiti dovoljenja, odprite aplikacijo."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Nazadnje odprto pred več kot toliko meseci: <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Po enem mesecu neuporabe aplikacije se zgodi to:\n\n• Dovoljenja se odstranijo, da se zaščitijo vaši podatki.\n• Začasne datoteke se odstranijo, da se sprosti prostor.\n\nČe želite znova omogočiti dovoljenja, odprite aplikacijo."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Nazadnje odprto pred več kot # mesecem}one{Nazadnje odprto pred več kot # mesecem}two{Nazadnje odprto pred več kot # mesecema}few{Nazadnje odprto pred več kot # meseci}other{Nazadnje odprto pred več kot # meseci}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Aplikacija je bila nazadnje odprta <xliff:g id="DATE">%s</xliff:g>"</string>
<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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Ni dovoljeno"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Prikaži več aplikacij z dostopom do vseh datotek"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 dan}one{# dan}two{# dneva}few{# dni}other{# dni}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 ura}one{# ura}two{# uri}few{# ure}other{# ur}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minuta}one{# minuta}two{# minuti}few{# minute}other{# minut}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 sekunda}one{# sekunda}two{# sekundi}few{# sekunde}other{# sekund}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# ura}one{# ura}two{# uri}few{# ure}other{# ur}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minuta}one{# minuta}two{# minuti}few{# minute}other{# minut}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# sekunda}one{# sekunda}two{# sekundi}few{# sekunde}other{# sekund}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Opomniki za dovoljenja"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 neuporabljena aplikacija"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"Št. neuporabljenih aplikacij: <xliff:g id="NUMBER_OF_APPS">%s</xliff:g>"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Nekatere aplikacije niso bile uporabljene več mesecev. Dotaknite se za pregled."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# neuporabljena aplikacija}one{# neuporabljena aplikacija}two{# neuporabljeni aplikaciji}few{# neuporabljene aplikacije}other{# neuporabljenih aplikacij}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Dovoljenja in začasne datoteke so odstranjeni, obvestila so zaustavljena. Dotaknite se za pregled."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Preglejte aplikacije z odstranjenimi dovoljenji"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Za aplikacije, ki jih nekaj časa niste uporabljali, so bili dovoljenja in začasne datoteke odstranjeni, obvestila pa so bila ustavljena."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Preglejte aplikacije"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Preverite nedavna dovoljenja"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Med vožnjo ste aplikaciji <xliff:g id="APP">%1$s</xliff:g> odobrili dostop do tega dovoljenja: <xliff:g id="PERMISSION">%2$s</xliff:g>."</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Med vožnjo ste aplikaciji <xliff:g id="APP">%1$s</xliff:g> odobrili dostop do teh dovoljenj: <xliff:g id="PERMISSION_1">%2$s</xliff:g> in <xliff:g id="PERMISSION_2">%3$s</xliff:g>."</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Dovoljenja odstranjena za zaščito vaše zasebnosti"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"Aplikacija <xliff:g id="APP_NAME">%s</xliff:g> je podatek o lokaciji pridobila v ozadju"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Ta aplikacija lahko vedno dostopa do vaše lokacije. Dotaknite se, če želite spremeniti dovoljenje."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Pregled aplikacije z dostopom do obvestil"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> lahko opusti vsebino v obvestilih, ukrepa glede te vsebine in dostopa do nje."</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Ta aplikacija lahko opusti vsebino v obvestilih, ukrepa glede te vsebine in dostopa do nje. Nekatere aplikacije potrebujejo takšen dostop, da lahko delujejo, kot je predvideno."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Odstrani dostop"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Pokaži več možnosti"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Dostop je odstranjen"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Pregled aplikacije s polnim dostopom do naprave"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"Aplikacija <xliff:g id="APP_NAME">%s</xliff:g> si lahko ogleduje zaslon in izvaja dejanja v napravi. Aplikacije za dostopnost potrebujejo tovrstni dostop, da lahko delujejo, kot je predvideno."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Ta aplikacija si lahko ogleduje zaslon in izvaja dejanja v napravi. Aplikacije za dostopnost potrebujejo tovrstni dostop, da lahko delujejo, kot je predvideno, vendar pa preverite aplikacijo in se prepričajte, da ji zaupate."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Odstrani dostop"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Prikaži aplikacije s polnim dostopom"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Dostop je odstranjen."</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Sistem Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Dovoljenja za aplikacije odstranjena za zaščito zasebnosti"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Več mesecev niste uporabljali aplikacije <xliff:g id="APP_NAME">%s</xliff:g>. Dotaknite se za pregled."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"Več mesecev niste uporabljali aplikacije <xliff:g id="APP_NAME">%s</xliff:g> in 1 druge aplikacije. Dotaknite se za pregled."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> bosta omogočena interakcija z obvestili in dostop do dovoljenj za telefon, sporočila SMS, stike in koledar."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> bosta omogočena interakcija z obvestili in pretočno izvajanje aplikacij v povezano napravo."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Ta storitev deli vaše fotografije, predstavnost in obvestila iz vašega telefona z drugimi napravami."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Privzeta aplikacija za zapiske"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Zunanje upravljana dovoljenja"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Omogočen je dostop do lokacije"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Skrbnik za IT aplikaciji <xliff:g id="APP_NAME">%s</xliff:g> dovoljuje dostop do vaše lokacije"</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>
<string name="other_permissions_label" msgid="8986184335503271992">"Druga dovoljenja"</string>
<string name="not_used_permissions_label" msgid="3939839426115141264">"Dovoljenje, ki ga uporablja sistem"</string>
<string name="not_used_permissions_description" msgid="7595514824169388718">"Dovoljenja, ki jih uporabljajo le sistemske aplikacije"</string>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Za aplikacije in storitve"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Podatki mikrofona bodo morda še vedno deljeni, ko pokličete številko za klic v sili."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Spremeni"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Varnost in zasebnost"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Išči"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Varnost in zasebnost"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Preglej napravo"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Opusti"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Želite opustiti to opozorilo?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Za dodatno zaščito lahko kadar koli pregledate varnostne nastavitve in nastavitve zasebnosti."</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Opusti"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Prekliči"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Nastavitve"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Stanje glede varnosti in zasebnosti. <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">"Varnostne nastavitve"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Dovoljenja za tipala"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Nastavitve zasebnosti"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Dovoljenja"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Varnost in zasebnost"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Preverjanje stanja"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Vaše nastavitve zasebnosti"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Več nastavitev"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Dostop do fotoaparata"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Dostop do mikrofona"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Dovoljenje je bilo odstranjeno"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Več o uporabi fotoaparata"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Več o uporabi mikrofona"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Odstrani dovoljenje za fotoaparat"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Odstrani dovoljenje za mikrofon"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Prikaži nedavno uporabo fotoaparata"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Prikaži nedavno uporabo mikrofona"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Odstrani dovoljenje za to aplikacijo"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Odstrani dovoljenje za to aplikacijo"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Upravljanje storitve"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Upravljanje dovoljenj"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Trenutno se uporablja v telefonskem klicu"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Nedavno uporabljala 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">"Trenutno uporablja 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>
<string name="recent_app_usage_2_qs" msgid="3591205954235694403">"Nedavno uporabljala 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>
- <string name="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Varnost in zasebnost"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Preverjanje stanja"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Potrdi"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Nazaj"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Tudi dostop do drugih datotek bo dovoljen"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Ta aplikacija ne podpira najnovejše različice Androida. Če ta aplikacija ne sme dostopati do glasbe in zvočnih datotek, ji tudi dostop do fotografij in videoposnetkov ne bo dovoljen."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Ta aplikacija ne podpira najnovejše različice Androida. Če ta aplikacija sme dostopati do fotografij in videoposnetkov, ji bo dovoljen tudi dostop do glasbe in zvočnih datotek."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Ta aplikacija ne podpira najnovejše različice Androida. Če ta aplikacija ne sme dostopati do glasbe in zvočnih datotek, ji tudi dostop do fotografij in videoposnetkov ne bo dovoljen."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Pregled aplikacije z dostopom do lokacije v ozadju"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"Aplikacija <xliff:g id="APP_NAME">%s</xliff:g> lahko vedno dostopa do vaše lokacije, tudi ko je aplikacija zaprta."</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Pregled aplikacije z dostopom do lokacije v ozadju"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Ta aplikacija lahko vedno dostopa do vaše lokacije, tudi ko je zaprta.\n\nNekatere varnostne aplikacije in aplikacije v sili za pravilno delovanje potrebujejo dostop do lokacije v ozadju."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Dostop je bil spremenjen."</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Prikaži nedavno uporabo lokacije"</string>
+ <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="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>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Pokaži sporočilo, ko aplikacije dostopijo do besedila, slik ali drugih vsebin, ki ste jih kopirali."</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Pokaži gesla"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Za trenutek prikaži znake med vnašanjem."</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Postopki obdelave podatkov se morda razlikujejo glede na različico aplikacije, uporabo, območje in starost. "<annotation id="link">"Preberite več o deljenju podatkov"</annotation>"."</string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Postopki deljenja podatkov se morda razlikujejo glede na različico aplikacije, njeno uporabo, območje in vašo starost."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Vaši lokacijski podatki"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Dostop te aplikacije lahko spremenite v "<annotation id="link">"nastavitvah zasebnosti"</annotation>"."</string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Funkcija aplikacije"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analitika"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Komunikacija z razvijalci"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Oglaševanje ali trženje"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Preprečevanje prevar, varnost in zagotavljanje skladnosti"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Individualna prilagoditev"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Upravljanje računa"</string>
+ <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="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_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>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Vaši lokacijski podatki so zdaj deljeni s tretjimi osebami."</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Vaši lokacijski podatki so zdaj deljeni s tretjimi osebami za namene oglaševanja ali trženja."</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Posodobljeno v zadnjem dnevu}=1{Posodobljeno v zadnjem dnevu}one{Posodobljeno v zadnjem # dnevu}two{Posodobljeno v zadnjih # dneh}few{Posodobljeno v zadnjih # dneh}other{Posodobljeno v zadnjih # dneh}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Trenutno ni nobenih posodobitev"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-sq-v33/strings.xml b/PermissionController/res/values-sq-v33/strings.xml
index b25c6c2b8..bbe8e9a89 100644
--- a/PermissionController/res/values-sq-v33/strings.xml
+++ b/PermissionController/res/values-sq-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Ky aplikacion do të lejohet të të dërgojë njoftime dhe do t\'i jepet qasje te kamera, kontaktet, mikrofoni, telefoni dhe mesazhet SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Ky aplikacion do të lejohet të të dërgojë njoftime dhe do t\'i jepet qasje te \"Kamera\", \"Kontaktet\", \"Skedarët\", \"Mikrofoni\", \"Telefoni\" dhe \"SMS-të\""</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Aplikacionet me këtë leje mund të kenë qasje tek të gjithë skedarët në këtë pajisje"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Informacioni i politikës së punës"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Cilësimet menaxhohen nga administratori i teknologjisë së informacionit"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Zgjero dhe shfaq listën"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Palos listën dhe fshih cilësimet"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Lista. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Lista. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Nevojiten veprime. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Artikulli i listës. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Mbyll"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Zgjero dhe shfaq opsionet"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Palos"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Ndërro. <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">"Aktivizo/çaktivizo"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Hap"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Rishiko cilësimet"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Cilësimet"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Informacione"</string>
</resources>
diff --git a/PermissionController/res/values-sq-v34/strings.xml b/PermissionController/res/values-sq-v34/strings.xml
new file mode 100644
index 000000000..bf9c922cd
--- /dev/null
+++ b/PermissionController/res/values-sq-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Siguria dhe privatësia"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Kontrollet"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Menaxho qasjen e aplikacioneve te të dhënat e shëndetit"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Qasja te vendndodhja"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Për aplikacionet dhe shërbimet. Nëse ky cilësim është joaktiv, të dhënat e mikrofonit mund të vazhdojnë të ndahen kur telefonon një numër urgjence."</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Për aplikacionet dhe shërbimet"</string>
+</resources>
diff --git a/PermissionController/res/values-sq/strings.xml b/PermissionController/res/values-sq/strings.xml
index ab09c66f4..bfda0b905 100644
--- a/PermissionController/res/values-sq/strings.xml
+++ b/PermissionController/res/values-sq/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Pas"</string>
<string name="available" msgid="6007778121920339498">"Ofrohet"</string>
<string name="blocked" msgid="9195547604866033708">"Bllokuar"</string>
+ <string name="on" msgid="280241003226755921">"Aktiv"</string>
+ <string name="off" msgid="1438489226422866263">"Joaktiv"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Çinstalo ose çaktivizo"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Aplikacioni nuk u gjet"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Mos lejo"</string>
@@ -30,11 +32,16 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Mbaje \"Kur aplikacioni është në përdorim\""</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Mbaje “Vetëm këtë herë”"</string>
<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_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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Mbivendosja e ekranit u zbulua"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Për të ndryshuar këtë cilësim të lejes, në fillim duhet të çaktivizosh mbivendosjen e ekranit nga Cilësimet &gt; Aplikacionet"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Hap \"Cilësimet\""</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Kronologjia se kur është përdorur \"<xliff:g id="PERMGROUP">%1$s</xliff:g>\" nga aplikacionet në 7 ditët e fundit"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Kur ky aplikacion ka përdorur lejen për: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Mëso më shumë"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Mëso më shumë për: <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Kontrollo qasjen e aplikacionit në <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 ditë}other{# ditë}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 orë}other{# orë}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min.}other{# min.}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 sek.}other{# sek.}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# ditë}other{# ditë}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# orë}other{# orë}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min.}other{# min.}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# sek.}other{# sek.}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Çdo autorizim"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Në çdo kohë"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"7 ditët e fundit"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"24 orët e fundit"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"1 orën e fundit"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"15 minutat e fundit"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Minuta e fundit"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Dita e fundit}other{# ditët e fundit}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Ora e fundit}other{# orët e fundit}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Minuta e fundit}other{# minutat e fundit}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Nuk ka përdorime të lejeve"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Qasja më e fundit në çdo kohë"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Qasja më e fundit në 7 ditët e fundit"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Përdorimi i autorizimeve në 1 orën e fundit"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Përdorimi i autorizimeve në 15 minutat e fundit"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Përdorimi i autorizimeve në 1 minutën e fundit"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Asnjë përdorim gjatë 24 orëve të fundit"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Nuk është përdorur gjatë 7 ditëve të fundit"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Nuk është përdorur gjatë ditës së fundit}other{Nuk është përdorur gjatë # ditëve të fundit}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Nuk është përdorur gjatë orës së fundit}other{Nuk është përdorur gjatë # orëve të fundit}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Përdorur nga 1 aplikacion}other{Përdorur nga # aplikacione}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Shikoji të gjitha te \"Paneli\""</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtruar sipas: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,14 +188,15 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Lejo qasjen vetëm në media"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Lejo gjithmonë"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Lejo vetëm kur përdor aplikacionin"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Lejoji gjithmonë të gjitha"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Pyet çdo herë"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Mos lejo"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Vendndodhja e saktë"</string>
<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>
@@ -207,23 +211,22 @@
<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>
- <string name="off" msgid="1438489226422866263">"Joaktiv"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Leja për \"<xliff:g id="PERMISSION_NAME">%s</xliff:g>\" është hequr"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> dhe <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> leje janë hequr"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> dhe <xliff:g id="NUMBER">%2$s</xliff:g> leje të tjera janë hequr"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Aplikacionet e papërdorura"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Nëse një aplikacion nuk përdoret për disa muaj:\n\n• Lejet hiqen për të mbrojtur të dhënat e tua\n• Njoftimet ndalohen për të kursyer baterinë\n• Skedarët e përkohshëm hiqen për të liruar hapësirën\n\nPër të lejuar përsëri lejet dhe njoftimet, hap aplikacionin."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Nëse një aplikacion nuk përdoret për disa muaj:\n\n• Lejet hiqen për të mbrojtur të dhënat e tua\n• Skedarët e përkohshëm hiqen për të liruar hapësirën\n\nPër të lejuar përsëri lejet, hap aplikacionin."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Hapur për herë të fundit më shumë se <xliff:g id="NUMBER">%s</xliff:g> muaj më parë"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Nëse një aplikacion nuk përdoret për një muaj:\n\n• Lejet hiqen për të mbrojtur të dhënat e tua\n• Skedarët e përkohshëm hiqen për të liruar hapësirën\n\nPër të lejuar përsëri lejet, hap aplikacionin."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Hapur për herë të fundit më shumë se # muaj më parë}other{Hapur për herë të fundit më shumë se # muaj më parë}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Aplikacioni është hapur së fundi më <xliff:g id="DATE">%s</xliff:g>"</string>
<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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Nuk lejohet"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Shiko më shumë aplikacione me qasje tek të gjithë skedarët"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 ditë}other{# ditë}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 orë}other{# orë}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minutë}other{# minuta}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 sekondë}other{# sekonda}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# orë}other{# orë}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minutë}other{# minuta}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# sekondë}other{# sekonda}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Alarmet rikujtuese për lejet"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 aplikacion i papërdorur"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> aplikacione të papërdorura"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Disa aplikacione nuk janë përdorur për disa muaj. Trokit për t\'i rishikuar."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# aplikacion i papërdorur}other{# aplikacione të papërdorura}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Lejet dhe skedarët e përkohshëm janë hequr dhe njoftimet janë ndaluar. Trokit për t\'i rishikuar."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Shqyrto aplikacionet me leje të hequra"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Lejet dhe skedarët e përkohshëm u hoqën dhe njoftimet u ndaluan për aplikacionet që nuk ke përdorur prej kohësh."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Shqyrto aplikacionet"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Kontrollo lejet e fundit"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Gjatë drejtimit të makinës, i ke dhënë \"<xliff:g id="APP">%1$s</xliff:g>\" qasje te <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Gjatë drejtimit të makinës, i ke dhënë \"<xliff:g id="APP">%1$s</xliff:g>\" qasje te <xliff:g id="PERMISSION_1">%2$s</xliff:g> dhe <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Lejet u hoqën për të mbrojtur privatësinë tënde"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> ka marrë vendndodhjen tënde në sfond"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Ky aplikacion mund të qaset gjithmonë te vendndodhja jote. Trokit për ta ndryshuar."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Shqyrto aplikacionin me qasje në njoftimet e tua"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> mund të heqë njoftimet, të kryejë veprime për njoftimet dhe të qaset te përmbajtjet brenda njoftimeve të tua"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Ky aplikacion mund të heqë njoftimet, të kryejë veprime për njoftimet dhe të qaset te përmbajtjet brenda njoftimeve të tua. Disa aplikacione e kërkojnë këtë qasje për të funksionuar siç duhet."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Hiq qasjen"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Shiko opsione të tjera"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Qasja u hoq"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Shqyrto aplikacionin me qasje të plotë te pajisja"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> mund të shikojë ekranin tënd dhe të kryejë veprime në pajisjen tënde. Aplikacioneve të qasshmërisë u nevojitet kjo lloj qasje për të funksionuar siç duhet."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Ky aplikacion mund të shikojë ekranin tënd dhe të kryejë veprime në pajisjen tënde. Aplikacioneve të qasshmërisë u nevojitet kjo lloj qasje për të funksionuar siç duhet por kontrollo aplikacionin dhe sigurohu që i beson."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Hiq qasjen"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Shiko aplikacionet me qasje të plotë"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Qasja u hoq"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Sistemi Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Lejet e aplikacionit u hoqën për të mbrojtur privatësinë"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> nuk është përdorur për disa muaj. Trokit për ta rishikuar."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> dhe 1 aplikacion tjetër nuk janë përdorur për disa muaj. Trokit për ta rishikuar."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\" dhe \"Kalendarit\"."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të transmetojë aplikacionet në pajisjen e lidhur."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Ky shërbim ndan fotografitë, median dhe njoftimet nga telefoni yt me pajisje të tjera."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Shënimet; apl. i parazgjedhur"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Lejet e kontrolluara"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Lejohet qasja te vendndodhja"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Administratori yt i TI-së e lejon aplikacionin \"<xliff:g id="APP_NAME">%s</xliff:g>\" të ketë qasje te vendndodhja jote"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Për aplikacionet dhe shërbimet"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Të dhënat e mikrofonit mund të vazhdojnë të ndahen kur telefonon një numër urgjence."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Ndrysho"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Siguria dhe privatësia"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Skano"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Siguria dhe privatësia"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Skano pajisjen"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Hiq"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Të hiqet ky sinjalizim?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Shqyrto cilësimet e sigurisë dhe privatësisë në çdo kohë për të shtuar më shumë mbrojtje"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Hiq"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Anulo"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Cilësimet"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Statusi i sigurisë dhe i privatësisë. <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">"Cilësimet e sigurisë"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Lejet e sensorëve"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Kontrollet e privatësisë"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Lejet"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Siguria dhe privatësia"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Kontrollo statusin"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Kontrollet e privatësisë"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Cilësime të tjera"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Qasja te kamera"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Qasja te mikrofoni"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Leja është hequr"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Shiko më shumë përdorime të kamerës"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Shiko më shumë përdorime të mikrofonit"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Hiq lejen e kamerës"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Hiq lejen e mikrofonit"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Shiko përdorimin e fundit të kamerës"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Shiko përdorimin e fundit të mikrofonit"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Hiq lejen për këtë aplikacion"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Hiq lejen për këtë aplikacion"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Menaxho shërbimin"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Menaxho lejet"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Po përdoret nga telefonata"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Përdorur së fundi nga <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">"Po përdoret nga <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">"Përdorur së fundi nga <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Siguria dhe privatësia"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Kontrollo statusin"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Konfirmo"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Pas"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Gjithashtu, do të lejohet qasja te skedarët e tjerë"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Ky aplikacion nuk mbështet versionin më të fundit të Android. Nëse ky aplikacion nuk mund të ketë qasje te muzika dhe te skedarët audio, atij nuk do t\'i lejohet gjithashtu të ketë qasje te fotografitë dhe te videot."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Ky aplikacion nuk mbështet versionin më të fundit të Android. Nëse ky aplikacion mund të ketë qasje te fotografitë dhe te videot, atij do t\'i lejohet gjithashtu të ketë qasje te muzika dhe te skedarët audio."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Ky aplikacion nuk mbështet versionin më të fundit të Android. Nëse ky aplikacion nuk mund të ketë qasje te muzika dhe te skedarët audio, atij nuk do t\'i lejohet gjithashtu të ketë qasje te fotografitë dhe te videot."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Shqyrto aplikacionin me qasje te vendndodhja në sfond"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> mund të ketë qasje në vendndodhjen tënde edhe kur aplikacioni është i mbyllur"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Shqyrto aplikacionin me qasje te vendndodhja në sfond"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Ky aplikacion mund të ketë qasje te vendndodhja jote edhe kur është i mbyllur.\n\nDisa aplikacione sigurie dhe urgjence kërkojnë qasje te vendndodhja jote në sfond për të funksionuar siç duhet."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Qasja u ndryshua"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Shiko përdorimin e fundit të vendndodhjes"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Kontrollet e privatësisë"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Qasja te kamera"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Qasja te mikrofoni"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Për aplikacionet dhe shërbimet"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Për aplikacionet dhe shërbimet. Nëse ky cilësim është joaktiv, të dhënat e mikrofonit mund të vazhdojnë të ndahen kur telefonon një numër urgjence."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Shiko aplikacione dhe shërbime dhe qasu te vendndodhja"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Shfaq qasjen te kujtesa e fragmenteve"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Shfaq një mesazh kur aplikacionet qasen te tekstet, imazhet ose përmbajtje të tjera që ke kopjuar"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Shfaq fjalëkalimet"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Shfaq karakteret shkurtimisht kur shkruan"</string>
+ <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_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>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Veprimet me të dhënat mund të ndryshojnë bazuar në versionin e aplikacionit, përdorimin, rajonin dhe moshën tënde."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Të dhënat e vendndodhjes sate"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Ndrysho qasjen e këtij aplikacioni te "<annotation id="link">"cilësimet e privatësisë"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Funksionaliteti i aplikacionit"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analiza"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Komunikimet e zhvilluesit"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Reklamimin ose marketingun"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Parandalimi i mashtrimeve, siguria dhe respektimi i rregullave"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Personalizimi"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Menaxhimi i llogarisë"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Zhvilluesit e këtyre aplikacioneve i ofruan informacione rreth praktikave të tyre për ndarjen e të dhënave një dyqani aplikacionesh. Informacionet mund të përditësohen me kalimin e kohës.\n\nPraktikat për ndarjen e të dhënave mund të ndryshojnë bazuar në versionin e aplikacionit, përdorimin, rajonin dhe moshën tënde."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Mëso rreth ndarjes së të dhënave"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Të dhënat e vendndodhjes sate tani ndahen me palë të treta"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Të dhënat e vendndodhjes sate tani ndahen me palë të treta për reklamim ose marketing"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Të përditësuara brenda ditës së fundit}=1{Të përditësuara brenda ditës së fundit}other{Të përditësuara brenda # ditëve}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Nuk ka përditësime tani"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-sr-v33/strings.xml b/PermissionController/res/values-sr-v33/strings.xml
index 983b1f40f..1fe22cee5 100644
--- a/PermissionController/res/values-sr-v33/strings.xml
+++ b/PermissionController/res/values-sr-v33/strings.xml
@@ -19,4 +19,28 @@
<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="work_policy_title" msgid="832967780713677409">"Информације о смерницама за посао"</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>
+ <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{Проширите и видите још # обавештење}few{Проширите и видите још # обавештења}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Затвори"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Прошири и прикажи опције"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Скупи"</string>
+ <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_gear_label" msgid="5175877094379694098">"Подешавања"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Информације"</string>
</resources>
diff --git a/PermissionController/res/values-sr-v34/strings.xml b/PermissionController/res/values-sr-v34/strings.xml
new file mode 100644
index 000000000..89233996c
--- /dev/null
+++ b/PermissionController/res/values-sr-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-sr/strings.xml b/PermissionController/res/values-sr/strings.xml
index 73178d2af..0fd94a069 100644
--- a/PermissionController/res/values-sr/strings.xml
+++ b/PermissionController/res/values-sr/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"Увек дозволи све"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Откривен је елемент који прекрива садржај екрана"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Да бисте променили подешавање ове дозволе, прво треба да искључите елемент који прекрива садржај екрана у одељку Подешавања &gt; Апликације"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Отвори подешавања"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 дан}one{# дан}few{# дана}other{# дана}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 сат}one{# сат}few{# сата}other{# сати}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 мин}one{# мин}few{# мин}other{# мин}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 сек}one{# сек}few{# сек}other{# сек}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# дан}one{# дан}few{# дана}other{# дана}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# сат}one{# сат}few{# сата}other{# сати}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# мин}one{# мин}few{# мин}other{# мин}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# сек}one{# сек}few{# сек}other{# сек}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Било која дозвола"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Било када"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Последњих 7 дана"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Последња 24 сата"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Последњи сат"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Последњих 15 минута"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Последњи минут"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Последњи # дан}one{Последњи # дан}few{Последња # дана}other{Последњих # дана}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Последњи # сат}one{Последњи # сат}few{Последња # сата}other{Последњих # сати}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Последњи # минут}one{Последњи # минут}few{Последња # минута}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>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Коришћење дозвола у последњих сат времена"</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">"Коришћење дозвола у последњем минуту"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Није коришћено у последња 24 сата"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Није коришћено у последњих 7 дана"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Није коришћено током последњег # дана}one{Није коришћено током последњег # дана}few{Није коришћено током последња # дана}other{Није коришћено током последњих # дана}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Није коришћено током последњег # сата}one{Није коришћено током последњег # сата}few{Није коришћено током последња # сата}other{Није коришћено током последњих # сати}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Користи 1 апликација}one{Користи # апликација}few{Користе # апликације}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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"Увек дозволи све"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Питај сваки пут"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Не дозволи"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Прецизна локација"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Уклониће се дозволе: <xliff:g id="PERM_0">%1$s</xliff:g> и <xliff:g id="PERM_1">%2$s</xliff:g>."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Дозволе које ће се уклонити: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Управљајте дозволама аутоматски"</string>
- <string name="off" msgid="1438489226422866263">"Искључено"</string>
<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_tv_summary" msgid="3685907153054355671">"Ако не користите апликацију неколико месеци:\n\n• дозволе се уклањају да би се заштитили подаци\n• привремени фајлови се уклањају да би се ослободио простор\n\nДа бисте поново омогућили дозволе, отворите апликацију."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Последњи пут отворено пре више од <xliff:g id="NUMBER">%s</xliff:g> мес."</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{Последњи пут отворено пре више од # месеца}few{Последњи пут отворено пре више од # месеца}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>
@@ -251,9 +254,9 @@
<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{# дана}other{# дана}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 сат}one{# сат}few{# сата}other{# сати}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 минут}one{# минут}few{# минута}other{# минута}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 секунда}one{# секунда}few{# секунде}other{# секунди}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# сат}one{# сат}few{# сата}other{# сати}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# минут}one{# минут}few{# минута}other{# минута}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# секунда}one{# секунда}few{# секунде}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>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Неке апликације нису коришћене пар месеци. Додирните да бисте прегледали."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# апликација која се не користи}one{# апликација које се не користи}few{# апликације које се не користе}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_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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android систем"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Дозволе за апликације су уклоњене ради заштите приватности"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Апликција <xliff:g id="APP_NAME">%s</xliff:g> није коришћена пар месеци. Додирните да бисте прегледали."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> и још једна апликација нису коришћене пар месеци. Додирните да бисте прегледали."</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"белешке"</string>
<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>
@@ -452,6 +475,7 @@
<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_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_microphone" msgid="2825208549114811299">"Желите да дозволите да &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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"Контролисане дозволе"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Може да се приступи локацији"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"ИТ администратор дозвољава апликацији <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"Безбедност и приватност"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Скенирај"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"Дозволе за сензоре"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Контроле приватности"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"Дозвола је уклоњена"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Прикажи још коришћења камере"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Прикажи још коришћења микрофона"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Уклони дозволу за камеру"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Уклони дозволу за микрофон"</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="manage_service_qs" msgid="7862555549364153805">"Управљајте услугом"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Управљајте дозволама"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Користи га телефонски позив"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Безбедност и приватност"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Проверите статус"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Поруке програмера"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Ажурирано током претходног дана}=1{Ажурирано током претходног дана}one{Ажурирано током претходног # дана}few{Ажурирано током претходна # дана}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>
</resources>
diff --git a/PermissionController/res/values-sv-v33/strings.xml b/PermissionController/res/values-sv-v33/strings.xml
index 897c2cbd7..e661efeb0 100644
--- a/PermissionController/res/values-sv-v33/strings.xml
+++ b/PermissionController/res/values-sv-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Appen får tillåtelse att skicka aviseringar och får åtkomst till behörigheterna Kamera, Kontakter, Mikrofon, Telefon och Sms"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Appen får tillåtelse att skicka aviseringar och får åtkomst till behörigheterna Kamera, Kontakter, Filer, Mikrofon, Telefon och Sms"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Appar med den här behörigheten får åtkomst till alla filer på enheten"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Information om jobbpolicy"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Inställningar som hanteras av IT-administratören"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Utöka och visa listan"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Komprimera lista och dölja inställningar"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Lista. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Lista. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Åtgärder krävs. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Post i listan. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Stäng"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Utöka och visa alternativ"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Komprimera"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Brytare. <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">"Aktivera och inaktivera"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Öppna"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Granska inställ­ningarna"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Inställningar"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Information"</string>
</resources>
diff --git a/PermissionController/res/values-sv-v34/strings.xml b/PermissionController/res/values-sv-v34/strings.xml
new file mode 100644
index 000000000..09e204e2e
--- /dev/null
+++ b/PermissionController/res/values-sv-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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 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>
+</resources>
diff --git a/PermissionController/res/values-sv/strings.xml b/PermissionController/res/values-sv/strings.xml
index 6c211dca1..7d53baf1a 100644
--- a/PermissionController/res/values-sv/strings.xml
+++ b/PermissionController/res/values-sv/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Tillbaka"</string>
<string name="available" msgid="6007778121920339498">"Tillgänglig"</string>
<string name="blocked" msgid="9195547604866033708">"Blockerad"</string>
+ <string name="on" msgid="280241003226755921">"På"</string>
+ <string name="off" msgid="1438489226422866263">"Av"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Avinstallera eller inaktivera"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Appen hittades inte"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Tillåt inte"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Behåll När appen används"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Behåll Bara den här gången"</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Tillåt inte ändå"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Stäng"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> av <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -107,9 +114,6 @@
<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">"Behörighetsbegäran"</string>
- <string name="screen_overlay_title" msgid="6977038513913222078">"Skärmöverlagring har upptäckts"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Innan du kan ändra den här behörighetsinställningen måste du inaktivera skärmöverlagring under Inställningar &gt; Appar"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Öppna inställningarna"</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_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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Tidslinje för när appar har använt <xliff:g id="PERMGROUP">%1$s</xliff:g> under de senaste sju dagarna"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"När denna app använde behörigheten <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Läs mer"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Läs mer om <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Styr appåtkomst till <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 dag}other{# dagar}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 timme}other{# timmar}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}other{# min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 sek}other{# sek}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# dag}other{# dagar}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# timme}other{# timmar}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# min}other{# min}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# sek}other{# sek}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Alla behörigheter"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"När som helst"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Senaste 7 dagarna"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"De senaste 24 timmarna"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Senaste timmen"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"De senaste 15 minuterna"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Senaste minuten"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Senaste # dagen}other{Senaste # dagarna}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Senaste # timmen}other{Senaste # timmarna}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Senaste # minuten}other{Senaste # minuterna}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Ingen behörighetsanvändning"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Den senaste åtkomsten när som helst"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Den senaste åtkomsten under de senaste sju dagarna"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Behörighetsanvändning under den senaste timmen"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Behörighetsanvändning under den senaste kvarten"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Behörighetsanvändning under den senaste minuten"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Har inte använts under de senaste 24 timmarna"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Har inte använts under de senaste sju dagarna"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Har inte använts under den senaste # dagen}other{Har inte använts under de senaste # dagarna}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Har inte använts under den senaste # timmen}other{Har inte använts under de senaste # timmarna}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Används av 1 app}other{Används av # appar}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Visa alla i översikten"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtreras efter: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Tillåt endast åtkomst till media"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Tillåt alltid"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Tillåt bara när appen används"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Tillåt alltid alla"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Fråga varje gång"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Tillåt inte"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Exakt plats"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Behörigheterna <xliff:g id="PERM_0">%1$s</xliff:g> och <xliff:g id="PERM_1">%2$s</xliff:g> tas bort."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Behörigheter som tas bort: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Hantera behörigheter automatiskt"</string>
- <string name="off" msgid="1438489226422866263">"Av"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Följande behörighet har tagits bort: <xliff:g id="PERMISSION_NAME">%s</xliff:g>"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Följande behörigheter har tagits bort: <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> och <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> och <xliff:g id="NUMBER">%2$s</xliff:g> andra behörigheter har tagits bort"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Appar som inte används"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Följande händer om en app inte används på några månader:\n\n• Behörigheter tas bort för att skydda din data\n• Aviseringar stoppas för att spara batteri\n• Tillfälliga filer tas bort för att frigöra lagringsutrymme\n\nÖppna appen om du vill ge behörigheter och tillåta aviseringar på nytt."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Följande händer om en app inte används på några månader:\n\n• Behörigheter tas bort för att skydda din data\n• Tillfälliga filer tas bort för att frigöra lagringsutrymme\n\nÖppna appen om du vill ge behörigheter på nytt."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Öppnades senast för över <xliff:g id="NUMBER">%s</xliff:g> månader sedan"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Följande händer om en app inte används på en månad:\n\n• Behörigheter tas bort för att skydda din data\n• Tillfälliga filer tas bort för att frigöra lagringsutrymme\n\nÖppna appen om du vill ge behörigheter på nytt."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Öppnades senast för över # månad sedan}other{Öppnades senast för över # månader sedan}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Appen öppnades senast den <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Öppnades senast <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Om du tillåter hantering av alla filer kan appen komma åt, redigera och radera alla filer i det vanliga lagringsutrymmet på denna enhet eller anslutna lagringsenheter. Appen kan komma åt filer utan att du tillfrågas."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Tillåts inte"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Se fler appar som kan komma åt alla filer"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 dag}other{# dagar}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 timme}other{# timmar}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minut}other{# minuter}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 sekund}other{# sekunder}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# timme}other{# timmar}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minut}other{# minuter}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# sekund}other{# sekunder}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Behörighetspåminnelser"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 app som inte används"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> appar som inte används"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Vissa appar har inte använts på några månader. Tryck för att granska."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# app som inte används}other{# appar som inte används}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Behörigheter och tillfälliga filer har tagits bort och aviseringar stoppats. Tryck för att granska."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Granska appar vars behörigheter tagits bort"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"För appar som du inte använt på ett tag har behörigheter och tillfälliga filer tagits bort och aviseringar stoppats."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Granska appar"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Kontrollera de senaste behörigheterna"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Du gav <xliff:g id="APP">%1$s</xliff:g> åtkomst till <xliff:g id="PERMISSION">%2$s</xliff:g> medan du körde"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Du gav <xliff:g id="APP">%1$s</xliff:g> åtkomst till <xliff:g id="PERMISSION_1">%2$s</xliff:g> och <xliff:g id="PERMISSION_2">%3$s</xliff:g> medan du körde"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Behörigheterna har tagits bort för att skydda din integritet"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> har åtkomst till din plats i bakgrunden"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Den här appen har alltid åtkomst till din plats. Tryck här om du vill ändra det."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Granska app med åtkomst till dina aviseringar"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> kan ignorera, agera på och få åtkomst till innehåll i dina aviseringar"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Den här appen kan ignorera, agera på och få åtkomst till innehåll i dina aviseringar. Vissa appar behöver denna åtkomst för att fungera som de ska."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Ta bort åtkomst"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Se fler alternativ"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Åtkomst har tagits bort"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Granska app med fullständig åtkomst till enheten"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> får visa din skärm och utföra åtgärder på enheten. Tillgänglighetsappar behöver denna typ av åtkomst för att fungera som de ska."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Den här appen får visa din skärm och utföra åtgärder på enheten. Tillgänglighetsappar behöver denna typ av åtkomst för att fungera som de ska, men du bör granska appen och se till att du litar på den."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Ta bort åtkomst"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Visa appar med fullständig åtkomst"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Åtkomst har tagits bort"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android-system"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Appbehörigheter har tagits bort av integritetsskäl"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> har inte använts på ett par månader. Tryck för att granska."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> och en app till har inte använts på ett par månader. Tryck för att granska."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> får behörighet att interagera med dina aviseringar och komma åt behörigheterna för Telefon, Sms, Kontakter och Kalender."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> får behörighet att interagera med dina aviseringar och streama dina appar till den anslutna enheten."</string>
<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 göra anteckningar på enheten"</string>
+ <string name="role_notes_search_keywords" msgid="7710756695666744631">"anteckningar"</string>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Styrda behörigheter"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Plats kan kommas åt"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"IT-administratören tillåter att <xliff:g id="APP_NAME">%s</xliff:g> får åtkomst till din plats"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"För appar och tjänster"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Mikrofondata kan fortfarande delas när du ringer ett nödnummer."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Ändra"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Säkerhet och integritet"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Sök"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Säkerhet och integritet"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Skanna enhet"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Stäng"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Ska varningen ignoreras?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Granska säkerhets- och integritetsinställningarna när du vill för att lägga till mer skydd"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Ignorera"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Avbryt"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Inställningar"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Säkerhets- och integritetsstatus. <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">"Säkerhetsinställningar"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Sensorbehörigheter"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Integritetsinställningar"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Behörigheter"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Säkerhet och integritet"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Kontrollera status"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Dina integritetsinställningar"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Fler inställningar"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Kameraåtkomst"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Mikrofonåtkomst"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Behörighet har tagits bort"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Se mer om kameraanvändning"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Se mer om mikrofonanvändning"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Ta bort kamerabehörighet"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Ta bort mikrofonbehörighet"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Se den senaste kameraanvändningen"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Se den senaste mikrofonanvändningen"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Ta bort behörigheten för den här appen"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Ta bort behörigheten för den här appen"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Hantera tjänst"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Hantera behörigheter"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Används just nu av telefonsamtal"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Användes nyligen av <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">"Används just nu av <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">"Användes nyligen av <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Säkerhet och integritet"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Kontrollera status"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Bekräfta"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Tillbaka"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Appen har också åtkomst till andra filer"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Den här appen stöder inte den senaste versionen av Android. Om den här appen inte har åtkomst till musik och ljudfiler har den inte heller åtkomst till foton eller videor."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Den här appen stöder inte den senaste versionen av Android. Om den här appen har åtkomst till foton och videor får den också åtkomst till musik och ljudfiler."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Den här appen stöder inte den senaste versionen av Android. Om den här appen inte har åtkomst till musik och ljudfiler har den inte heller åtkomst till foton eller videor."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Granska app med platsåtkomst i bakgrunden"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> har alltid åtkomst till din plats, också när appen är stängd"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Granska app med platsåtkomst i bakgrunden"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Den här appen har alltid åtkomst till din plats, även när den är stängd.\n\nVissa säkerhets- och nödappar kräver platsåtkomst i bakgrunden för att fungera som de ska."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Åtkomst ändrad"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Se senaste användning av plats"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Integritetsinställningar"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Kameraåtkomst"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Mikrofonåtkomst"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"För appar och tjänster"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"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="2328360561197430695">"Visa appar och tjänster som har åtkomst till din plats"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Visa åtkomst till urklipp"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Visa ett meddelande när appar får åtkomst till text, bilder eller annat som du har kopierat"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Visa lösenord"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Visa tecknen en kort stund medan du skriver"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Rutiner för data kan variera efter appversion, användning, region och din ålder. "<annotation id="link">"Läs mer om datadelning"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Rutiner för data kan variera efter appversion, användning, region och din ålder."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Din platsdata"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Ändra appens åtkomst i "<annotation id="link">"integritetsinställningarna"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Appfunktioner"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analys"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Kommunikation från utvecklaren"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Annonsering eller marknadsföring"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Säkerhet, efterlevnad och att förhindra bedrägeri"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Anpassning"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Kontohantering"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Utvecklarna av dessa appar har angett information om sina datadelningsrutiner i en appbutik. Informationen kan uppdateras med tiden.\n\nDatadelningsrutinerna kan variera efter appversion, användning, region och din ålder."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Läs mer om datadelning"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Din platsdata delas nu med tredje part"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Din platsdata delas nu med tredje part i annonserings- eller marknadsföringssyfte"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Uppdaterades under den senaste dagen}=1{Uppdaterades under den senaste dagen}other{Uppdaterades under de senaste # dagarna}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Inga uppdateringar just nu"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-sw-v33/strings.xml b/PermissionController/res/values-sw-v33/strings.xml
index 45b3d9373..db02c110b 100644
--- a/PermissionController/res/values-sw-v33/strings.xml
+++ b/PermissionController/res/values-sw-v33/strings.xml
@@ -19,4 +19,28 @@
<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 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>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Orodha. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Orodha. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Unahitaji kuchukua hatua. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Kipengee cha orodha. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Funga"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Chaguo za kupanua na kuonyesha"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Kunja"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Badilisha. <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">"Geuza"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Fungua"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Kagua mipangilio"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Mipangilio"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Maelezo"</string>
</resources>
diff --git a/PermissionController/res/values-sw-v34/strings.xml b/PermissionController/res/values-sw-v34/strings.xml
new file mode 100644
index 000000000..be6f2f72b
--- /dev/null
+++ b/PermissionController/res/values-sw-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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">"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, data ya maikrofoni bado inaweza ikashirikiwa unapopiga nambari 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 e2b202dce..83a4ebe03 100644
--- a/PermissionController/res/values-sw/strings.xml
+++ b/PermissionController/res/values-sw/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Rudi nyuma"</string>
<string name="available" msgid="6007778121920339498">"Inaruhusiwa kufikia"</string>
<string name="blocked" msgid="9195547604866033708">"Imezuiwa kufikia"</string>
+ <string name="on" msgid="280241003226755921">"Imewashwa"</string>
+ <string name="off" msgid="1438489226422866263">"Imezimwa"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Ondoa au uzime"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Programu haikupatikana"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Usiruhusu"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Usibadilishe “Wakati programu inatumika”"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Usibadilishe “Wakati huu pekee”"</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Usiruhusu hata hivyo"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Ondoa"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> kati ya <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Imetambua tangazo lililowekelewa juu ya skrini"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Ili kubadilisha mipangilio hii ya ruhusa, ni lazima kwanza uzime tangazo lililowekelewa juu ya skrini kwenye Mipangilio &gt; Programu"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Fungua mipangilio"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Rekodi ya wakati ambapo programu zilitumia <xliff:g id="PERMGROUP">%1$s</xliff:g> katika siku saba zilizopita"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Wakati programu hii ilipotumia ruhusa yako ya <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Pata maelezo zaidi"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Pata maelezo zaidi kuhusu <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Dhibiti ufikiaji wa programu yako kwenye <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{Siku moja}other{Siku #}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{Saa moja}other{Saa #}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{Dak 1}other{Dak #}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{Sek 1}other{Sek #}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{Siku #}other{Siku #}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{Saa #}other{Saa #}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{Dak #}other{Dak #}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{Sek #}other{Sek #}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Ruhusa yoyote"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Wakati wowote"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Siku 7 zilizopita"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Saa 24 zilizopita"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Saa 1 iliyopita"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Dakika 15 zilizopita"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Dakika 1 iliyopita"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Siku # iliyopita}other{Siku # zilizopita}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Saa # iliyopita}other{Saa # zilizopita}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Dakika # iliyopita}other{Dakika # zilizopita}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Hakuna matumizi ya ruhusa"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Zinazotumia zaidi wakati wowote"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Zilizotumiwa zaidi katika siku 7 zilizopita"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Ruhusa zilizotumiwa zaidi katika saa 1 iliyopita"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Matumizi ya ruhusa katika dakika 15 zilizopita."</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Matumizi ya ruhusa katika dakika 1 iliyopita"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Haijatumiwa katika saa 24 zilizopita"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Haijatumiwa katika siku saba zilizopita"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Haijatumiwa katika siku # iliyopita}other{Haijatumiwa katika siku # zilizopita}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Haijatumiwa katika saa # iliyopita}other{Haijatumiwa katika saa # zilizopita}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Imetumiwa na programu moja}other{Imetumiwa na programu #}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Yaone yote kwenye Dashibodi"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Zilizochujwa kulingana na: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Ruhusu ufikiaji wa maudhui pekee"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Ruhusu kila wakati"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Ruhusu tu unapotumia programu"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Ruhusu zote kila wakati"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Uliza kila wakati"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Usiruhusu"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Eneo mahususi"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Ruhusa za <xliff:g id="PERM_0">%1$s</xliff:g> na <xliff:g id="PERM_1">%2$s</xliff:g> zitaondolewa."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Ruhusa zitakazoondolewa: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Dhibiti ruhusa kiotomatiki"</string>
- <string name="off" msgid="1438489226422866263">"Imezimwa"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Ruhusa ya <xliff:g id="PERMISSION_NAME">%s</xliff:g> imeondolewa"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Ruhusa ya <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> na <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> zimeondolewa"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Ruhusa ya <xliff:g id="PERMISSION_NAME">%1$s</xliff:g> na ruhusa zingine <xliff:g id="NUMBER">%2$s</xliff:g> zimeondolewa"</string>
<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="3685907153054355671">"Programu isipotumika kwa miezi kadhaa:\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="7871347400611202595">"Zilizofunguliwa mwisho zaidi ya miezi <xliff:g id="NUMBER">%s</xliff:g> iliyopita"</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 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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Zisizoruhusiwa"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Angalia programu zaidi zinazoweza kufikia faili zote"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{Siku moja}other{Siku #}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{Saa moja}other{Saa #}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{Dakika moja}other{Dakika #}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{Sekunde 1}other{Sekunde #}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{Saa #}other{Saa #}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{Dakika #}other{Dakika #}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{Sekunde #}other{Sekunde #}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Vikumbusho vya ruhusa"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"Programu moja isiyotumika"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"Programu <xliff:g id="NUMBER_OF_APPS">%s</xliff:g> zisizotumika"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Baadhi ya programu hazijatumiwa kwa miezi michache. Gusa ili ukague."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{Programu # isiyotumika}other{Programu # zisizotumika}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Ruhusa na faili za muda zimeondolewa na arifa zimesimamishwa. Gusa ili ukague."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Kagua programu zilizoondolewa ruhusa"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Kwa programu ambazo hujazitumia kwa muda mrefu, ruhusa na faili za muda ziliondolewa na arifa zilisimamishwa."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Kagua programu"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Angalia ruhusa za hivi majuzi"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Wakati wa kuendesha gari, uliipa <xliff:g id="APP">%1$s</xliff:g> uwezo wa kufikia <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Wakati wa kuendesha gari, uliipa <xliff:g id="APP">%1$s</xliff:g> uwezo wa kufikia <xliff:g id="PERMISSION_1">%2$s</xliff:g> na <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Ruhusa zimeondolewa ili kulinda faragha yako"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> ilipata mahali ulipo chinichini"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Programu hii inaweza kufikia maelezo ya mahali ulipo kila wakati. Gusa ili ubadilishe."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Kagua programu inayoweza kufikia arifa zako"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> inaweza kuondoa, kutekeleza na kufikia maudhui ndani ya arifa zako"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Programu hii inaweza kuondoa, kutekeleza na kufikia maudhui ndani ya arifa zako. Baadhi ya programu zinahitaji ufikiaji huu ili zifanye kazi kadiri ilivyokusudiwa."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Ondoa idhini ya kufikia"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Angalia chaguo zaidi"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Idhini ya kufikia imeondolewa"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Kagua programu yenye idhini kamili ya kufikia kifaa"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> inaweza kuona skrini yako na kutekeleza vitendo kwenye kifaa chako. Programu za ufikivu zinahitaji aina hii ya ufikiaji ili zifanye kazi kadiri ilivyokusudiwa."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Programu hii inaweza kuona skrini yako na kutekeleza vitendo kwenye kifaa chako. Programu za ufikivu zinahitaji aina hii ya ufikiaji ili zifanye kazi kama ilivyokusudiwa, lakini kagua programu na uhakikishe kuwa unaiamini."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Ondoa idhini ya kufikia"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Angalia programu zenye ufikiaji kamili"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Idhini ya kufikia imeondolewa"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Mfumo wa Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Ruhusa za programu zimeondolewa ili kulinda faragha"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> haijatumiwa kwa miezi michache. Gusa ili ukague."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> na programu nyingine moja hazijatumiwa kwa miezi michache. Gusa ili ukague."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> itaruhusiwa kushirikiana na arifa zako na kufikia ruhusa za Simu, SMS, Anwani na Kalenda yako."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> itaruhusiwa kufikia arifa zako na kutiririsha programu zako kwenye kifaa kilichounganishwa."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Huduma hii inashiriki picha, maudhui na arifa zako kutoka kwenye simu yako hadi vifaa vingine."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Programu chaguomsingi ya madokezo"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Ruhusa zinazodhibitiwa"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Maelezo ya mahali yanaweza kufikiwa"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Msimamizi wako wa TEHAMA anaruhusu <xliff:g id="APP_NAME">%s</xliff:g> kufikia maelezo ya mahali ulipo"</string>
+ <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>
@@ -496,17 +520,28 @@
<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_sensor_button_label" msgid="6742092634984289658">"Badilisha"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Usalama na Faragha"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Tafuta"</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>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Ondoa"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Ungependa kuondoa arifa hii?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Kagua mipangilio yako ya usalama na faragha wakati wowote ili kuongeza ulinzi zaidi"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Ondoa"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Ghairi"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Mipangilio"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Hali ya usalama na faragha. <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">"Mipangilio ya Usalama"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Ruhusa za Kitambuzi"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Vidhibiti vya Faragha"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Ruhusa"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Usalama na faragha"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Kagua hali"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Vidhibiti vyako vya faragha"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Mipangilio zaidi"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Ufikiaji wa kamera"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Ufikiaji wa maikrofoni"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Ruhusa imeondolewa"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Angalia matumizi zaidi ya kamera"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Angalia matumizi zaidi ya maikrofoni"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Ondoa ruhusa ya kamera"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Ondoa ruhusa ya maikrofoni"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Angalia matumizi ya hivi karibuni ya kamera"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Angalia matumizi ya hivi karibuni ya maikrofoni"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Ondolea programu hii ruhusa"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Ondolea programu hii ruhusa"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Dhibiti huduma"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Dhibiti ruhusa"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Inatumiwa na simu"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Ilitumiwa hivi karibuni na <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">"Inatumiwa na <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">"Ilitumiwa hivi karibuni na <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Usalama na Faragha"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Kagua hali"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Thibitisha"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Nyuma"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Pia, uwezo wa kufikia faili zingine utaruhusiwa"</string>
@@ -537,4 +570,53 @@
<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 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 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>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Vidhibiti vya faragha"</string>
+ <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="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>
+ <string name="show_password_title" msgid="2877269286984684659">"Onyesha manenosiri"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Onyesha herufi kwa muda mfupi unapoandika"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Kanuni za data zinaweza kutofautiana kulingana na toleo la programu yako, matumizi, eneo na umri wako. "<annotation id="link">"Maelezo zaidi kuhusu kushiriki data"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Kanuni za data zinaweza kutofautiana kulingana na toleo la programu yako, matumizi, eneo na umri wako."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Data ya mahali ulipo"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Badilisha ufikiaji wa programu hii kwenye "<annotation id="link">"mipangilio ya faragha"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Utendaji wa programu"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Takwimu"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Mawasiliano ya msanidi programu"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Utangazaji au uuzaji"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Kuzuia ulaghai, usalama na kutii"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Kuweka mapendeleo"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Usimamizi wa akaunti"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Wasanidi wa programu hizi wametoa maelezo kuhusu mbinu zao za kushiriki data kwenye duka la programu. Wanaweza kuyasasisha kadiri muda unavyosonga.\n\nMbinu za kushiriki data zinaweza kutofautiana kulingana na toleo la programu, matumizi, eneo na umri wako."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Pata maelezo kuhusu kushiriki data"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Sasa data ya mahali ulipo inashirikiwa na wengine"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Sasa data ya mahali ulipo inashirikiwa na wengine kwa madhumuni ya utangazaji au uuzaji"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Imesasisha ndani ya siku iliyopita}=1{Imesasisha ndani ya siku iliyopita}other{Imesasisha ndani ya siku #}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Hakuna masasisho kwa wakati huu"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-ta-v33/strings.xml b/PermissionController/res/values-ta-v33/strings.xml
index 8cce66e39..41b6d0923 100644
--- a/PermissionController/res/values-ta-v33/strings.xml
+++ b/PermissionController/res/values-ta-v33/strings.xml
@@ -19,4 +19,28 @@
<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_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>
+ <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>
+ <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{விரிவாக்கி மேலும் ஒரு விழிப்பூட்டலைப் பாருங்கள்}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">"பாதுகாப்பு &amp; தனியுரிமை விரைவு அமைப்புகள்"</string>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"மூடுக"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"விருப்பங்களை விரிவாக்கிக் காட்டு"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"சுருக்கு"</string>
+ <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_gear_label" msgid="5175877094379694098">"அமைப்புகள்"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"தகவல்கள்"</string>
</resources>
diff --git a/PermissionController/res/values-ta-v34/strings.xml b/PermissionController/res/values-ta-v34/strings.xml
new file mode 100644
index 000000000..b92b9a184
--- /dev/null
+++ b/PermissionController/res/values-ta-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="location_settings" msgid="8863940440881290182">"இருப்பிட அணுகல்"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"ஆப்ஸ் மற்றும் சேவைகளுக்கு. இந்த அமைப்பு முடக்கப்பட்டிருந்தாலும் அவசர உதவி எண்ணை நீங்கள் அழைக்கும்போது மைக்ரோஃபோன் தரவு பகிரப்படலாம்"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"ஆப்ஸ் &amp; சேவைகளுக்கு"</string>
+</resources>
diff --git a/PermissionController/res/values-ta/strings.xml b/PermissionController/res/values-ta/strings.xml
index ee306172f..ad2bea8a3 100644
--- a/PermissionController/res/values-ta/strings.xml
+++ b/PermissionController/res/values-ta/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"எப்போதும் அனைத்தையும் அனுமதி"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"\'திரை மேலடுக்கு\' ஆனில் உள்ளது"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"இந்த அனுமதியை மாற்ற முதலில் \'அமைப்புகள் &gt; ஆப்ஸ்’ என்பதற்குச் சென்று \'திரை மேலடுக்கை\' ஆஃப் செய்யவும்"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"அமைப்புகளைத் திற"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 நாள்}other{# நாட்கள்}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 மணிநேரம்}other{# மணிநேரம்}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 நிமிடம்}other{# நிமிடங்கள்}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 வினாடி}other{# வினாடிகள்}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# நாள்}other{# நாட்கள்}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# மணிநேரம்}other{# மணிநேரம்}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# நிமிடம்}other{# நிமிடங்கள்}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# வினாடி}other{# வினாடிகள்}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"அனுமதி எதுவாயினும்"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"எந்த நேரமும்"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"கடந்த 7 நாட்கள்"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"கடந்த 24 மணிநேரம்"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"கடந்த ஒரு மணிநேரம்"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"கடந்த 15 நிமிடங்கள்"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"கடந்த 1 நிமிடத்தில்"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{கடந்த # நாள்}other{கடந்த # நாட்கள்}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{கடந்த # மணிநேரம்}other{கடந்த # மணிநேரம்}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{கடந்த # நிமிடம்}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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"கடந்த 24 மணிநேரத்தில் பயன்படுத்தப்படவில்லை"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"கடந்த 7 நாட்களில் பயன்படுத்தப்படவில்லை"</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_view_details" msgid="6675335735468752787">"டாஷ்போர்டில் அனைத்தையும் காட்டு"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"இதன்படி வடிகட்டப்பட்டது: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"எப்போதும் அனைத்தையும் அனுமதி"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"ஒவ்வொரு முறையும் கேள்"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"அனுமதிக்க வேண்டாம்"</string>
<string name="precise_image_description" msgid="6349638632303619872">"துல்லியமான இருப்பிடம்"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g>, <xliff:g id="PERM_1">%2$s</xliff:g> அனுமதிகள் அகற்றப்படும்."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"அகற்றப்படவிருக்கும் அனுமதிகள்: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"அனுமதிகளைத் தானாகவே நிர்வகித்தல்"</string>
- <string name="off" msgid="1438489226422866263">"ஆஃப்"</string>
<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_tv_summary" msgid="3685907153054355671">"ஓர் ஆப்ஸைச் சில மாதங்கள் பயன்படுத்தாமல் இருந்தால்:\n\n• உங்கள் தரவைப் பாதுகாக்கும் பொருட்டு அனுமதிகள் அகற்றப்படும்\n• சேமிப்பிடத்தைக் காலியாக்கும் பொருட்டு தற்காலிக ஃபைல்கள் அகற்றப்படும்\n\nமீண்டும் அனுமதிகளை வழங்க ஆப்ஸைத் திறக்கவும்."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"கடைசியாக <xliff:g id="NUMBER">%s</xliff:g> மாதங்களுக்கு முன்பு திறக்கப்பட்டது"</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="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,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 மணிநேரம்}other{# மணிநேரம்}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 நிமிடம்}other{# நிமிடங்கள்}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 வினாடி}other{# வினாடிகள்}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# மணிநேரம்}other{# மணிநேரம்}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<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_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_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> &amp; <xliff:g id="PERMISSION_2">%3$s</xliff:g> அணுகலை <xliff:g id="APP">%1$s</xliff:g> ஆப்ஸுக்கு வழங்கியுள்ளீர்கள்"</string>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android சிஸ்டம்"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"தனியுரிமையைப் பாதுகாக்க ஆப்ஸ் அனுமதிகள் அகற்றப்பட்டன"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"கடந்த சில மாதங்களில் <xliff:g id="APP_NAME">%s</xliff:g> ஆப்ஸ் பயன்படுத்தப்படவில்லை. பார்க்க தட்டவும்."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"கடந்த சில மாதங்களில் <xliff:g id="APP_NAME">%s</xliff:g> ஆப்ஸும் 1 பிற ஆப்ஸும் பயன்படுத்தப்படவில்லை. பார்க்க தட்டவும்."</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"குறிப்புகள்"</string>
<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>
@@ -452,6 +475,7 @@
<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_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_microphone" msgid="2825208549114811299">"ஆடியோ ரெக்கார்டு செய்ய &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>
@@ -474,8 +498,8 @@
<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="permgrouprequest_notifications" msgid="6396739062335106181">"உங்களுக்கு அறிவிப்புகளை அனுப்ப &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="1438871159268985993">"இருப்பிடத்தை அணுகலாம்"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"<xliff:g id="APP_NAME">%s</xliff:g> ஆப்ஸ் உங்கள் இருப்பிடத்தை அணுக உங்கள் IT நிர்வாகி அனுமதித்துள்ளார்"</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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"ஆப்ஸ் &amp; சேவைகளுக்கு"</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="7514620345152008005">"பாதுகாப்பு &amp; தனியுரிமை"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"ஸ்கேன் செய்"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"பாதுகாப்பு &amp; தனியுரிமை"</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_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="sensor_permissions_qs" msgid="4365989229426201877">"சென்சார் அனுமதிகள்"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"தனியுரிமைக் கட்டுப்பாடுகள்"</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_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="microphone_toggle_label_qs" msgid="8132912469813396552">"மைக்ரோஃபோன் அணுகல்"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"அனுமதி அகற்றப்பட்டது"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"கூடுதல் கேமரா பயன்பாட்டைக் காண்க"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"கூடுதல் மைக்ரோஃபோன் பயன்பாட்டைக் காண்க"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"கேமரா அனுமதியை அகற்று"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"மைக்ரோஃபோன் அனுமதியை அகற்று"</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="manage_service_qs" msgid="7862555549364153805">"சேவையை நிர்வகியுங்கள்"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"அனுமதிகளை நிர்வகியுங்கள்"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"மொபைல் அழைப்பால் பயன்படுத்தப்படுகிறது"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"பாதுகாப்பு &amp; தனியுரிமை"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"நிலையைச் சரிபாருங்கள்"</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>
@@ -537,4 +570,53 @@
<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_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">"ஆப்ஸ் &amp; சேவைகளுக்கு"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"ஆப்ஸ் &amp; சேவைகளுக்கு. இந்த அமைப்பு முடக்கப்பட்டிருந்தாலும் அவசர உதவி எண்ணை நீங்கள் அழைக்கும்போது மைக்ரோஃபோன் தரவு பகிரப்படலாம்."</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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"டெவெலப்பர் தகவல்தொடர்புகள்"</string>
+ <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="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="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="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>
</resources>
diff --git a/PermissionController/res/values-te-v33/strings.xml b/PermissionController/res/values-te-v33/strings.xml
index d9dbdfd19..7245ac078 100644
--- a/PermissionController/res/values-te-v33/strings.xml
+++ b/PermissionController/res/values-te-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"మీకు నోటిఫికేషన్‌లను పంపడానికి ఈ యాప్ అనుమతించబడుతుంది, అలాగే ఈ యాప్‌నకు మీ కెమెరా, కాంటాక్ట్‌లు, మైక్రోఫోన్, ఫోన్, SMSకు యాక్సెస్ ఇవ్వబడుతుంది"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"మీకు నోటిఫికేషన్‌లను పంపడానికి ఈ యాప్ అనుమతించబడుతుంది, అలాగే ఈ యాప్‌నకు మీ కెమెరా, కాంటాక్ట్‌లు, Files, మైక్రోఫోన్, ఫోన్, SMSకు యాక్సెస్ ఇవ్వబడుతుంది"</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>
+ <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>
+ <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{విస్తరించి, మరొక అలర్ట్‌ను చూడండి}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"మూసివేయండి"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"ఆప్షన్‌లను విస్తరించండి ఎంపికలను చూపించండి"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"కుదించండి"</string>
+ <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_gear_label" msgid="5175877094379694098">"సెట్టింగ్‌లు"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"సమాచారం"</string>
</resources>
diff --git a/PermissionController/res/values-te-v34/strings.xml b/PermissionController/res/values-te-v34/strings.xml
new file mode 100644
index 000000000..c8281ea1d
--- /dev/null
+++ b/PermissionController/res/values-te-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"సెక్యూరిటీ &amp; గోప్యత"</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="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-te/strings.xml b/PermissionController/res/values-te/strings.xml
index 425d46281..dd105ae85 100644
--- a/PermissionController/res/values-te/strings.xml
+++ b/PermissionController/res/values-te/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,11 +32,16 @@
<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_always_allow_all" msgid="1719900027660252167">"ఎల్లవేళలా అన్నీ అనుమతించండి"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"స్క్రీన్ అతివ్యాప్తి గుర్తించబడింది"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"ఈ అనుమతి సెట్టింగ్‌ను మార్చడానికి, మీరు సెట్టింగ్‌లు &gt; యాప్‌ల నుండి స్క్రీన్ అతివ్యాప్తిని ఆఫ్ చేయాలి"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"సెట్టింగ్‌లను తెరువు"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 రోజు}other{# రోజులు}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 గంట}other{# గంటలు}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 నిమి}other{# నిమిషాలు}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 సెకను}other{# సెకన్లు}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# రోజు}other{# రోజులు}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# గంట}other{# గంటలు}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# నిమి}other{# నిమిషాలు}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# సెక}other{# సెకన్లు}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"ఏ అనుమతి అయినా"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"ఎప్పుడైనా"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"గత 7 రోజులు"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"గత 24 గంటలు"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"గత 1 గంట"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"గత 15 నిమిషాలు"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"చివరి 1 నిమిషం"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{గడిచిన # రోజులో}other{గడిచిన # రోజులలో}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{గడిచిన # గంటలో}other{గడిచిన # గంటలలో}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{గడిచిన # నిమిషంలో}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>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"గడిచిన ఒక గంటలో అనుమతి వినియోగించబడింది"</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">"గత నిమిషంలో అనుమతి వినియోగించబడింది"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"గత 24 గంటలలో ఉపయోగించలేదు"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"గత 7 రోజుల్లో ఉపయోగించలేదు"</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_view_details" msgid="6675335735468752787">"అన్నింటినీ డ్యాష్‌బోర్డ్‌లో చూడండి"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"దీని ద్వారా ఫిల్టర్ చేయబడింది: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"అన్నింటినీ ఎల్లవేళలా అనుమతించండి"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"ప్రతిసారి అడగాలి"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"అనుమతించవద్దు"</string>
<string name="precise_image_description" msgid="6349638632303619872">"ఖచ్చితమైన లొకేషన్"</string>
@@ -192,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>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> అలాగే <xliff:g id="PERM_1">%2$s</xliff:g> అనుమతులు తీసివేయబడతాయి."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"తీసివేయబడే అనుమతులు: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"అనుమతులను ఆటోమేటిక్‌గా నిర్వహించండి"</string>
- <string name="off" msgid="1438489226422866263">"ఆఫ్"</string>
<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_tv_summary" msgid="3685907153054355671">"యాప్‌ను కొన్ని నెలలు ఉపయోగించకపోతే:\n\n• మీ డేటాను రక్షించడానికి అనుమతులు తీసివేయబడతాయి\n• స్పేస్‌ను ఖాళీ చేయడానికి తాత్కాలిక ఫైళ్లు తీసివేయబడతాయి\n\nఅనుమతులను మళ్లీ అనుమతించడానికి, యాప్‌ను తెరవండి."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"చివరిసారిగా <xliff:g id="NUMBER">%s</xliff:g> నెలల కంటే ముందు తెరవబడింది"</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>
@@ -251,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 గంట}other{# గంటలు}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 నిమిషం}other{# నిమిషాలు}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 సెకను}other{# సెకన్లు}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# గంట}other{# గంటలు}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<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_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_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>
<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>
@@ -276,6 +282,19 @@
<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_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">"This app can view your screen and perform actions on your device. Accessibility apps need this type of access to function as intended, but check the app and make sure you trust it."</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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android సిస్టమ్"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"గోప్యతను కాపాడడానికి యాప్ అనుమతులు తీసివేయబడ్డాయి"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"కొన్ని నెలలుగా <xliff:g id="APP_NAME">%s</xliff:g> ఉపయోగంలో లేదు. రివ్యూ చేయడానికి నొక్కండి."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> మరియు మరో 1 యాప్ కొన్ని నెలలుగా ఉపయోగంలో లేవు. రివ్యూ చేయడానికి నొక్కండి."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"మీ నోటిఫికేషన్‌లతో ఇంటరాక్ట్ అవ్వడానికి అలాగే మీ ఫోన్, SMS, కాంటాక్ట్‌లు అలాగే Calendar అనుమతులను యాక్సెస్ చేయడానికి <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_search_keywords" msgid="7710756695666744631">"నోట్స్"</string>
<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>
@@ -452,6 +475,7 @@
<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_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_microphone" msgid="2825208549114811299">"ఆడియోను రికార్డ్ చేయడానికి &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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"నియంత్రణలో ఉన్న అనుమతులు"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"లొకేషన్‌ను యాక్సెస్ చేయవచ్చు"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"మీ IT అడ్మిన్ మీ లొకేషన్‌ను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"సెక్యూరిటీ &amp; గోప్యత"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"స్కాన్ చేయండి"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"సెక్యూరిటీ &amp; గోప్యత"</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_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="sensor_permissions_qs" msgid="4365989229426201877">"సెన్సార్ అనుమతులు"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"గోప్యతా కంట్రోల్స్"</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_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="microphone_toggle_label_qs" msgid="8132912469813396552">"మైక్ యాక్సెస్"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"అనుమతి తీసివేయబడింది"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"మరింత కెమెరా వినియోగాన్ని చూడండి"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"మరింత మైక్రోఫోన్ వినియోగాన్ని చూడండి"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"కెమెరా అనుమతిని తీసివేయండి"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"మైక్రోఫోన్ అనుమతిని తీసివేయండి"</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="manage_service_qs" msgid="7862555549364153805">"సర్వీస్‌ను మేనేజ్ చేయండి"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"అనుమతులను మేనేజ్ చేయండి"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"ఫోన్ కాల్ ద్వారా ఉపయోగించబడుతోంది"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"సెక్యూరిటీ &amp; గోప్యత"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"స్టేటస్‌ను చెక్ చేయండి"</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>
@@ -537,4 +570,53 @@
<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">"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_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="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">"డేటా షేరింగ్ &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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"డెవలపర్ కమ్యూనికేషన్స్"</string>
+ <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="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="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="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>
</resources>
diff --git a/PermissionController/res/values-television/themes.xml b/PermissionController/res/values-television/themes.xml
index 12d03b284..2c239eb28 100644
--- a/PermissionController/res/values-television/themes.xml
+++ b/PermissionController/res/values-television/themes.xml
@@ -56,15 +56,15 @@
</style>
<style name="GrantPermissions.ActionItem">
- <item name="android:gravity">left|center_vertical</item>
+ <item name="android:gravity">start|center_vertical</item>
<item name="android:fontFamily">sans-serif-condensed</item>
<item name="android:textSize">14sp</item>
<item name="android:textColor">@color/tv_grant_button_text_color</item>
<item name="android:lineSpacingMultiplier">1</item>
<item name="android:background">@drawable/dialog_action_button_background</item>
<item name="android:layout_margin">@dimen/action_dialog_button_margin</item>
- <item name="android:paddingLeft">@dimen/action_dialog_button_padding_left</item>
- <item name="android:paddingRight">@dimen/action_dialog_button_padding_right</item>
+ <item name="android:paddingStart">@dimen/action_dialog_button_padding_left</item>
+ <item name="android:paddingEnd">@dimen/action_dialog_button_padding_right</item>
<item name="android:paddingTop">@dimen/action_dialog_button_padding_top</item>
<item name="android:paddingBottom">@dimen/action_dialog_button_padding_bottom</item>
<item name="android:minHeight">@dimen/action_dialog_button_min_height</item>
diff --git a/PermissionController/res/values-th-v33/strings.xml b/PermissionController/res/values-th-v33/strings.xml
index 1093f50e8..1270c9c1c 100644
--- a/PermissionController/res/values-th-v33/strings.xml
+++ b/PermissionController/res/values-th-v33/strings.xml
@@ -19,4 +19,28 @@
<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="work_policy_title" msgid="832967780713677409">"ข้อมูลนโยบายงาน"</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>
+ <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{ขยายและดูการแจ้งเตือนอีก 1 รายการ}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"ปิด"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"ขยายและแสดงตัวเลือก"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"ยุบ"</string>
+ <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_gear_label" msgid="5175877094379694098">"การตั้งค่า"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"ข้อมูล"</string>
</resources>
diff --git a/PermissionController/res/values-th-v34/strings.xml b/PermissionController/res/values-th-v34/strings.xml
new file mode 100644
index 000000000..8e6bae837
--- /dev/null
+++ b/PermissionController/res/values-th-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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 9960ecc18..c6b80ea1f 100644
--- a/PermissionController/res/values-th/strings.xml
+++ b/PermissionController/res/values-th/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"อนุญาตทั้งหมดตลอดเวลา"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"ตรวจพบการวางซ้อนหน้าจอ"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"หากต้องการเปลี่ยนแปลงการตั้งค่าสิทธิ์นี้ ก่อนอื่น คุณต้องปิดการวางซ้อนหน้าจอที่การตั้งค่า &gt; แอป"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"เปิดการตั้งค่า"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 วัน}other{# วัน}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 ชั่วโมง}other{# ชั่วโมง}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 นาที}other{# นาที}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 วินาที}other{# วินาที}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# วัน}other{# วัน}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# ชั่วโมง}other{# ชั่วโมง}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# นาที}other{# นาที}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# วินาที}other{# วินาที}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"ทุกสิทธิ์"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"ทุกเวลา"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"7 วันที่ผ่านมา"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"24 ชั่วโมงที่ผ่านมา"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"1 ชั่วโมงที่ผ่านมา"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"15 นาทีที่ผ่านมา"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"1 นาทีที่ผ่านมา"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{# วันที่ผ่านมา}other{# วันที่ผ่านมา}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{# ชั่วโมงที่ผ่านมา}other{# ชั่วโมงที่ผ่านมา}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{# นาทีที่ผ่านมา}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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"ไม่ได้ใช้ใน 24 ชั่วโมงที่ผ่านมา"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"ไม่ได้ใช้ใน 7 วันที่ผ่านมา"</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_view_details" msgid="6675335735468752787">"ดูทั้งหมดในหน้าแดชบอร์ด"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"กรองตาม: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"อนุญาตทั้งหมดเสมอ"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"ถามทุกครั้ง"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"ไม่อนุญาต"</string>
<string name="precise_image_description" msgid="6349638632303619872">"ตำแหน่งที่แน่นอน"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"ระบบจะนำสิทธิ์เข้าถึง<xliff:g id="PERM_0">%1$s</xliff:g>และ<xliff:g id="PERM_1">%2$s</xliff:g>ออก"</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"สิทธิ์ที่จะนำออก ได้แก่ การเข้าถึง<xliff:g id="PERMS">%1$s</xliff:g>"</string>
<string name="auto_manage_title" msgid="7693181026874842935">"จัดการสิทธิ์โดยอัตโนมัติ"</string>
- <string name="off" msgid="1438489226422866263">"ปิด"</string>
<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">"จะมีการดำเนินการต่อไปนี้หากไม่ได้ใช้แอปเป็นเวลา 2-3 เดือน\n\n• สิทธิ์จะถูกนำออกเพื่อปกป้องข้อมูลของคุณ\n• การแจ้งเตือนจะหยุดลงเพื่อประหยัดแบตเตอรี่\n• ไฟล์ชั่วคราวจะถูกนำออกเพื่อเพิ่มพื้นที่ว่าง\n\nเปิดแอปเพื่ออนุญาตสิทธิ์และการแจ้งเตือนอีกครั้ง"</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"จะมีการดำเนินการต่อไปนี้หากไม่ได้ใช้แอปเป็นเวลา 2-3 เดือน\n\n• สิทธิ์จะถูกนำออกเพื่อปกป้องข้อมูลของคุณ\n• ไฟล์ชั่วคราวจะถูกนำออกเพื่อเพิ่มพื้นที่ว่าง\n\nเปิดแอปเพื่ออนุญาตสิทธิ์อีกครั้ง"</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"เปิดล่าสุดนานกว่า <xliff:g id="NUMBER">%s</xliff:g> เดือนที่ผ่านมา"</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>
<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>
@@ -251,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 ชั่วโมง}other{# ชั่วโมง}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 นาที}other{# นาที}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 วินาที}other{# วินาที}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# ชั่วโมง}other{# ชั่วโมง}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"บางแอปไม่มีการใช้งานมา 2-3 เดือนแล้ว แตะเพื่อตรวจสอบ"</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>
+ <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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"ระบบ Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"ระบบนำสิทธิ์ของแอปออกเพื่อปกป้องความเป็นส่วนตัว"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> ไม่มีการใช้งานมา 2-3 เดือนแล้ว แตะเพื่อตรวจสอบ"</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> และอีก 1 แอปไม่มีการใช้งานมา 2-3 เดือนแล้ว แตะเพื่อตรวจสอบ"</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"บันทึก"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"สิทธิ์ที่มีการควบคุม"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"เข้าถึงตำแหน่งได้"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"ผู้ดูแลระบบไอทีอนุญาตให้ <xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"ความปลอดภัยและความเป็นส่วนตัว"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"สแกน"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"สิทธิ์ใช้เซ็นเซอร์"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"การควบคุมความเป็นส่วนตัว"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"นำสิทธิ์ออกแล้ว"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"ดูการใช้งานกล้องเพิ่มเติม"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"ดูการใช้งานไมโครโฟนเพิ่มเติม"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"นำสิทธิ์เข้าถึงกล้องออก"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"นำสิทธิ์เข้าถึงไมโครโฟนออก"</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="manage_service_qs" msgid="7862555549364153805">"จัดการบริการ"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"จัดการสิทธิ์"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"ใช้อยู่โดยการโทร"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"ความปลอดภัยและความเป็นส่วนตัว"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"ตรวจสอบสถานะ"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"การสื่อสารจากนักพัฒนาแอป"</string>
+ <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="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="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">"นักพัฒนาแอปเหล่านี้ได้ให้ข้อมูลเกี่ยวกับแนวทางปฏิบัติในการแชร์ข้อมูลไว้ใน App Store นักพัฒนาแอปอาจอัปเดตข้อมูลนี้เมื่อเวลาผ่านไป\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="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>
</resources>
diff --git a/PermissionController/res/values-tl-v33/strings.xml b/PermissionController/res/values-tl-v33/strings.xml
index 4e6955fcd..0c23a30f7 100644
--- a/PermissionController/res/values-tl-v33/strings.xml
+++ b/PermissionController/res/values-tl-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Papayagan ang app na ito na magpadala sa iyo ng Mga Notification, at mabibigyan ito ng access sa iyong Camera, Mga Contact, Mikropono, Telepono, at SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Papayagan ang app na ito na magpadala sa iyo ng Mga Notification, at mabibigyan ito ng access sa iyong Camera, Mga Contact, Mga File, Mikropono, Telepono, at SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Maa-access ng mga app na mayroon ng pahintulot na ito ang lahat ng file sa device na ito"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Impormasyon tungkol sa iyong patakaran sa trabaho"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Pinapamahalaan ng iyong IT admin ang mga setting"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"I-expand at ipakita ang listahan"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"I-collapse ang listahan at itago ang mga setting"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Listahan. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Listahan. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Mga kailangang pagkilos. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Item sa listahan. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Isara"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"I-expand at ipakita ang mga opsyon"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"I-collapse"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Lumipat. <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">"I-toggle"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Buksan"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Suriin ang mga setting"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Mga Setting"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Impormasyon"</string>
</resources>
diff --git a/PermissionController/res/values-tl-v34/strings.xml b/PermissionController/res/values-tl-v34/strings.xml
new file mode 100644
index 000000000..4ed588f80
--- /dev/null
+++ b/PermissionController/res/values-tl-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Seguridad at privacy"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Mga Kontrol"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Pamahalaan ang access ng app sa data ng kalusugan"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Access sa lokasyon"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Para sa mga app at serbisyo. Kung naka-off ang setting na ito, posible pa ring ibahagi ang data ng mikropono kapag tumawag ka sa isang pang-emergency na numero"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Para sa mga app at serbisyo"</string>
+</resources>
diff --git a/PermissionController/res/values-tl/strings.xml b/PermissionController/res/values-tl/strings.xml
index afffffaf4..7ed715c01 100644
--- a/PermissionController/res/values-tl/strings.xml
+++ b/PermissionController/res/values-tl/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Bumalik"</string>
<string name="available" msgid="6007778121920339498">"Available"</string>
<string name="blocked" msgid="9195547604866033708">"Naka-block"</string>
+ <string name="on" msgid="280241003226755921">"Naka-on"</string>
+ <string name="off" msgid="1438489226422866263">"I-off"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"I-uninstall o i-disable"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Hindi makita ang app"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Huwag payagan"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Panatilihin ang “Habang ginagamit ang app”"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Panatilihing “Sa pagkakataong ito lang”"</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Huwag pa ring payagan"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"I-dismiss"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> sa <xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Natukoy ang screen overlay"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Para baguhin ang setting ng pahintulot na ito, kailangan mo munang i-off ang screen overlay sa Mga Setting &gt; Mga App"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Buksan ang mga setting"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Timeline ng kung kailan ginamit ng mga app ang iyong <xliff:g id="PERMGROUP">%1$s</xliff:g> sa nakalipas na 7 araw"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Kung kailan ginamit ng app na ito ang iyong<xliff:g id="PERMGROUP">%1$s</xliff:g> pahintulot"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Matuto pa"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Matuto pa tungkol sa <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Kontrolin ang access ng app sa iyong <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 araw}one{# araw}other{# na araw}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 oras}one{# oras}other{# na oras}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 min}one{# min}other{# na min}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 segundo}one{# segundo}other{# na segundo}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# araw}one{# araw}other{# na araw}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# oras}one{# oras}other{# na oras}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# minuto}one{# minuto}other{# na minuto}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# segundo}one{# segundo}other{# na segundo}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Anumang pahintulot"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Anumang oras"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Nakalipas na 7 araw"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Nakalipas na 24 na oras"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Nakalipas na 1 oras"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Nakalipas na 15 minuto"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Nakalipas na 1 minuto"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Nakalipas na # araw}one{Nakalipas na # araw}other{Nakalipas na # na araw}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Nakalipas na # oras}one{Nakalipas na # oras}other{Nakalipas na # na oras}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Nakalipas na # minuto}one{Nakalipas na # minuto}other{Nakalipas na # na minuto}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Walang paggamit ng pahintulot"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Pinakakamakailang pag-access anumang oras"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Pinakakamakailang pag-access sa nakaraang 7 araw"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Paggamit ng pahintulot sa loob ng nakaraang 1 oras"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Paggamit ng pahintulot sa nakaraang 15 minuto"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Paggamit ng pahintulot sa nakaraang 1 minuto"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Hindi ginamit sa nakalipas na 24 na oras"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Hindi ginamit sa nakalipas na 7 araw"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Hindi ginamit sa nakalipas na # araw}one{Hindi ginamit sa nakalipas na # araw}other{Hindi ginamit sa nakalipas na # na araw}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Hindi ginamit sa nakalipas na # oras}one{Hindi ginamit sa nakalipas na # oras}other{Hindi ginamit sa nakalipas na # na oras}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Ginagamit ng 1 app}one{Ginagamit ng # app}other{Ginagamit ng # na app}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Tingnan lahat sa Dashboard"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Na-filter ng: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Payagan lang ang pag-access ng media"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Payagan sa lahat ng oras"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Payagan lang habang ginagamit ang app"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Palaging pahintulutan lahat"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Magtanong palagi"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Huwag payagan"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Eksaktong lokasyon"</string>
@@ -192,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>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Maaalis ang mga pahintulot sa <xliff:g id="PERM_0">%1$s</xliff:g> at <xliff:g id="PERM_1">%2$s</xliff:g>."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Mga pahintulot na maaalis: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Awtomatikong pamahalaan ang pahintulot"</string>
- <string name="off" msgid="1438489226422866263">"I-off"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Inalis ang pahintulot na <xliff:g id="PERMISSION_NAME">%s</xliff:g>"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Inalis ang mga pahintulot na <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> at <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g>"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Inalis ang <xliff:g id="PERMISSION_NAME">%1$s</xliff:g> at <xliff:g id="NUMBER">%2$s</xliff:g> pang pahintulot"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Mga hindi ginagamit na app"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Kung hindi ginamit ang isang app sa loob ng ilang buwan:\n\n• Aalisin ang mga pahintulot para maprotektahan ang iyong data\n• Ihihinto ang mga notification para makatipid sa baterya\n• Aalisin ang mga pansamantalang file para magbakante ng space\n\nPara payagan ulit ang mga pahintulot at notification, buksan ang app."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Kung hindi ginamit ang isang app sa loob ng ilang buwan:\n\n• Aalisin ang mga pahintulot para maprotektahan ang iyong data\n• Aalisin ang mga pansamantalang file para magbakante ng space\n\nPara payagan ulit ang mga pahintulot, buksan ang app."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Huling binuksan mahigit <xliff:g id="NUMBER">%s</xliff:g> (na) buwan na ang nakakalipas"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Kung hindi ginamit ang isang app sa loob ng isang buwan:\n\n• Aalisin ang mga pahintulot para maprotektahan ang iyong data\n• Aalisin ang mga pansamantalang file para magbakante ng space\n\nPara payagan ulit ang mga pahintulot, buksan ang app."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Huling binuksan mahigit # buwan na ang nakalipas}one{Huling binuksan mahigit # buwan na ang nakalipas}other{Huling binuksan mahigit # na buwan na ang nakalipas}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Huling binuksan ang app noong <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="last_opened_summary_short" msgid="1646067226191176825">"Huling binuksan noong <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="app_permission_footer_special_file_access" msgid="1884202176147657788">"Kung papayagan mo ang pamamahala ng lahat ng file, magagawa ng app na ito na i-access, baguhin, at i-delete ang anumang file na nasa karaniwang storage sa device na ito o mga nakakonektang storage device. Posibleng mag-access ng mga file ang app nang hindi ka tinatanong."</string>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Hindi pinapayagan"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Tumingin pa ng mga app na puwedeng mag-access ng lahat ng file"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 araw}one{# araw}other{# na araw}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 oras}one{# oras}other{# na oras}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 minuto}one{# minuto}other{# na minuto}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 segundo}one{# segundo}other{# na segundo}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# oras}one{# oras}other{# na oras}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# minuto}one{# minuto}other{# na minuto}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# segundo}one{# segundo}other{# na segundo}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Mga paalala sa pahintulot"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 hindi ginagamit na app"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> (na) hindi ginagamit na app"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"May ilang app na ilang buwan nang hindi ginagamit. I-tap para suriin."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# hindi ginagamit na app}one{# hindi ginagamit na app}other{# na hindi ginagamit na app}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Inalis ang mga pahintulot at pansamantalang file at inihinto ang mga notification. I-tap para suriin."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Suriin ang mga app na inalisan ng pahintulot"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Para sa mga app na matagal mo nang hindi nagamit, inalis ang mga pahintulot at pansamantalang file at inihinto ang mga notification."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Suriin ang mga app"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Tingnan ang mga kamakailang pahintulot"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Habang nagmamaneho, binigyan mo ng access ang <xliff:g id="APP">%1$s</xliff:g> na <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Habang nagmamaneho, binigyan mo ng access ang <xliff:g id="APP">%1$s</xliff:g> na <xliff:g id="PERMISSION_1">%2$s</xliff:g> at <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Inalis ang mga pahintulot para protektahan ang iyong privacy"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"Kinuha ng <xliff:g id="APP_NAME">%s</xliff:g> ang iyong lokasyon sa background"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Maa-access ng app na ito ang iyong lokasyon anumang oras. I-tap para baguhin."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Suriin ang app na may access sa iyong mga notification"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"Magagawa ng <xliff:g id="APP_NAME">%s</xliff:g> na i-dismiss, aksyunan, at i-access ang content sa loob ng iyong mga notification"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Magagawa ng app na ito na i-dismiss, aksyunan, at i-access ang content sa loob ng iyong mga notification. Kinakailangan ng ilang app ang access na ito para gumana nang maayos."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Alisin ang access"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Tumingin ng higit pang opsyon"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Inalis ang access"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Suriin ang app na may kumpletong access sa device"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"Matitingnan ng <xliff:g id="APP_NAME">%s</xliff:g> ang iyong screen at makakagawa ito ng mga pagkilos sa device mo Kailangan ng mga app sa accessibility ang ganitong uri ng access para gumana nang maayos."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Matitingnan ng app na ito ang iyong screen at makakagawa ito ng mga pagkilos sa iyong device. Kailangan ng mga app sa accessibility ang ganitong uri ng access para gumana nang maayos, pero suriin ang app at tiyaking pinagkakatiwalaan mo ito."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Alisin ang access"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Tingnan ang mga app na may kumpletong access"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Inalis ang access"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android System"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Inalis ang pahintulot sa app para protektahan ang privacy"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Ilang buwan nang hindi ginagamit ang <xliff:g id="APP_NAME">%s</xliff:g>. I-tap para suriin."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"Ilang buwan nang hindi ginagamit ang <xliff:g id="APP_NAME">%s</xliff:g> at 1 pang app. I-tap para suriin."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"Papayagan ang <xliff:g id="APP_NAME">%1$s</xliff:g> na makipag-ugnayan sa iyong mga notification at ma-access ang iyong mga pahintulot sa Telepono, SMS, Mga Contact, at Kalendaryo."</string>
<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">"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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="permgrouprequest_notifications" msgid="6396739062335106181">"Payagan ang <xliff:g id="APP_NAME">%1$s</xliff:g> na padalhan ka ng mga notification?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"Kontroladong pahintulot"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Puwedeng i-access ang lokasyon"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Pinapahintulutan ng iyong IT admin ang <xliff:g id="APP_NAME">%s</xliff:g> na i-access ang lokasyon mo"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Para sa mga app at serbisyo"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Posible pa ring ibahagi ang data ng mikropono kapag tumawag ka sa isang pang-emergency na numero."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Baguhin"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Security at Privacy"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Mag-scan"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Seguridad at privacy"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"I-scan ang device"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"I-dismiss"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"I-dismiss ang alertong ito?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Suriin ang iyong mga setting sa seguridad at privacy kahit kailan para magdagdag pa ng proteksyon"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"I-dismiss"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Kanselahin"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Mga Setting"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Status ng seguridad at privacy. <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">"Mga Setting ng Seguridad"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Mga Pahintulot sa Sensor"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Mga Kontrol sa Privacy"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Mga Pahintulot"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Seguridad at privacy"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Tingnan ang status"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Iyong mga kontrol sa privacy"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Higit pang setting"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Access sa camera"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Access sa mikropono"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Inalis ang pahintulot"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Tumingin ng higit pang paggamit ng camera"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Tumingin ng higit pang paggamit ng mikropono"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Alisin ang pahintulot sa camera"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Alisin ang pahintulot sa mikropono"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Tingnan ang kamakailang paggamit ng camera"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Tingnan ang kamakailang paggamit ng mikropono"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Alisin ang pahintulot para sa app na ito"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Alisin ang pahintulot para sa app na ito"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Pamahalaan ang serbisyo"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Pamahalaan ang mga pahintulot"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Ginagamit ng tawag sa telepono"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Kamakailang ginamit ng <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">"Ginagamit ng <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">"Kamakailang ginamit ng <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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Seguridad at Privacy"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Tingnan ang status"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Kumpirmahin"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Bumalik"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Papahintulutan din ang access sa iba pang file"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Hindi sinusuportahan ng app na ito ang pinakabagong bersyon ng Android. Kung hindi puwedeng i-access ng app na ito ang musika at mga audio file, hindi rin ito papahintulutang i-access ang mga larawan at video."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Hindi sinusuportahan ng app na ito ang pinakabagong bersyon ng Android. Kung puwedeng i-access ng app na ito ang mga larawan at video, papahintulutan din itong i-access ang musika at mga audio file."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Hindi sinusuportahan ng app na ito ang pinakabagong bersyon ng Android. Kung hindi puwedeng i-access ng app na ito ang musika at mga audio file, hindi rin ito papahintulutang i-access ang mga larawan at video."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Suriin ang app na may access sa lokasyon sa background"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"Maa-access ng <xliff:g id="APP_NAME">%s</xliff:g> ang iyong lokasyon kahit kailan, kahit na nakasara ang app"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Suriin ang app na may access sa lokasyon sa background"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Maa-access ng app na ito ang iyong lokasyon kahit kailan, kahit na nakasara ito.\n\nKailangan ng ilang app para sa kaligtasan at emergency ng access sa iyong lokasyon sa background para gumana ang mga ito gaya ng inaasahan."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Binago ang access"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Tingnan ang kamakailang paggamit ng lokasyon"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Mga kontrol sa privacy"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Access sa camera"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Access sa mikropono"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Para sa mga app at serbisyo"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Para sa mga app at serbisyo. Kung naka-off ang setting na ito, posible pa ring ibahagi ang data ng mikropono kapag tumawag ka sa pang-emergency na numero."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Tingnan ang mga app at serbisyong may access sa lokasyon"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Ipakita ang access sa clipboard"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Magpakita ng mensahe kapag ina-access ng mga app ang text, mga larawan, o iba pang content na nakopya mo"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Ipakita ang mga password"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Ipakita sandali ang mga character habang nagta-type ka"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Posibleng mag-iba ang mga kagawian sa data batay sa iyong bersyon ng app, paggamit, rehiyon, at edad. "<annotation id="link">"Higit pa tungkol sa pagbabahagi ng data"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Posibleng mag-iba ang mga kagawian sa data batay sa iyong bersyon ng app, paggamit, rehiyon, at edad."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Iyong data ng lokasyon"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Palitan ang access ng app na ito sa "<annotation id="link">"mga setting ng privacy"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Functionality ng app"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analytics"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Mga komunikasyon ng developer"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Pag-advertise o marketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Pag-iwas sa panloloko, seguridad, at pagsunod"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Pag-personalize"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Pamamahala sa account"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Nagbigay ang mga developer ng mga app na ito ng impormasyon tungkol sa kanilang mga kagawian sa pagbabahagi ng data sa isang app store Puwede nilang i-update ito sa paglipas ng panahon.\n\nPuwedeng mag-iba ang mga kagawian sa pagbabahagi ng data batay sa bersyon ng iyong app, paggamit, rehiyon, at edad."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Matuto tungkol sa pagbabahagi ng data"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Ibinabahagi na ngayon sa mga third party ang iyong data ng lokasyon"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Ibinabahagi na ngayon ang iyong data ng lokasyon sa mga third party para sa pag-advertise o marketing"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Na-update sa loob ng huling araw}=1{Na-update sa loob ng huling araw}one{Na-update sa loob ng # araw}other{Na-update sa loob ng # na araw}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Walang update sa ngayon"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-tr-v33/strings.xml b/PermissionController/res/values-tr-v33/strings.xml
index 25aff156a..d6d2e4286 100644
--- a/PermissionController/res/values-tr-v33/strings.xml
+++ b/PermissionController/res/values-tr-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Bu uygulamanın size bildirim göndermesine izin verilecek. Ayrıca Kamera, Kişiler, Mikrofon, Telefon ve SMS\'inize erişebilecek"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Bu uygulamanın size bildirim göndermesine izin verilecek. Ayrıca Kamera, Kişiler, Dosyalar, Mikrofon, Telefon ve SMS\'inize erişebilecek"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Bu izne sahip uygulamalar bu cihazdaki tüm dosyalara erişebilir"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"İş politikası bilgileriniz"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Ayarlar BT yöneticiniz tarafından yönetiliyor"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Listeyi genişletip göster"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Listeyi daraltıp ayarları gizle"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Liste. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Liste. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. İşlem gerekiyor. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Liste öğesi. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Kapat"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Seçenekleri genişletip göster"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Daralt"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Değiştir. <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">"Aç/Kapat"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Aç"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Ayarları incele"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Ayarlar"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Bilgi"</string>
</resources>
diff --git a/PermissionController/res/values-tr-v34/strings.xml b/PermissionController/res/values-tr-v34/strings.xml
new file mode 100644
index 000000000..81d533562
--- /dev/null
+++ b/PermissionController/res/values-tr-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Güvenlik ve gizlilik"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Denetimler"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Uygulamaların, sağlık verilerine erişimini yönetin"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Konum erişimi"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Uygulamalar ve hizmetler için. Bu ayar kapalıyken bir acil durum numarasını aradığınızda mikrofon verileri paylaşılmaya devam edebilir."</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Uygulamalar ve hizmetler için"</string>
+</resources>
diff --git a/PermissionController/res/values-tr/strings.xml b/PermissionController/res/values-tr/strings.xml
index dea713f9d..9bda44775 100644
--- a/PermissionController/res/values-tr/strings.xml
+++ b/PermissionController/res/values-tr/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Geri"</string>
<string name="available" msgid="6007778121920339498">"İzin verildi"</string>
<string name="blocked" msgid="9195547604866033708">"Engellendi"</string>
+ <string name="on" msgid="280241003226755921">"Açık"</string>
+ <string name="off" msgid="1438489226422866263">"Kapalı"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Kaldır veya devre dışı bırak"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Uygulama bulunamadı"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"İzin verme"</string>
@@ -30,10 +32,15 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"“Uygulama kullanılırken” tut"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"\"Yalnızca bu defa\" sakla"</string>
<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_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">"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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Ekran yer paylaşımı tespit edildi"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Bu izin ayarını değiştirmek için ilk olarak Ayarlar &gt; Uygulamalar\'dan ekran yer paylaşımını kapatmanız gerekir"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Ayarları aç"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"<xliff:g id="PERMGROUP">%1$s</xliff:g> izin grubunuzun, son 7 gün içinde uygulamalar tarafından kullanımının zaman çizelgesi"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Bu uygulamanın <xliff:g id="PERMGROUP">%1$s</xliff:g> izninizi kullandığı zaman"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Daha fazla bilgi"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"<xliff:g id="PERMGROUP">%1$s</xliff:g> hakkında daha fazla bilgi"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Uygulamaların <xliff:g id="PERMGROUP">%1$s</xliff:g> bilgilerinize erişimini kontrol edin"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 gün}other{# gün}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 saat}other{# saat}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 dk.}other{# dk.}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 sn.}other{# sn.}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# gün}other{# gün}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# saat}other{# saat}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# dk.}other{# dk.}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# sn.}other{# sn.}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Tüm izinler"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Tüm zamanlar"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Son 7 gün"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Son 24 saat"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Son 1 saat"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Son 15 dakika"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Son 1 dakika"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Son # gün}other{Son # gün}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Son # saat}other{Son # saat}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Son # dakika}other{Son # dakika}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"İzin kullanılmadı"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Herhangi bir zamanda gerçekleşen en son erişim"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Son 7 gün içindeki en son erişimler"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Son 1 saat içinde gerçekleşen izin kullanımı"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Son 15 dakika içinde gerçekleştirilen izin kullanımı"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Son 1 dakika içinde gerçekleşen izin kullanımı"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Son 24 saat içinde kullanılmadı"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Son 7 gün içinde kullanılmadı"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Son # gün içinde kullanılmadı}other{Son # gün içinde kullanılmadı}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Son # saat içinde kullanılmadı}other{Son # saat içinde kullanılmadı}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{1 uygulama tarafından kullanıldı}other{# uygulama tarafından kullanıldı}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Tümünü Kontrol Paneli\'nde göster"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtre ölçütü: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Yalnızca medyaya erişim izni ver"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Her zaman izin ver"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Yalnızca uygulama kullanılırken izin ver"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Tümüne her zaman izin ver"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Her zaman sor"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"İzin verme"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Tam konum"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> ve <xliff:g id="PERM_1">%2$s</xliff:g> izinleri kaldırılacak."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Kaldırılacak izinler: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"İzinleri otomatik olarak yönetin"</string>
- <string name="off" msgid="1438489226422866263">"Kapalı"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"<xliff:g id="PERMISSION_NAME">%s</xliff:g> izni kaldırıldı"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> ve <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> izni kaldırıldı"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> izni ve diğer <xliff:g id="NUMBER">%2$s</xliff:g> izin kaldırıldı"</string>
<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="3685907153054355671">"Uygulama birkaç 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="7871347400611202595">"En son <xliff:g id="NUMBER">%s</xliff:g> aydan fazla bir süre önce açıldı"</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 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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"İzin verilmeyenler"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Tüm dosyalara erişebilen diğer uygulamaları görün"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 gün}other{# gün}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 saat}other{# saat}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 dakika}other{# dakika}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 saniye}other{# saniye}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# saat}other{# saat}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# dakika}other{# dakika}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# saniye}other{# saniye}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"İzin hatırlatıcılar"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 kullanılmayan uygulama"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> kullanılmayan uygulama"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Bazı uygulamalar birkaç aydır kullanılmadı. İncelemek için dokunun."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# kullanılmayan uygulama}other{# kullanılmayan uygulama}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"İzinler ve geçici dosyalar kaldırıldı, bildirimler durduruldu. İncelemek için dokunun."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"İzinleri kaldırılan uygulamaları inceleyin"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Bir süredir kullanmadığınız uygulamalardaki izinler ile geçici dosyalar kaldırıldı ve bildirimler durduruldu."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Uygulamaları inceleyin"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Son izinleri kontrol edin"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Sürüş sırasında <xliff:g id="APP">%1$s</xliff:g> uygulamasına <xliff:g id="PERMISSION">%2$s</xliff:g> erişim izni verdiniz"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Sürüş sırasında <xliff:g id="APP">%1$s</xliff:g> uygulamasına <xliff:g id="PERMISSION_1">%2$s</xliff:g> ve <xliff:g id="PERMISSION_2">%3$s</xliff:g> erişim izni verdiniz"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"İzinler gizliliğinizi korumak için kaldırıldı"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g>, arka planda konumunuza erişti"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Bu uygulama, konumunuza her zaman erişebilir. Değiştirmek için dokunun."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Bildirim erişimine sahip olan uygulamayı inceleyin"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g>, bildirimlerinizdeki içerikleri kapatabilir, bu içeriklerle ilgili işlem yapabilir ve bunlara erişebilir"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Bu uygulama, bildirimlerinizdeki içerikleri kapatabilir, bu içeriklerle ilgili işlem yapabilir ve bunlara erişebilir. Bazı uygulamaların istenen şekilde çalışabilmeleri için bu erişime ihtiyaçları vardır."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Erişimi kaldırın"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Diğer seçenekleri göster"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Erişim kaldırıldı"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Tam cihaz erişimine sahip olan uygulamayı inceleyin"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g>, ekranınızı görüntüleyebilir ve cihazınızda işlem gerçekleştirebilir. Erişilebilirlik uygulamaları, istenen şekilde çalışmak için bu tür bir erişime ihtiyaç duyar."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Bu uygulama, ekranınızı görüntüleyebilir ve cihazınızda işlem gerçekleştirebilir. Erişilebilirlik uygulamaları, istenen şekilde çalışmak için bu tür bir erişime ihtiyaç duyar. Yine de ilgili uygulamayı kontrol edip güvenilir olduğundan emin olun."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Erişimi kaldırın"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Tam erişime sahip olan uygulamaları görüntüleyin"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Erişim kaldırıldı"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android Sistemi"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Uygulama izinleri gizliliği korumak için kaldırıldı"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> birkaç aydır kullanılmadı. İncelemek için dokunun."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> ve 1 diğer uygulama birkaç aydır kullanılmadı. İncelemek için dokunun."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler ve Takvim izinlerinize erişmesine izin verilir."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup uygulamalarınızı bağlı cihazda canlı oynatmasına izin verilecek."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Bu hizmet, telefonunuzdaki fotoğraf, medya ve bildirimleri diğer cihazlarla paylaşır."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Varsayılan not uygulaması"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Kontrol edilen izinler"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Konuma erişilebilir"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"BT yöneticiniz, <xliff:g id="APP_NAME">%s</xliff:g> uygulamasının konumunuza erişmesine izin veriyor"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Uygulamalar ve hizmetler için"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Mikrofon verileri, bir acil durum numarasını aradığınızda paylaşılmaya devam edilebilir."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Değiştir"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Güvenlik ve Gizlilik"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Tara"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Güvenlik ve gizlilik"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Cihaz taraması yap"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Kapat"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Bu uyarı kapatılsın mı?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Daha fazla korumaya sahip olmak için güvenlik ve gizlilik ayarlarınızı istediğiniz zaman gözden geçirin."</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Kapat"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"İptal"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Ayarlar"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Güvenlik ve gizlilik durumu. <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">"Güvenlik Ayarları"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Sensör İzinleri"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Gizlilik Denetimleri"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"İzinler"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Güvenlik ve gizlilik"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Durumu denetle"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Gizlilik kontrolleriniz"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Diğer ayarlar"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Kamera erişimi"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Mikrofon erişimi"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"İzin kaldırıldı"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Daha fazla kamera kullanımı göster"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Daha fazla mikrofon kullanımı göster"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Kamera iznini kaldır"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Mikrofon iznini kaldır"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Son kamera kullanımını göster"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Son mikrofon kullanımını göster"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Bu uygulamanın iznini kaldır"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Bu uygulamanın iznini kaldır"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Hizmeti yönet"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"İzinleri yönetin"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Telefon aramasında kullanılıyor"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"En son <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) tarafından kullanıldı"</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>) tarafından kullanılıyor"</string>
<string name="recent_app_usage_2_qs" msgid="3591205954235694403">"En son <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>) tarafından kullanıldı"</string>
- <string name="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Güvenlik ve Gizlilik"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Durumu denetle"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Onayla"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Geri"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Diğer dosyalara erişime de izin verilir"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Bu uygulamada Android\'in en son sürümü desteklenmiyor. Bu uygulama müzik ve ses dosyalarına erişemezse fotoğraflara ve videolara da erişmesine izin verilmez."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Bu uygulamada Android\'in en son sürümü desteklenmiyor. Bu uygulama fotoğraflara ve videolara erişebilirse müzik ve ses dosyalarına da erişmesine izin verilir."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Bu uygulamada Android\'in en son sürümü desteklenmiyor. Bu uygulama müzik ve ses dosyalarına erişemezse fotoğraflara ve videolara da erişmesine izin verilmez."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Arka planda konum erişimine sahip olan uygulamayı inceleyin"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g>, uygulama kapalıyken bile konumunuza her zaman erişebilir"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Arka planda konum erişimine sahip olan uygulamayı inceleyin"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Bu uygulama kapalı olduğunda bile her zaman konumunuza erişebilir.\n\nBazı güvenlik ve acil durum uygulamalarının doğru şekilde çalışabilmesi için arka planda konum bilginize erişmesi gerekir."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Erişim değiştirildi"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Son konum kullanımını göster"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Gizlilik denetimleri"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Kamera erişimi"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Mikrofon erişimi"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Uygulamalar ve hizmetler için"</string>
+ <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_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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Veri uygulamaları; uygulama sürümünüz, kullanımınız, bölgeniz ve yaşınıza göre değişiklik gösterebilir. "<annotation id="link">"Veri paylaşımı hakkında daha fazla bilgi"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Veri uygulamaları; uygulama sürümünüz, kullanımınız, bölgeniz ve yaşınıza göre değişiklik gösterebilir."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Konum verileriniz"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Bu uygulamanın erişimini "<annotation id="link">"gizlilik ayarlarından"</annotation>" değiştirebilirsiniz"</string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Uygulama işlevselliği"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analizler"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Geliştirici iletişimleri"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Reklam veya pazarlama"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Sahtekarlığı önleme, güvenlik ve kanunlara uygunluk"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Kişiselleştirme"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Hesap yönetimi"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Bu uygulamaların geliştiricileri, bir uygulama mağazasına veri paylaşımı yöntemleri hakkında bilgi ekledi. Zaman içinde bu bilgileri güncelleyebilirler.\n\nVeri paylaşımı yöntemleri uygulama sürümüne, kullanıma, bölgeye ve yaşa göre değişebilir."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Veri paylaşımı hakkında bilgi"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Konum verileriniz artık üçüncü taraflarla paylaşılıyor"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Konum verileriniz artık reklam ve pazarlama amacıyla üçüncü taraflarla paylaşılıyor"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Son 1 günde güncellendi}=1{Son 1 günde güncellendi}other{Son # günde güncellendi}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Şu an için güncelleme yok"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-uk-v33/strings.xml b/PermissionController/res/values-uk-v33/strings.xml
index 689d9e327..0066766f5 100644
--- a/PermissionController/res/values-uk-v33/strings.xml
+++ b/PermissionController/res/values-uk-v33/strings.xml
@@ -19,4 +19,28 @@
<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="work_policy_title" msgid="832967780713677409">"Інформація про правила роботи"</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>
+ <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{Розгорніть і перегляньте ще # сповіщення}few{Розгорніть і перегляньте ще # сповіщення}many{Розгорніть і перегляньте ще # сповіщень}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Закрити"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Розгорнути та показати опції"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Згорнути"</string>
+ <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_gear_label" msgid="5175877094379694098">"Налаштування"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Інформація"</string>
</resources>
diff --git a/PermissionController/res/values-uk-v34/strings.xml b/PermissionController/res/values-uk-v34/strings.xml
new file mode 100644
index 000000000..5d14c8ebe
--- /dev/null
+++ b/PermissionController/res/values-uk-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-uk/strings.xml b/PermissionController/res/values-uk/strings.xml
index b6d4f62aa..bf4b99d43 100644
--- a/PermissionController/res/values-uk/strings.xml
+++ b/PermissionController/res/values-uk/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,11 +32,16 @@
<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_always_allow_all" msgid="1719900027660252167">"Завжди дозволяти всі"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Виявлено показ поверх інших вікон"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Щоб змінити налаштування цього дозволу, спершу вимкніть показ додатка поверх інших вікон у меню \"Налаштування\" &gt; \"Додатки\""</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Відкрити налаштування"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 день}one{# день}few{# дні}many{# днів}other{# дня}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 година}one{# година}few{# години}many{# годин}other{# години}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 хвилина}one{# хвилина}few{# хвилини}many{# хвилин}other{# хвилини}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 секунда}one{# секунда}few{# секунди}many{# секунд}other{# секунди}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# день}one{# день}few{# дні}many{# днів}other{# дня}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# година}one{# година}few{# години}many{# годин}other{# години}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# хв}one{# хв}few{# хв}many{# хв}other{# хв}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# с}one{# с}few{# с}many{# с}other{# с}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Будь-який дозвіл"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"У будь-який час"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Останні 7 днів"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Останні 24 години"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Остання година"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Останні 15 хвилин"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Остання хвилина"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{За останній # день}one{За останній # день}few{За останні # дні}many{За останні # днів}other{За останні # дня}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{За останню # годину}one{За останню # годину}few{За останні # години}many{За останні # годин}other{За останні # години}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{За останню # хвилину}one{За останню # хвилину}few{За останні # хвилини}many{За останні # хвилин}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>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Використання дозволів за останню годину"</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">"Використання дозволів за останню хвилину"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Дозвіл не використовувався протягом останніх 24 годин"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Дозвіл не використовувався протягом останніх 7 днів"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Не використовувався протягом останнього # дня}one{Не використовувався протягом останнього # дня}few{Не використовувався протягом останніх # днів}many{Не використовувався протягом останніх # днів}other{Не використовувався протягом останніх # дня}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Не використовувався протягом останньої # години}one{Не використовувався протягом останньої # години}few{Не використовувався протягом останніх # годин}many{Не використовувався протягом останніх # годин}other{Не використовувався протягом останніх # години}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Використано в 1 додатку}one{Використано в # додатку}few{Використано в # додатках}many{Використано в # додатках}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>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"Завжди дозволяти всі"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Запитувати щоразу"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Не дозволяти"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Точне місцезнаходження"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Дозволи \"<xliff:g id="PERM_0">%1$s</xliff:g>\" і \"<xliff:g id="PERM_1">%2$s</xliff:g>\" буде відкликано."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Дозволи, які буде відкликано: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Керувати дозволами автоматично"</string>
- <string name="off" msgid="1438489226422866263">"Вимкнути"</string>
<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_tv_summary" msgid="3685907153054355671">"Якщо ви не користуєтеся додатком кілька місяців:\n\n• дозволи буде скасовано, щоб захистити ваші дані;\n• тимчасові файли буде видалено, щоб звільнити місце на диску.\n\nЩоб відновити дозволи, відкрийте додаток."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Відкривались понад <xliff:g id="NUMBER">%s</xliff:g> міс. тому"</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{Відкривались понад # місяць тому}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>
@@ -251,9 +254,9 @@
<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="3447767892295843282">"{count,plural, =1{1 година}one{# година}few{# години}many{# годин}other{# години}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 хвилина}one{# хвилина}few{# хвилини}many{# хвилин}other{# хвилини}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 секунда}one{# секунда}few{# секунди}many{# секунд}other{# секунди}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# година}one{# година}few{# години}many{# годин}other{# години}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# хвилина}one{# хвилина}few{# хвилини}many{# хвилин}other{# хвилини}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# секунда}one{# секунда}few{# секунди}many{# секунд}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>
@@ -262,6 +265,9 @@
<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_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_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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Система Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Дозволи додатка відкликано для захисту конфіденційності"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Додаток <xliff:g id="APP_NAME">%s</xliff:g> не використовувався кілька місяців. Натисніть, щоб переглянути."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> і ще 1 додаток не використовувалися кілька місяців. Натисніть, щоб переглянути."</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"нотатки"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"Керовані дозволи"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Відкрито доступ до місцезнаходження"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Ваш ІТ-адміністратор дозволяє додатку <xliff:g id="APP_NAME">%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>
@@ -489,24 +513,35 @@
<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>
<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="7514620345152008005">"Безпека й конфіденційність"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Сканувати"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"Доступ до датчиків"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Налаштування конфіденційності"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"Дозвіл вилучено"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Докладніше про використання камери"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Докладніше про використання мікрофона"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Вилучити дозвіл на доступ до камери"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Вилучити дозвіл на доступ до мікрофона"</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="manage_service_qs" msgid="7862555549364153805">"Керувати сервісом"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Керувати дозволами"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Використовується в телефонному дзвінку"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Безпека й конфіденційність"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Перевірити статус"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Сповіщення від розробника"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Оновлено за останній день}=1{Оновлено за останній день}one{Оновлено за # день}few{Оновлено за # дні}many{Оновлено за # днів}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>
</resources>
diff --git a/PermissionController/res/values-ur-v33/strings.xml b/PermissionController/res/values-ur-v33/strings.xml
index 8ada211ed..0a56dd190 100644
--- a/PermissionController/res/values-ur-v33/strings.xml
+++ b/PermissionController/res/values-ur-v33/strings.xml
@@ -19,4 +19,28 @@
<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="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>
+ <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>
+ <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{پھیلائیں اور ایک اور الرٹ دیکھیں}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"بند کریں"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"اختیارات کو پھیلاکر دکھائیں"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"سکیڑیں"</string>
+ <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_gear_label" msgid="5175877094379694098">"ترتیبات"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"معلومات"</string>
</resources>
diff --git a/PermissionController/res/values-ur-v34/strings.xml b/PermissionController/res/values-ur-v34/strings.xml
new file mode 100644
index 000000000..37b5ec635
--- /dev/null
+++ b/PermissionController/res/values-ur-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-ur/strings.xml b/PermissionController/res/values-ur/strings.xml
index 255bfc6d6..4cb926518 100644
--- a/PermissionController/res/values-ur/strings.xml
+++ b/PermissionController/res/values-ur/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"ہمیشہ سبھی کو اجازت دیں"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"اسکرین اورلے کا پتا چلا ہے"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"اس اجازت کی ترتیب کو تبدیل کرنے کیلئے آپ کو پہلے ترتیبات &gt; ایپس سے اسکرین اورلے کو آف کرنا ہوگا"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"ترتیبات کھولیں"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 دن}other{# دن}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 گھنٹہ}other{# گھنٹے}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 منٹ}other{# منٹ}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 سیکنڈ}other{# سیکنڈ}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# دن}other{# دن}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# گھنٹہ}other{# گھنٹے}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# منٹ}other{# منٹ}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# سیکنڈ}other{# سیکنڈ}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"کوئی بھی اجازت"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"کسی بھی وقت"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"آخری 7 دن"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"آخری 24 گھنٹے"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"آخری 1 گھنٹہ"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"آخری 15 منٹ"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"آخری 1 منٹ"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{گزشتہ # دن}other{گزشتہ # دن}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{گزشتہ # گھنٹہ}other{گزشتہ # گھنٹے}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{گزشتہ # منٹ}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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"گزشتہ 24 گھنٹے میں استعمال نہیں کی گئی"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"گزشتہ 7 دن میں استعمال نہیں کی گئی"</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_view_details" msgid="6675335735468752787">"سبھی کو ڈیش بورڈ میں دیکھیں"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"فلٹر کردہ بلحاظ: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"ہمیشہ سبھی کو اجازت دیں"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"ہر بار پوچھیں"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"اجازت نہ دیں"</string>
<string name="precise_image_description" msgid="6349638632303619872">"قطعی مقام"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> اور <xliff:g id="PERM_1">%2$s</xliff:g> کی اجازتیں ہٹا دی جائیں گی۔"</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"وہ اجازتیں جو ہٹا دی جائیں گی: <xliff:g id="PERMS">%1$s</xliff:g>۔"</string>
<string name="auto_manage_title" msgid="7693181026874842935">"خودکار طور پر اجازتوں کا نظم کریں"</string>
- <string name="off" msgid="1438489226422866263">"آف کریں"</string>
<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_tv_summary" msgid="3685907153054355671">"اگر کوئی ایپ کچھ ماہ تک استعمال نہیں ہوتی ہے تو:\n\n• آپ کے ڈیٹا کی حفاظت کیے لیے اجازتوں کو ہٹا دیا جاتا ہے\n• اسپیس خالی کرنے کے لیے عارضی فائلز کو ہٹا دیا جاتا ہے\n\nاجازتوں کو دوبارہ اجازت دینے کے لیے ایپ کو کھولیں۔"</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"آخری بار <xliff:g id="NUMBER">%s</xliff:g> ماہ سے زیادہ پہلے کھولی گئی"</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>
@@ -251,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 گھنٹہ}other{# گھنٹے}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 منٹ}other{# منٹ}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 سیکنڈ}other{# سیکنڈ}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# گھنٹہ}other{# گھنٹے}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<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_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_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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"‏Android سسٹم"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"رازداری کی حفاظت کے لیے ایپ کی اجازتوں کو ہٹایا گیا"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> کا استعمال کچھ مہینوں سے نہیں کیا گیا ہے۔ جائزہ کے لیے تھپتھپائیں۔"</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> اور 1 دیگر ایپس کا استعمال کچھ مہینوں سے نہیں کیا گیا ہے۔ جائزہ کے لیے تھپتھپائیں۔"</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"نوٹس"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"کنٹرول کی گئی اجازتیں"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"مقام تک رسائی حاصل کی جا سکتی ہے"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"‏آپ کا IT منتظم <xliff:g id="APP_NAME">%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>
@@ -496,29 +520,38 @@
<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="7514620345152008005">"سیکیورٹی اور رازداری"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"اسکین کریں"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"سینسر کی اجازتیں"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"رازداری سے متعلق کنٹرولز"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"اجازت کو ہٹایا گیا"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"کیمرے کا مزید استعمال دیکھیں"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"مائیکروفون کا مزید استعمال دیکھیں"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"کیمرے کی اجازت کو ہٹا دیا گیا"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"مائیکروفون کی اجازت کو ہٹا دیا گیا"</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="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="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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"سیکیورٹی اور رازداری"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"صورتحال چیک کریں"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"ڈیولپر سے مواصلات"</string>
+ <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="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="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">"‏ان ایپس کے ڈویلپرز نے اپنے ڈیٹا کے اشتراک کے طریقوں کے بارے میں App اسٹور کو معلومات فراہم کیں۔ وہ اسے وقت کے ساتھ اپ ڈیٹ کر سکتے ہیں۔\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="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>
</resources>
diff --git a/PermissionController/res/values-uz-v33/strings.xml b/PermissionController/res/values-uz-v33/strings.xml
index ff21e81cd..a32387c37 100644
--- a/PermissionController/res/values-uz-v33/strings.xml
+++ b/PermissionController/res/values-uz-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Bu ilova Kamera, Kontaktlar, Mikrofon, Telefon va SMSlarga ruxsat oladi va sizga bildirishnomalar yubora oladi"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Bu ilova Kamera, Kontaktlar, Fayllar, Mikrofon, Telefon va SMSlarga ruxsat oladi va sizga bildirishnomalar yubora oladi"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Bunday ruxsatga ega ilovalar bu qurilmadagi barcha fayllarga kira oladi"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Ish siyosati haqida axborot"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Sozlamalar AT administratori tomonidan boshqariladi"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Yoyish va roʻyxatni koʻrsatish"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Roʻyxatni yigʻadi va sozlamalarni yashiradi"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Roʻyxat. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Roʻyxat. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Amallar bajarish zarur. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Roʻyxat bandi. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Yopish"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Parametrlarni ochish"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Yopish"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Almashtirish. <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">"Almashtirish"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Ochish"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Sozlamalarni tekshirish"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Sozlamalar"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Axborot"</string>
</resources>
diff --git a/PermissionController/res/values-uz-v34/strings.xml b/PermissionController/res/values-uz-v34/strings.xml
new file mode 100644
index 000000000..3c48cd9d1
--- /dev/null
+++ b/PermissionController/res/values-uz-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Xavfsizlik va maxfiylik"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Boshqaruv"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Salomatlik maʼlumotlariga ilova ruxsatini boshqaring"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Joylashuv axborotiga ruxsat"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Ilovalar va xizmatlar uchun. Bu sozlama yoqilmasa, favqulodda xizmat raqamiga telefon qilganingizda mikrofon maʼlumotlari hamon ulashilishi mumkin"</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Ilovalar va xizmatlar uchun"</string>
+</resources>
diff --git a/PermissionController/res/values-uz/strings.xml b/PermissionController/res/values-uz/strings.xml
index 0d108b02b..356df948e 100644
--- a/PermissionController/res/values-uz/strings.xml
+++ b/PermissionController/res/values-uz/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Orqaga"</string>
<string name="available" msgid="6007778121920339498">"Mavjud"</string>
<string name="blocked" msgid="9195547604866033708">"Bloklangan"</string>
+ <string name="on" msgid="280241003226755921">"Yoniq"</string>
+ <string name="off" msgid="1438489226422866263">"Oʻchiq"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Oʻchirish yoki faolsizlantirish"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Ilova topilmadi"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Rad etish"</string>
@@ -30,11 +32,16 @@
<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"</string>
+ <string name="grant_dialog_button_always_allow_all" msgid="1719900027660252167">"Doim hammasiga 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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Ekran ustidan ochiladigan ilova aniqlandi"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Bu ruxsat parametrini o‘zgartirish uchun avval Sozlamalar &gt; Ilovalar ruknidan ekran ustidan ochilish funksiyasini faolsizlantiring"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Sozlamalarni ochish"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Oxirgi 7 soat ichida ishlatilgan ilovalar xronologiyasi (<xliff:g id="PERMGROUP">%1$s</xliff:g>)"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Bu ilova <xliff:g id="PERMGROUP">%1$s</xliff:g> ruxsatidan foydalanganda"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Batafsil"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"<xliff:g id="PERMGROUP">%1$s</xliff:g> haqida batafsil"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Ilovaning <xliff:g id="PERMGROUP">%1$s</xliff:g> uchun ruxsatini boshqarish"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 kun}other{# kun}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 soat}other{# soat}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 daq}other{# daq}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 son}other{# son}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# kun}other{# kun}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# soat}other{# soat}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# daq}other{# daq}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# son}other{# son}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Har qanday ruxsat"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Har qanday vaqt"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Oxirgi 7 kun"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Oxirgi 24 soat"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Oxirgi 1 soat"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Oxirgi 15 daqiqa"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Oxirgi 1 daqiqa"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Oxirgi # kun}other{Oxirgi # kun}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Oxirgi # soat}other{Oxirgi # soat}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Oxirgi # daqiqa}other{Oxirgi # daqiqa}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Ruxsatlardan foydalanilmagan"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Butun vaqtda ruxsatlardan foydalanish"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Oxirgi 7 kunda ruxsatlardan foydalanish"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Oxirgi 1 soatda ishlatilgan ruxsatlar"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Oxirgi 15 daqiqada ishlatilgan ruxsatlar"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Oxirgi 1 daqiqada ishlatilgan ruxsatlar"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Oxirgi 24 soatda foydalanilmagan"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Oxirgi 7 kunda foydalanilmagan"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Oxirgi # kunda foydalanilmagan}other{Oxirgi # kunda foydalanilmagan}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Oxirgi # soatda foydalanilmagan}other{Oxirgi # soatda foydalanilmagan}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{1 ta ilova ishlatyapti}other{# ta ilova ishlatyapti}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Boshqaruv panelida ochish"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Filtrlar: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Faqat media fayllarga ruxsat"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Har doim ruxsat"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Faqat ilova faolligida ruxsat"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Doim hammasiga ruxsat"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Har safar soʻralsin"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Rad etish"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Aniq joylashuv"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g> va <xliff:g id="PERM_1">%2$s</xliff:g> ruxsatlari olib tashlanadi."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Olib tashlanadigan ruxsatlar: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Ruxsatlarni avtomatik boshqarish"</string>
- <string name="off" msgid="1438489226422866263">"Oʻchiq"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"<xliff:g id="PERMISSION_NAME">%s</xliff:g> ruxsati olib tashlandi"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"<xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> va yana <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g> ta ruxsat olib tashlandi"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"<xliff:g id="PERMISSION_NAME">%1$s</xliff:g> va yana <xliff:g id="NUMBER">%2$s</xliff:g> ta ruxsat olib tashlandi"</string>
<string name="unused_apps_page_title" msgid="6986983535677572559">"Ishlatilmagan ilovalar"</string>
<string name="unused_apps_page_summary" msgid="1867593913217272155">"Ilova bir necha oy ishlatilmasa:\n\n• Maxfiyligingizni himoyalash uchun ruxsatlar bekor qilinadi\n• Batareyani tejash uchun bildirishnomalar toʻxtatiladi\n• Boʻsh joy ochish uchun vaqtinchalik fayllar tozalab tashlanadi\n\nRuxsat va bildirishnomalarga yana ruxsat berish uchun ilovani oching."</string>
- <string name="unused_apps_page_tv_summary" msgid="3685907153054355671">"Ilova bir necha oy ishlatilmasa:\n\n• Maxfiyligingizni himoyalash uchun ruxsatlar bekor qilinadi\n• Boʻsh joy ochish uchun vaqtinchalik fayllar tozalab tashlanadi\n\nRuxsatlarni qayta berish uchun ilovani oching."</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"Oxirgi marta <xliff:g id="NUMBER">%s</xliff:g> oy oldin ochilgan"</string>
+ <string name="unused_apps_page_tv_summary" msgid="2624911608663778308">"Ilova bir oy ishlatilmasa:\n\n• Maxfiyligingizni himoyalash uchun ruxsatlar bekor qilinadi\n• Boʻsh joy ochish uchun vaqtinchalik fayllar tozalab tashlanadi\n\nRuxsatlarni qayta berish uchun ilovani oching."</string>
+ <string name="last_opened_category_title" msgid="8796557894614236128">"{count,plural, =1{Oxirgi marta # oy oldinroq ochilgan}other{Oxirgi marta # oy oldinroq ochilgan}}"</string>
<string name="last_opened_summary" msgid="5248984030024968808">"Ilova oxirgi marta ochilgan: <xliff:g id="DATE">%s</xliff:g>"</string>
<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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Ruxsat berilmagan"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Barcha fayllarga kirish uchun koʻproq ilovalarni koʻring"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 kun}other{# kun}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 soat}other{# soat}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 daqiqa}other{# daqiqa}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 soniya}other{# soniya}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# soat}other{# soat}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# daqiqa}other{# daqiqa}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# soniya}other{# soniya}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Ruxsat eslatmalari"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 ta ishlatilmagan ilova"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> ta ishlatilmagan ilova"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Ayrim ilovalar bir necha oydan beri ishlatilmadi. Tekshirish uchun bosing."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# ta ishlatilmagan ilova}other{# ta ishlatilmagan ilova}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Ruxsatlar va vaqtinchalik fayllar olib tashlandi hamda bildirishnomalar toʻxtatildi. Tekshirish uchun bosing."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Ruxsat olib tashlangan ilovalarni tekshirish"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Ruxsatlarni bekor qildik, vaqtinchalik fayllarni oʻchirib tashladik va siz anchadan beri foydalanmayotgan ilovalaringiz uchun bildirishnomalarni faolsizlantirdik."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Ilovalarni tekshirish"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Oxirgi ruxsatlarni tekshirish"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Haydash vaqtida <xliff:g id="APP">%1$s</xliff:g> ilovasiga <xliff:g id="PERMISSION">%2$s</xliff:g> ruxsatini bergansiz"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Haydash vaqtida <xliff:g id="APP">%1$s</xliff:g> ilovasiga <xliff:g id="PERMISSION_1">%2$s</xliff:g> va <xliff:g id="PERMISSION_2">%3$s</xliff:g> ruxsatlarini bergansiz"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Xavfsizlik yuzasidan, ruxsatlar olib tashlandi"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> geolokatsiyangizni fonda aniqladi"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Bu ilova joylashuv axborotingizdan foydalana oladi. Oʻzgartirish uchun bosing."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Bildirishnomalaringizga ruxsati bor ilovani tekshiring"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> ilovasining bildirishnomalar ichidagi kontentni ochish va yopishga ruxsati bor"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Bu ilovaning bildirishnomalar ichidagi kontentni ochishi va yopishiga ruxsat berilgan. Bu uning xatosiz ishlashi uchun zarur."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Ruxsatni olib tashlash"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Boshqa variantlarni tanlash"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Ruxsat olib tashlandi"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Toʻliq kirish imkoniyati bilan ilovani tekshiring"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> ekraningizni koʻra oladi va qurilmangizda amallarni bajara oladi. Qulayliklar ilovalari kutilganidek ishlashi uchun bunday ruxsatni talab qiladi."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Bu ilova ekraningizni koʻra oladi va qurilmangizda amallarni bajara oladi. Qulayliklar ilovalari kutilganidek ishlashi uchun bunday ruxsatni talab qiladi, lekin ilovaning ishonchli ekanini tekshiring."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Ruxsatni olib tashlash"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Toʻliq ruxsatga ega ilovalarni koʻrsatish"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Ruxsat olib tashlandi"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android tizimi"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Xavfsizlik himoyasi uchun ilova ruxsatlari olib tashlandi"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g> bir necha oydan beri ishlatilmadi. Tekshirish uchun bosing."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g> va yana 1 ta ilova bir necha oydan beri ishlatilmadi. Tekshirish uchun bosing."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar va taqvimga kirishga ruxsat beriladi"</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va ulangan qurilmalarga ilovalarni translatsiya qilishga ruxsat beriladi"</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Bu xizmat telefoningizdagi suratlar, media va bildirishnomalarni boshqa qurilmalarga ulashadi."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Birlamchi qaydlar ilovasi"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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 suratlar 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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Boshqariluvchi ruxsatlar"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Joylashuv axborotiga ruxsati bor"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"AT administratori <xliff:g id="APP_NAME">%s</xliff:g> ilovasiga joylashuvingiz haqidagi axborotdan foydalanishga ruxsat bergan"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Ilovalar va xizmatlar uchun"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Favqulodda xizmat raqamiga telefon qilganingizda mikrofon maʼlumotlari hamon ulashilishi mumkin."</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Oʻzgartirish"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Xavfsizlik va maxfiylik"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Qidiruv"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Xavfsizlik va maxfiylik"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Qurilmani tekshirish"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Yopish"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Bu ogohlantirish yopilsinmi?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Himoyani kuchaytirish uchun xavfsizlik va maxfiylik sozlamalarini istalgan vaqt tekshiring"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Yopish"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Bekor qilish"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Sozlamalar"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Xavfsizlik va maxfiylik holati. <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">"Xavfsizlik sozlamalari"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Sensorlarga ruxsatlar"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Maxfiylik boshqaruvi"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Ruxsatlar"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Xavfsizlik va maxfiylik"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Holatini tekshirish"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Daxlsizlik nazorati"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Boshqa sozlamalar"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Kameraga ruxsat"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Mikrofondan foydalanish"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Ruxsat olib tashlandi"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Kamera ishlatgan boshqa ilovalar"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Mikrofon ishlatgan boshqa ilovalar"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Kameraga ruxsatni olib tashlash"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Mikrofonga ruxsatni olib tashlash"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Oxirgi kameradan foydalanish axborotini koʻrsatish"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Oxirgi mikrofondan foydalanish axborotini koʻrsatish"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Bu ilova uchun ruxsatni olib tashlash"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Bu ilova uchun ruxsatni olib tashlash"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Xizmatni boshqarish"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Ruxsatlarni boshqarish"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Telefon chaqiruvi ishlatmoqda"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Yaqinda <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) ishlatgan"</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>) ishlatmoqda"</string>
<string name="recent_app_usage_2_qs" msgid="3591205954235694403">"Yaqinda <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>) ishlatgan"</string>
- <string name="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Xavfsizlik va maxfiylik"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Holatini tekshirish"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"OK"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Orqaga"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Boshqa fayllarga kirishga ham ruxsat beriladi"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Bu ilova eng oxirgi Android versiyasi bilan ishlamaydi. Agar bu ilova musiqa va audio fayllarga kira olmasa, unga suratlar va videolarga ham kirishiga ruxsat berilmaydi."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Bu ilova eng oxirgi Android versiyasi bilan ishlamaydi. Agar bu ilova suratlar va videolarga kira olsa, unga musiqa, va audio fayllarga ham kirishiga ruxsat beriladi."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Bu ilova eng oxirgi Android versiyasi bilan ishlamaydi. Agar bu ilova musiqa va audio fayllarga kira olmasa, unga suratlar va videolarga ham kirishiga ruxsat berilmaydi."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Joylashuv axborotidan fonda foydalanish ruxsati bor ilovani tekshiring"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"Ilova yopiq boʻlsa ham <xliff:g id="APP_NAME">%s</xliff:g> doim joylashuv axborotiga kira oladi"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Joylashuv axborotidan fonda foydalanish ruxsati bor ilovani tekshiring"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Bu ilova yopiq ekanligida ham har doim joylashuv axborotiga kira oladi.\n\nAyrim xavfsizlik va favqulodda holatlar ilovalari maqsadga muvofiq ishlashi uchun fonda joylashuv axborotidan foydalanishni talab qiladi."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Ruxsat oʻzgartirildi"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Oxirgi joylashuvdan foydalanish maʼlumotlarini koʻrsatish"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Maxfiylik sozlamalari"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Kameraga ruxsat"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Mikrofonga ruxsat"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Ilovalar va xizmatlar uchun"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Ilovalar va xizmatlar uchun. Bu sozlama yoqilmasa, favqulodda xizmat raqamiga telefon qilganingizda mikrofon maʼlumotlari hamon ulashilishi mumkin."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Joylashuv axborotiga ruxsati bor ilovalar va xizmatlari"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Vaqtinchalik xotiraga kirish haqida ogohlantirish"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Ilovalar siz nusxa olgan matn, rasmlar yoki boshqa kontentdan foydalanganda xabar chiqarish"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Parollar ochiq tursin"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Parolni kiritishda belgilar qisqa muddat ochiq turadi"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Axborot bilan ishlash amaliyotlari ilova versiyasi, foydalanish, hudud va yoshga qarab farq qilishi mumkin. "<annotation id="link">"Maʼlumotlar ulashuvi haqida batafsil"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Axborot bilan ishlash amaliyotlari ilova versiyasi, foydalanish, hudud va yoshga qarab farq qilishi mumkin."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Joylashuvingiz axboroti"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Bu ilovaning "<annotation id="link">"maxfiylik sozlamalariga"</annotation>" ruxsatini oʻzgartiring"</string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Ilova funksiyalari"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Analitika"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Dasturchidan axborot"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Reklama yoki marketing"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Firibgarlikning oldini olish, xavfsizlik va unga rioya qilish"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Moslashtirish"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Hisob boshqaruvi"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Quyidagi ilovalar dasturchilari ilova doʻkoniga maʼlumotlar qanday ulashilishi haqida axborot bergan. Bu axborot keyinchalik yangilanishi mumkin.\n\nMaʼlumotlar ilova versiyasi, foydalanishi, mamlakat va yosh asosida ulashiladi."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Maʼlumotlar ulashuvi haqida batafsil"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Joylashuvingiz axboroti endi tashqariga ulashilmoqda"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Joylashuvingizga oid axborotlar endi reklama yoki marketing maqsadlarida tashqariga ulashilmoqda"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Oxirgi bir kunda yangilandi}=1{Oxirgi bir kunda yangilandi}other{Oxirgi # kunda yangilandi}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Hozircha yangilanishlar mavjud emas"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-v31/colors.xml b/PermissionController/res/values-v31/colors.xml
index 1e4d8c1c8..c8f194ef7 100644
--- a/PermissionController/res/values-v31/colors.xml
+++ b/PermissionController/res/values-v31/colors.xml
@@ -17,4 +17,7 @@
<resources>
<color name="warning_surface">#F0E3A8</color>
<color name="warning_onsurface">#895900</color>
+
+ <!-- overviewBackground is not visible from mainline, so UX provided this alternative -->
+ <color name="permission_rationale_overview_background">@android:color/system_neutral2_200</color>
</resources> \ No newline at end of file
diff --git a/PermissionController/res/values-v31/styles.xml b/PermissionController/res/values-v31/styles.xml
index 0f073d233..a05fd488b 100644
--- a/PermissionController/res/values-v31/styles.xml
+++ b/PermissionController/res/values-v31/styles.xml
@@ -90,6 +90,12 @@
parent="@style/PermissionGrantButtonTop"></style>
<style name="PermissionGrantButtonAllowOneTimeMaterial3"
parent="@style/PermissionGrantButtonMiddle"></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"
@@ -115,136 +121,4 @@
<item name="android:textDirection">locale</item>
<item name="android:textAppearance">?android:attr/textAppearanceListItem</item>
</style>
-
- <!-- START SAFETY Center QUICK SETTINGS PAGE -->
-
- <style name="SafetyCenterLinkText">
- <item name="android:layout_marginTop">5dp</item>
- <item name="android:layout_marginBottom">5dp</item>
- <item name="android:layout_marginStart">5dp</item>
- <item name="android:layout_marginEnd">5dp</item>
- <item name="android:paddingTop">10dp</item>
- <item name="android:paddingBottom">10dp</item>
- <item name="android:paddingStart">10dp</item>
- <item name="android:paddingEnd">10dp</item>
- <item name="android:textDirection">locale</item>
- <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
- </style>
-
- <style name="SafetyCenterToggleText" parent="Theme.AppCompat">
- <item name="android:layout_marginTop">2dp</item>
- <item name="android:layout_marginStart">5dp</item>
- <item name="android:layout_marginEnd">5dp</item>
- <item name="android:textDirection">locale</item>
- <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
- </style>
-
- <style name="SafetyCenterSensorToggleButton" parent="SafetyCenterLinkText">
- <item name="android:background">@drawable/safety_center_button_background</item>
- </style>
-
- <style name="TextAppearance.SafetyStatusTitle"
- parent="@android:style/TextAppearance.DeviceDefault.Medium">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:textSize">22sp</item>
- <item name="android:textColor">?android:attr/textColorPrimary</item>
- </style>
-
- <style name="TextAppearance.SafetyStatusSummary"
- parent="@android:style/TextAppearance.DeviceDefault.Small">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
- <item name="android:textSize">14sp</item>
- <item name="android:textColor">?android:attr/textColorSecondary</item>
- </style>
-
- <style name="SafetyCenter.RescanButton"
- parent="android:Widget.DeviceDefault.Button.Colored">
- <item name="android:layout_marginStart">24dp</item>
- <item name="android:layout_marginEnd">24dp</item>
- </style>
-
- <style name="SafetyCenter.IssueCard"
- parent="android:Widget.DeviceDefault">
- <item name="android:paddingStart">20dp</item>
- <item name="android:paddingEnd">20dp</item>
- <item name="android:paddingTop">20dp</item>
- <item name="android:paddingBottom">8dp</item>
- <item name="android:layout_marginTop">8dp</item>
- <item name="android:layout_marginStart">16dp</item>
- <item name="android:layout_marginBottom">8dp</item>
- <item name="android:layout_marginEnd">16dp</item>
- <item name="android:background">@drawable/safety_center_card_background</item>
- </style>
-
- <style name="SafetyCenter.IssueCard.TopRow"
- parent="android:Widget.DeviceDefault">
- <item name="android:paddingBottom">8dp</item>
- </style>
-
- <style name="SafetyCenter.IssueCard.Dismiss"
- parent="android:Widget.DeviceDefault.ImageButton">
- <item name="android:background">@android:color/transparent</item>
- </style>
-
- <style name="SafetyCenter.IssueCard.Title"
- parent="@android:style/TextAppearance.Material.Subhead">
- <item name="android:textSize">20sp</item>
- <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
- <item name="android:textColor">?android:attr/textColorPrimary</item>
- </style>
-
- <style name="SafetyCenter.IssueCard.Subtitle"
- parent="@android:style/TextAppearance.DeviceDefault">
- <item name="android:textColor">?android:attr/textColorSecondary</item>
- <item name="android:textSize">14sp</item>
- </style>
-
- <style name="SafetyCenter.IssueCard.Summary"
- parent="@android:style/TextAppearance.DeviceDefault">
- <item name="android:textColor">?android:attr/textColorSecondary</item>
- <item name="android:textSize">14sp</item>
- </style>
-
- <style name="SafetyCenter.IssueCard.ActionButtonList"
- parent="android:Widget.DeviceDefault" />
-
- <style name="SafetyCenter.IssueCard.ActionButton"
- parent="android:Widget.DeviceDefault.Button.Colored" />
-
- <style name="IndicatorCardView"
- xmlns:card_view="http://schemas.android.com/apk/res-auto"
- xmlns:app="http://schemas.android.com/apk/res-auto" >
- <item name="android:layout_width">match_parent</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="app:cardCornerRadius">20dp</item>
- <item name="app:cardElevation">0dp</item>
- <item name="app:cardBackgroundColor">#2f3133</item>
- <item name="card_view:contentPaddingBottom">15dp</item>
- <item name="card_view:contentPaddingTop">15dp</item>
- <item name="card_view:contentPaddingLeft">15dp</item>
- <item name="card_view:contentPaddingRight">15dp</item>
- </style>
-
- <style name="ExpandedCardView" parent="Theme.MaterialComponents">
- <item name="android:layout_marginBottom">0dp</item>
- <item name="android:layout_marginStart">0dp</item>
- <item name="android:layout_marginEnd">0dp</item>
- <item name="cardElevation">0dp</item>
- <item name="cardBackgroundColor">#454749</item>
- </style>
-
- <style name="TopCornersCardView" parent="ExpandedCardView">
- <item name="cornerSizeTopRight">8dp</item>
- <item name="cornerSizeTopLeft">8dp</item>
- <item name="cornerSizeBottomRight">0dp</item>
- <item name="cornerSizeBottomLeft">0dp</item>
- </style>
-
- <style name="BottomCornersCardView" parent="ExpandedCardView">
- <item name="cornerSizeTopRight">0dp</item>
- <item name="cornerSizeTopLeft">0dp</item>
- <item name="cornerSizeBottomRight">8dp</item>
- <item name="cornerSizeBottomLeft">8dp</item>
- </style>
-
</resources>
diff --git a/PermissionController/res/values-v33/attrs.xml b/PermissionController/res/values-v33/attrs.xml
new file mode 100644
index 000000000..b59716f6d
--- /dev/null
+++ b/PermissionController/res/values-v33/attrs.xml
@@ -0,0 +1,43 @@
+<?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>
+ <attr name="colorSurface" format="color" />
+ <attr name="colorSurfaceVariant" format="color" />
+ <attr name="colorAccentPrimary" format="color" />
+ <attr name="colorScStatusInfo" format="color" />
+ <attr name="colorScStatusRecommend" format="color" />
+ <attr name="colorScStatusWarn" format="color" />
+ <attr name="colorScStatusBackgroundInfo" format="color" />
+ <attr name="colorScStatusBackgroundRecommend" format="color" />
+ <attr name="colorScStatusBackgroundWarn" format="color" />
+ <attr name="textColorScActionButton" format="color" />
+ <attr name="textColorScSecondaryActionButton" format="color" />
+ <attr name="colorScIconInfo" format="color" />
+ <attr name="colorScIconRecommend" format="color" />
+ <attr name="colorScIconWarn" format="color" />
+ <attr name="colorScIconNull" format="color" />
+ <attr name="colorScOutlineButtonInfoBase" format="color" />
+ <attr name="colorScOutlineButtonRecommendBase" format="color" />
+ <attr name="colorScOutlineButtonWarnBase" format="color" />
+
+ <attr name="scStatusTitleAndSummaryContainerStyle" format="reference" />
+ <attr name="scStatusButtonStyle" 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/bools.xml b/PermissionController/res/values-v33/bools.xml
new file mode 100644
index 000000000..35be913a5
--- /dev/null
+++ b/PermissionController/res/values-v33/bools.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <bool name="is_at_least_t">true</bool>
+</resources>
diff --git a/PermissionController/res/values-v33/colors.xml b/PermissionController/res/values-v33/colors.xml
new file mode 100644
index 000000000..140f78ccd
--- /dev/null
+++ b/PermissionController/res/values-v33/colors.xml
@@ -0,0 +1,99 @@
+<?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.
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- sc_surface_light is a ColorStateList in colors-v33 (requires L* attribute) -->
+ <color name="sc_surface_dark">@android:color/system_neutral1_800</color>
+
+ <color name="sc_surface_variant_light">@android:color/system_neutral2_100</color>
+ <color name="sc_surface_variant_dark">@android:color/system_neutral1_700</color>
+
+ <color name="sc_accent_primary_light">@android:color/system_accent1_100</color>
+ <color name="sc_accent_primary_dark">@android:color/system_accent1_100</color>
+
+ <color name="sc_status_info_light">@color/gm_green_600</color>
+ <color name="sc_status_recommend_light">@color/gm_yellow_600</color>
+ <color name="sc_status_warn_light">@color/gm_red_600</color>
+
+ <color name="sc_status_info_dark">@color/gm_green_500</color>
+ <color name="sc_status_recommend_dark">@color/gm_yellow_500</color>
+ <color name="sc_status_warn_dark">@color/gm_red_500</color>
+
+ <color name="sc_status_background_info_light">@color/gm_green_100</color>
+ <color name="sc_status_background_recommend_light">@color/gm_yellow_100</color>
+ <color name="sc_status_background_warn_light">@color/gm_red_100</color>
+
+ <color name="sc_status_background_info_dark">@color/sc_surface_variant_dark</color>
+ <color name="sc_status_background_recommend_dark">@color/sc_surface_variant_dark</color>
+ <color name="sc_status_background_warn_dark">@color/sc_surface_variant_dark</color>
+
+ <color name="sc_icon_info_light">@color/gm_green_500</color>
+ <color name="sc_icon_recommend_light">@color/gm_yellow_500</color>
+ <color name="sc_icon_warn_light">@color/gm_red_500</color>
+ <color name="sc_icon_null_light">@color/gm_grey_600</color>
+
+ <color name="sc_icon_info_dark">@color/sc_icon_info_light</color>
+ <color name="sc_icon_recommend_dark">@color/sc_icon_recommend_light</color>
+ <color name="sc_icon_warn_dark">@color/sc_icon_warn_light</color>
+ <color name="sc_icon_null_dark">@color/sc_icon_null_light</color>
+
+ <color name="sc_shield_accent">#FFFFFF</color>
+
+ <color name="sc_primary_action_button_text">@android:color/black</color>
+
+ <color name="sc_outline_button_info_base_light">@color/gm_green_300</color>
+ <color name="sc_outline_button_recommend_base_light">@color/gm_yellow_300</color>
+ <color name="sc_outline_button_warn_base_light">@color/gm_red_300</color>
+
+ <color name="sc_outline_button_info_base_dark">@color/sc_outline_button_info_base_light</color>
+ <color name="sc_outline_button_recommend_base_dark">
+ @color/sc_outline_button_recommend_base_light
+ </color>
+ <color name="sc_outline_button_warn_base_dark">@color/sc_outline_button_warn_base_light</color>
+
+ <!-- Green status color aligned with Personal Safety app, instead of vanilla GM colors -->
+ <color name="sc_semantic_green">#0E8435</color>
+
+ <color name="gm_grey_900">#202124</color>
+
+ <color name="gm_green_600">#1E8E3E</color>
+ <color name="gm_yellow_600">#F9AB00</color>
+ <color name="gm_red_600">#D93025</color>
+ <color name="gm_grey_600">#80868B</color>
+
+ <color name="gm_green_500">#34A853</color>
+ <color name="gm_yellow_500">#FBBC04</color>
+ <color name="gm_red_500">#EA4335</color>
+
+ <color name="gm_green_400">#5BB974</color>
+ <color name="gm_yellow_400">#FCC934</color>
+ <color name="gm_red_400">#EE675C</color>
+ <color name="gm_grey_400">#BDC1C6</color>
+
+ <color name="gm_green_300">#81C995</color>
+ <color name="gm_yellow_300">#FDD663</color>
+ <color name="gm_red_300">#F28B82</color>
+
+ <color name="gm_green_100">#CEEAD6</color>
+ <color name="gm_yellow_100">#FEEFC3</color>
+ <color name="gm_red_100">#FAD2CF</color>
+
+ <!-- DEPRECATED: use theme attributes instead -->
+ <color name="safety_center_info">@color/gm_green_500</color>
+ <color name="safety_center_recommend">@color/gm_yellow_500</color>
+ <color name="safety_center_warn">@color/gm_red_500</color>
+
+</resources>
diff --git a/PermissionController/res/values-v33/dimens.xml b/PermissionController/res/values-v33/dimens.xml
new file mode 100644
index 000000000..ef70d2711
--- /dev/null
+++ b/PermissionController/res/values-v33/dimens.xml
@@ -0,0 +1,55 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <dimen name="sc_spacing_xxxsmall">2dp</dimen>
+ <dimen name="sc_spacing_xxsmall">4dp</dimen>
+ <dimen name="sc_spacing_xsmall">8dp</dimen>
+ <dimen name="sc_spacing_small">12dp</dimen>
+ <dimen name="sc_spacing_medium">14dp</dimen>
+ <dimen name="sc_spacing_large">16dp</dimen>
+ <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>
+ <dimen name="sc_action_button_list_margin">@dimen/sc_spacing_large</dimen>
+ <dimen name="sc_top_action_button_margin">@dimen/sc_spacing_xxxlarge</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>
+ <dimen name="sc_card_corner_radius_large">28dp</dimen>
+ <dimen name="sc_card_corner_radius_medium">20dp</dimen>
+ <dimen name="sc_card_corner_radius_xsmall">4dp</dimen>
+ <dimen name="sc_card_widget_corner_radius">16dp</dimen>
+
+ <dimen name="sc_qs_max_width">492dp</dimen>
+
+ <dimen name="sc_line_height_xlarge">28sp</dimen>
+ <dimen name="sc_line_height_large">24sp</dimen>
+ <dimen name="sc_line_height_medium">20sp</dimen>
+ <dimen name="sc_line_height_small">16dp</dimen>
+</resources>
diff --git a/PermissionController/res/values-v33/strings.xml b/PermissionController/res/values-v33/strings.xml
index 5e8421956..2267d068e 100644
--- a/PermissionController/res/values-v33/strings.xml
+++ b/PermissionController/res/values-v33/strings.xml
@@ -15,7 +15,7 @@
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Description when an app requests to become the default dialer app. [CHAR LIMIT=NONE] -->
<string name="role_dialer_request_description">This app will be allowed to send you Notifications, and will be given access to your Camera, Contacts, Microphone, Phone, and SMS</string>
<!-- Description when an app requests to become the default SMS app. [CHAR LIMIT=NONE] -->
@@ -23,4 +23,63 @@
<!-- Label for showing a permission group's description in the header of the list of apps that have the Storage permission [CHAR LIMIT=none] -->
<string name="permission_description_summary_storage">Apps with this permission can access all files on this device</string>
+
+ <!-- Title for the "Your Work Policy" under Advanced Settings in Safety Center for managed devices. [CHAR LIMIT=NONE]-->
+ <string name="work_policy_title" >Your work policy info</string>
+ <!-- Summary for the "Your Work Policy" for Advanced Settings in Safety Center for managed devices. [CHAR LIMIT=NONE]-->
+ <string name="work_policy_summary">Settings managed by your IT admin</string>
+
+ <!-- Label for expanding an entry group in Safety Center [CHAR LIMIT=NONE] -->
+ <string name="safety_center_entry_group_expand_action">Expand and show list</string>
+ <!-- Label for collapsing an entry group in Safety Center [CHAR LIMIT=NONE] -->
+ <string name="safety_center_entry_group_collapse_action">Collapse list and hide settings</string>
+ <!-- Content description for a safety center entry group [CHAR LIMIT=NONE]-->
+ <string name="safety_center_entry_group_content_description">List. <xliff:g id="entry title" example="App security">%1$s</xliff:g>. <xliff:g id="entry summary" example="Scanning is on">%2$s</xliff:g></string>
+ <!-- Content description for a safety center entry group with actions needed [CHAR LIMIT=NONE]-->
+ <string name="safety_center_entry_group_with_actions_needed_content_description">List. <xliff:g id="entry title" example="App security">%1$s</xliff:g>. Actions needed. <xliff:g id="entry summary" example="Scanning is on">%2$s</xliff:g></string>
+ <!-- Content description for a safety center entry group item [CHAR LIMIT=NONE]-->
+ <string name="safety_center_entry_group_item_content_description">List item. <xliff:g id="entry item title" example="App security">%1$s</xliff:g>. <xliff:g id="entry item summary" example="Scanning is on">%2$s</xliff:g></string>
+ <!-- Content description for a safety center entry [CHAR LIMIT=NONE]-->
+ <string name="safety_center_entry_content_description"> <xliff:g id="entry item title" example="App security">%1$s</xliff:g>. <xliff:g id="entry item summary" example="Scanning is on">%2$s</xliff:g></string>
+ <!-- Title for the "More alerts" card in Safety Center [CHAR LIMIT=NONE]-->
+ <string name="safety_center_more_issues_card_title">More alerts</string>
+ <!-- Title for the "Dismissed alerts" card in Safety Center [CHAR LIMIT=NONE]-->
+ <string name="safety_center_dismissed_issues_card_title">Dismissed alerts</string>
+ <!-- Label for expanding the "See all alerts"/"More issues" card in Safety Center [CHAR LIMIT=NONE] -->
+ <string name="safety_center_more_issues_card_expand_action">
+ {count, plural,
+ =1 {Expand and see one more alert}
+ other {Expand and see # more alerts}
+ }
+ </string>
+ <!-- Content description prefixing the first text view of a safety center issue card preference [CHAR LIMIT=NONE]-->
+ <string name="safety_center_issue_card_prefix_content_description">Alert. <xliff:g id="issue card title" example="Protect your account">%1$s</xliff:g></string>
+
+ <!-- Issue resolution confirmation text [CHAR LIMIT=NONE]-->
+ <string name="safety_center_resolved_issue_fallback">Action complete</string>
+
+ <!--Summary for safety center status card QS in case of pending actions [CHAR LIMIT=NONE] -->
+ <string name="safety_center_qs_status_summary">Check settings that can add protection to your device</string>
+ <!-- Content description for the safety center quick settings page landing [CHAR LIMIT=NONE] -->
+ <string name="safety_center_qs_page_landing">Security and privacy quick settings</string>
+ <!-- Content description for close button of the safety center quick settings [CHAR LIMIT=NONE] -->
+ <string name="safety_center_qs_close_button">Close</string>
+ <!-- Label for expanding the permission usage card in safety center quick settings [CHAR LIMIT=NONE] -->
+ <string name="safety_center_qs_expand_action">Expand and show options</string>
+ <!-- Label for collapsing the permission usage card in safety center quick settings [CHAR LIMIT=NONE] -->
+ <string name="safety_center_qs_collapse_action">Collapse</string>
+ <!-- Content description for the privacy controls of the safety center quick settings [CHAR LIMIT=NONE] -->
+ <string name="safety_center_qs_privacy_control">Switch. <xliff:g id="privacy control title" example="Camera">%1$s</xliff:g>. <xliff:g id="privacy control status" example="Available">%2$s</xliff:g></string>
+ <!-- Label for toggling controls of the safety center quick settings [CHAR LIMIT=NONE] -->
+ <string name="safety_center_qs_toggle_action">Toggle</string>
+ <!-- Label for opening safety center from quick settings [CHAR LIMIT=NONE] -->
+ <string name="safety_center_qs_open_action">Open</string>
+ <!--Label for the button that takes the user to Safety center in case of pending actions [CHAR LIMIT=NONE] -->
+ <string name="safety_center_review_settings_button">Review settings</string>
+
+ <!-- Content description for the Gear icon -->
+ <string name="safety_center_gear_label">Settings</string>
+ <!-- Content description for the Information icon -->
+ <string name="safety_center_info_label">Information</string>
+
</resources>
diff --git a/PermissionController/res/values-v33/styles.xml b/PermissionController/res/values-v33/styles.xml
new file mode 100644
index 000000000..a0938665f
--- /dev/null
+++ b/PermissionController/res/values-v33/styles.xml
@@ -0,0 +1,810 @@
+<!--
+ ~ 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.
+ -->
+
+<resources
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- START SAFETY CENTER QUICK SETTINGS PAGE -->
+
+ <style name="SafetyCenterQsContainer"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center_horizontal</item>
+ <item name="android:clipChildren">false</item>
+ </style>
+
+ <style name="SafetyCenterQsBody">
+ <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:layout_gravity">center_horizontal</item>
+ </style>
+
+ <style name="SafetyCenterQsBaseTextContainer">
+ <item name="android:hyphenationFrequency">normalFast</item>
+ </style>
+
+ <style name="SafetyCenterLinkText"
+ parent="SafetyCenterQsBaseTextContainer">
+ <item name="android:textDirection">locale</item>
+ <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
+ </style>
+
+ <style name="SafetyCenterQsCloseButton"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:layout_width">24dp</item>
+ <item name="android:layout_height">24dp</item>
+ <item name="android:layout_gravity">start</item>
+ <item name="android:layout_marginBottom">@dimen/sc_spacing_xxxlarge</item>
+ <item name="android:layout_marginStart">@dimen/sc_list_margin</item>
+ <item name="android:layout_marginTop">@dimen/sc_spacing_xxxlarge</item>
+ <item name="android:tint">?android:attr/textColorPrimary</item>
+ </style>
+
+ <style name="SafetyCenterQsSectionTitle"
+ parent="SafetyCenterQsBaseTextContainer">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginTop">@dimen/sc_spacing_xxlarge</item>
+ <item name="android:textColor">?attr/colorAccentPrimary</item>
+ <item name="android:paddingStart">@dimen/sc_spacing_xxxlarge</item>
+ <item name="android:paddingEnd">@dimen/sc_list_margin</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:lineHeight">24sp</item>
+ <item name="android:textAlignment">viewStart</item>
+ <item name="android:textAppearance">@style/TextAppearance.SafetyCenter.Medium</item>
+ </style>
+
+ <style name="SafetyCenterQsPermissionUsage">
+ <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:paddingStart">@dimen/sc_list_margin</item>
+ <item name="android:paddingEnd">@dimen/sc_list_margin</item>
+ <item name="android:layout_marginBottom">@dimen/sc_spacing_xsmall</item>
+ </style>
+
+ <style name="SafetyCenterQsPreferences">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginTop">@dimen/sc_spacing_xsmall</item>
+ </style>
+
+ <style name="SafetyCenterQsToggleContainer">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:orientation">vertical</item>
+ <item name="android:layout_marginStart">@dimen/sc_list_margin</item>
+ <item name="android:layout_marginEnd">@dimen/sc_list_margin</item>
+ <item name="android:layout_marginTop">@dimen/sc_spacing_large</item>
+ <item name="android:layout_marginBottom">@dimen/sc_spacing_large</item>
+ <item name="android:paddingStart">@dimen/sc_spacing_small</item>
+ <item name="android:paddingEnd">@dimen/sc_spacing_small</item>
+ <item name="android:paddingTop">@dimen/sc_spacing_small</item>
+ <item name="android:paddingBottom">@dimen/sc_spacing_small</item>
+ </style>
+
+ <style name="SafetyCenterQsToggleRow">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:gravity">center_horizontal</item>
+ <item name="android:orientation">horizontal</item>
+ </style>
+
+ <style name="SafetyCenterQsToggleButton">
+ <item name="android:background">@drawable/safety_center_sensor_toggle_enabled</item>
+ <item name="android:layout_width">0dp</item>
+ <item name="android:layout_height">80dp</item>
+ <item name="android:orientation">horizontal</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:layout_weight">0.5</item>
+ <item name="android:layout_marginStart">@dimen/sc_spacing_xxsmall</item>
+ <item name="android:layout_marginEnd">@dimen/sc_spacing_xxsmall</item>
+ <item name="android:layout_marginTop">@dimen/sc_spacing_xxsmall</item>
+ <item name="android:layout_marginBottom">@dimen/sc_spacing_xxsmall</item>
+ </style>
+
+ <style name="SafetyCenterQsToggleTextContainer">
+ <item name="android:layout_width">0dp</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:gravity">start|center_vertical</item>
+ <item name="android:layout_gravity">center_vertical</item>
+ <item name="android:orientation">vertical</item>
+ <item name="android:layout_weight">1</item>
+ </style>
+
+ <style name="SafetyCenterQsToggleText"
+ parent="SafetyCenterQsBaseTextContainer">
+ <item name="android:gravity">center</item>
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:marqueeRepeatLimit">marquee_forever</item>
+ <item name="android:focusable">false</item>
+ <item name="android:focusableInTouchMode">false</item>
+ <item name="android:scrollHorizontally">true</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:layout_marginEnd">@dimen/sc_spacing_large</item>
+ <item name="android:textAlignment">viewStart</item>
+ </style>
+
+ <style name="SafetyCenterQsToggleText.Title">
+ <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
+ <item name="android:textAppearance">@style/TextAppearance.SafetyCenter.Medium</item>
+ <item name="android:lineHeight">@dimen/sc_line_height_medium</item>
+ </style>
+
+ <style name="SafetyCenterQsToggleText.Subtitle">
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:textAppearance">@style/TextAppearance.SafetyCenter.Body</item>
+ <item name="android:lineHeight">@dimen/sc_line_height_medium</item>
+ </style>
+
+ <style name="SafetyCenterQsToggleArrow">
+ <item name="android:layout_width">20dp</item>
+ <item name="android:layout_height">20dp</item>
+ <item name="android:gravity">center</item>
+ <item name="android:layout_gravity">end|center_vertical</item>
+ <item name="android:layout_marginEnd">@dimen/sc_spacing_small</item>
+ </style>
+
+ <style name="SafetyCenterQsToggleIcon">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginStart">@dimen/sc_spacing_large</item>
+ <item name="android:layout_marginEnd">10dp</item>
+ <item name="android:layout_gravity">start|center_vertical</item>
+ <item name="android:adjustViewBounds">true</item>
+ <item name="android:scaleType">fitCenter</item>
+ <item name="android:maxWidth">20dp</item>
+ <item name="android:maxHeight">20dp</item>
+ </style>
+
+ <style name="SafetyCenterIndicatorCardView">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="cardCornerRadius">@dimen/sc_card_corner_radius_large</item>
+ <item name="cardElevation">0dp</item>
+ <item name="cardBackgroundColor">?attr/colorSurface</item>
+ <item name="android:layout_marginTop">@dimen/sc_spacing_large</item>
+ <item name="android:clickable">true</item>
+ <item name="android:foreground">?android:attr/selectableItemBackground</item>
+ </style>
+
+ <style name="SafetyCenterIndicatorImageView">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginStart">@dimen/sc_spacing_xxxlarge</item>
+ <item name="android:layout_centerVertical">true</item>
+ <item name="android:clickable">false</item>
+ </style>
+
+ <style name="SafetyCenterIndicatorTitleText"
+ parent="SafetyCenterQsBaseTextContainer">
+ <item name="android:layout_width">0dp</item>
+ <item name="android:layout_marginStart">@dimen/sc_spacing_large</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginTop">@dimen/sc_spacing_xxxlarge</item>
+ <item name="android:textAlignment">viewStart</item>
+ <item name="android:textAppearance">@style/TextAppearance.SafetyCenter.Medium</item>
+ <item name="android:lineHeight">@dimen/sc_line_height_medium</item>
+ </style>
+
+ <style name="SafetyCenterIndicatorLabelText"
+ parent="SafetyCenterQsBaseTextContainer">
+ <item name="android:layout_width">0dp</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginTop">@dimen/sc_spacing_xxxsmall</item>
+ <item name="android:layout_marginBottom">@dimen/sc_spacing_xxxlarge</item>
+ <item name="android:textAlignment">viewStart</item>
+ <item name="android:textAppearance">@style/TextAppearance.SafetyCenter.Body</item>
+ <item name="android:lineHeight">@dimen/sc_line_height_medium</item>
+ </style>
+
+ <style name="SafetyCenterIndicatorExpandView">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginEnd">@dimen/sc_spacing_xxxlarge</item>
+ </style>
+
+ <style name="SafetyCenterIndicatorActionButton"
+ parent="@style/Widget.MaterialComponents.Button.OutlinedButton">
+ <item name="android:layout_width">0dp</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginStart">@dimen/sc_spacing_xxxlarge</item>
+ <item name="android:layout_marginEnd">@dimen/sc_spacing_xxxlarge</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:paddingTop">18dp</item>
+ <item name="android:paddingBottom">18dp</item>
+ <item name="android:paddingStart">24dp</item>
+ <item name="android:paddingEnd">24dp</item>
+ <item name="android:ellipsize">end</item>
+ <item name="android:maxLines">3</item>
+ <item name="android:theme">@style/Theme.MaterialComponents</item>
+ <item name="android:insetTop">0dp</item>
+ <item name="android:insetBottom">0dp</item>
+ <item name="android:textAppearance">@style/TextAppearance.SafetyCenter.ActionButton</item>
+ <item name="android:hyphenationFrequency">normalFast</item>
+ <item name="cornerRadius">12dp</item>
+ <item name="rippleColor">?android:colorControlHighlight</item>
+ </style>
+
+ <style name="SafetyCenterIndicatorSecondaryActionButton"
+ parent="@style/SafetyCenterIndicatorActionButton">
+ <item name="android:layout_marginBottom">@dimen/sc_spacing_xxxlarge</item>
+ <item name="android:layout_marginTop">@dimen/sc_spacing_large</item>
+ </style>
+
+ <style name="SafetyCenterIndicatorForeground">
+ <item name="android:clickable">true</item>
+ <item name="android:foreground">?android:attr/selectableItemBackground</item>
+ </style>
+
+ <!-- END SAFETY CENTER QUICK SETTINGS PAGE -->
+
+ <!-- START SAFETY CENTER SETTINGS PAGE -->
+
+ <style name="TextAppearance.SafetyCenter.Headline"
+ parent="@android:style/TextAppearance.DeviceDefault.Headline" />
+
+ <style name="TextAppearance.SafetyCenter.Headline.Status">
+ <item name="android:textSize">22sp</item>
+ </style>
+ <style name="TextAppearance.SafetyCenter.Headline.Issue">
+ <item name="android:textSize">20sp</item>
+ </style>
+ <style name="TextAppearance.SafetyCenter.Headline.Entry">
+ <item name="android:textSize">20sp</item>
+ </style>
+
+ <style name="TextAppearance.SafetyCenter.Body"
+ parent="@android:style/TextAppearance.DeviceDefault.Small">
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ </style>
+
+ <style name="TextAppearance.SafetyCenter.IssueAttribution"
+ parent="TextAppearance.SafetyCenter.Body">
+ <item name="android:textSize">12sp</item>
+ </style>
+
+ <style name="TextAppearance.SafetyCenter.Medium"
+ parent="@android:style/TextAppearance.DeviceDefault.Medium">
+ <item name="android:textSize">14sp</item>
+ </style>
+
+ <style name="TextAppearance.SafetyCenter.IssueSubtitle"
+ parent="TextAppearance.SafetyCenter.Medium">
+ <item name="android:textSize">16sp</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
+
+ <style name="TextAppearance.SafetyCenter.ActionButton"
+ parent="TextAppearance.SafetyCenter.Medium">
+ <item name="android:capitalize">sentences</item>
+ </style>
+
+ <style name="TextAppearance.SafetyCenter.ActionButton.Secondary">
+ <item name="android:textColor">?attr/textColorScSecondaryActionButton</item>
+ </style>
+
+ <style name="SafetyCenterBaseTextContainer">
+ <item name="android:hyphenationFrequency">normalFast</item>
+ </style>
+
+ <style name="SafetyCenterBaseTextWidget"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:hyphenationFrequency">normalFast</item>
+ </style>
+
+ <style name="SafetyCenterCard"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:paddingStart">@dimen/sc_spacing_xxxlarge</item>
+ <item name="android:paddingEnd">@dimen/sc_spacing_xxxlarge</item>
+ <item name="android:paddingTop">@dimen/sc_spacing_xxxlarge</item>
+ <item name="android:paddingBottom">@dimen/sc_card_margin_bottom</item>
+ <item name="android:layout_marginStart">@dimen/sc_spacing_large</item>
+ <item name="android:layout_marginEnd">@dimen/sc_spacing_large</item>
+ <item name="android:background">@drawable/safety_center_card_background</item>
+ </style>
+
+ <style name="SafetyCenterActionButton"
+ parent="@style/Widget.MaterialComponents.Button.UnelevatedButton">
+ <item name="android:theme">@style/Theme.MaterialComponents</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:paddingTop">@dimen/sc_spacing_xlarge</item>
+ <item name="android:paddingBottom">@dimen/sc_spacing_xlarge</item>
+ <item name="android:insetTop">0dp</item>
+ <item name="android:insetBottom">0dp</item>
+ <item name="android:textAppearance">@style/TextAppearance.SafetyCenter.ActionButton</item>
+ <item name="android:hyphenationFrequency">normalFast</item>
+ <item name="android:textColor">?attr/textColorScActionButton</item>
+ <item name="android:maxLines">3</item>
+ <item name="android:ellipsize">end</item>
+ <item name="cornerRadius">@dimen/sc_button_corner_radius</item>
+ <item name="rippleColor">?android:colorControlHighlight</item>
+ </style>
+
+ <style name="SafetyCenterActionButton.Secondary"
+ parent="@style/Widget.MaterialComponents.Button.OutlinedButton">
+ <item name="android:theme">@style/Theme.MaterialComponents</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:paddingTop">@dimen/sc_spacing_xlarge</item>
+ <item name="android:paddingBottom">@dimen/sc_spacing_xlarge</item>
+ <item name="android:insetTop">0dp</item>
+ <item name="android:insetBottom">0dp</item>
+ <item name="android:textAppearance">
+ @style/TextAppearance.SafetyCenter.ActionButton.Secondary
+ </item>
+ <item name="android:hyphenationFrequency">normalFast</item>
+ <item name="android:textColor">?attr/textColorScSecondaryActionButton</item>
+ <item name="android:maxLines">3</item>
+ <item name="android:ellipsize">end</item>
+ <item name="cornerRadius">@dimen/sc_button_corner_radius</item>
+ <item name="rippleColor">?android:colorControlHighlight</item>
+ </style>
+
+ <!-- START SAFETY STATUS CARD -->
+ <style name="SafetyCenterCard.Status">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ </style>
+
+ <style name="SafetyCenterStatusImage" parent="android:Widget.DeviceDefault">
+ <item name="android:layout_width">56dp</item>
+ <item name="android:layout_height">56dp</item>
+ <item name="layout_constraintTop_toTopOf">parent</item>
+ <item name="layout_constraintBottom_toBottomOf">@id/status_title_and_summary</item>
+ <item name="layout_constraintStart_toStartOf">parent</item>
+ <item name="layout_constraintEnd_toStartOf">@id/status_title_and_summary</item>
+ <item name="android:scaleType">centerInside</item>
+ <item name="android:gravity">center</item>
+ </style>
+
+ <style name="SafetyCenterStatusTitleAndSummaryContainer" parent="android:Widget.DeviceDefault">
+ <item name="android:layout_width">0dp</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:orientation">vertical</item>
+ <item name="android:layout_marginTop">@dimen/sc_spacing_xxsmall</item>
+ <item name="android:layout_marginStart">@dimen/sc_spacing_large</item>
+ <item name="android:layout_marginEnd">@dimen/sc_spacing_xxxlarge</item>
+ <item name="layout_constraintStart_toEndOf">@id/status_image</item>
+ <item name="layout_constraintEnd_toEndOf">parent</item>
+ <item name="layout_constraintTop_toTopOf">parent</item>
+ </style>
+
+ <style name="SafetyCenterStatusTitleAndSummaryContainer.Fixed" />
+ <style name="SafetyCenterStatusTitleAndSummaryContainer.Responsive" />
+
+ <style name="SafetyCenterStatusTitle"
+ parent="SafetyCenterBaseTextWidget">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:textAppearance">
+ @style/TextAppearance.SafetyCenter.Headline.Status
+ </item>
+ <item name="android:lineHeight">@dimen/sc_line_height_xlarge</item>
+ </style>
+
+ <style name="SafetyCenterStatusSummary"
+ parent="SafetyCenterBaseTextWidget">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:textAppearance">@style/TextAppearance.SafetyCenter.Body</item>
+ <item name="android:lineHeight">@dimen/sc_line_height_medium</item>
+ </style>
+
+ <style name="SafetyCenterStatusButton" parent="SafetyCenterActionButton">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="layout_constraintTop_toBottomOf">@id/status_title_and_summary</item>
+ <item name="layout_constraintBottom_toBottomOf">parent</item>
+ <item name="layout_constraintStart_toStartOf">parent</item>
+ <item name="android:layout_marginTop">@dimen/sc_spacing_xxxlarge</item>
+ <item name="backgroundTint">@color/safety_center_button_info</item>
+ </style>
+
+ <style name="SafetyCenterStatusButton.Fixed" />
+ <style name="SafetyCenterStatusButton.Responsive" />
+
+ <!-- END SAFETY STATUS CARD -->
+
+ <style name="SafetyCenterCard.Issue">
+ <item name="android:orientation">vertical</item>
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginBottom">0dp</item>
+ </style>
+
+ <style name="SafetyCenterIssueDismiss"
+ parent="android:Widget.DeviceDefault.ImageButton">
+ <item name="android:background">@android:color/transparent</item>
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="layout_constraintTop_toTopOf">parent</item>
+ <item name="layout_constraintEnd_toEndOf">parent</item>
+ </style>
+
+ <style name="SafetyCenterIssueAttributionTitle"
+ parent="SafetyCenterBaseTextContainer">
+ <item name="android:textAppearance">
+ @style/TextAppearance.SafetyCenter.IssueAttribution
+ </item>
+ <item name="android:lineHeight">@dimen/sc_line_height_small</item>
+ <item name="android:layout_width">0dp</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="layout_constraintTop_toTopOf">parent</item>
+ <item name="layout_constraintBottom_toTopOf">@id/issue_card_title</item>
+ <item name="layout_constraintStart_toStartOf">parent</item>
+ <item name="layout_constraintEnd_toStartOf">@id/issue_card_dismiss_btn</item>
+ <item name="android:layout_marginBottom">@dimen/sc_spacing_medium</item>
+ <item name="android:layout_marginEnd">@dimen/sc_spacing_xxxlarge</item>
+ </style>
+
+ <style name="SafetyCenterIssueTitle"
+ parent="SafetyCenterBaseTextContainer">
+ <item name="android:textAppearance">@style/TextAppearance.SafetyCenter.Headline.Issue</item>
+ <item name="android:lineHeight">@dimen/sc_line_height_large</item>
+ <item name="android:layout_width">0dp</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="layout_constraintTop_toBottomOf">@id/issue_card_attribution_title</item>
+ <item name="layout_constraintBottom_toTopOf">@id/issue_card_subtitle</item>
+ <item name="layout_constraintStart_toStartOf">parent</item>
+ <item name="layout_constraintEnd_toStartOf">@id/issue_card_dismiss_btn</item>
+ <item name="android:layout_marginEnd">@dimen/sc_spacing_xxxlarge</item>
+ <item name="layout_constraintHorizontal_bias">0</item>
+ <item name="layout_goneMarginEnd">0dp</item>
+ </style>
+
+ <style name="SafetyCenterIssueSubtitle"
+ parent="SafetyCenterBaseTextContainer">
+ <item name="android:textAppearance">@style/TextAppearance.SafetyCenter.IssueSubtitle</item>
+ <item name="android:lineHeight">@dimen/sc_line_height_large</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_width">wrap_content</item>
+ <item name="layout_constraintStart_toStartOf">@id/issue_card_title</item>
+ <item name="layout_constraintTop_toBottomOf">@id/issue_card_title</item>
+ <item name="layout_constraintBottom_toTopOf">@id/issue_card_summary</item>
+ <item name="android:layout_marginTop">@dimen/sc_spacing_xxsmall</item>
+ </style>
+
+ <style name="SafetyCenterIssueSummary"
+ parent="SafetyCenterBaseTextContainer">
+ <item name="android:textAppearance">@style/TextAppearance.SafetyCenter.Body</item>
+ <item name="android:lineHeight">@dimen/sc_line_height_medium</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_width">wrap_content</item>
+ <item name="layout_constraintStart_toStartOf">@id/issue_card_title</item>
+ <item name="layout_constraintTop_toBottomOf">@id/issue_card_subtitle</item>
+ <item name="layout_constraintBottom_toTopOf">@id/issue_card_action_button_list</item>
+ <item name="android:layout_marginTop">@dimen/sc_spacing_large</item>
+ <!-- Use a smaller margin when there's no subtitle -->
+ <item name="layout_goneMarginTop">@dimen/sc_spacing_medium</item>
+ </style>
+
+ <style name="SafetyCenterIssueActionButtonList"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:layout_marginTop">@dimen/sc_spacing_xxlarge</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_width">0dp</item>
+ <item name="android:orientation">vertical</item>
+ <item name="layout_constraintTop_toBottomOf">@id/issue_card_summary</item>
+ <item name="layout_constraintStart_toStartOf">parent</item>
+ <item name="layout_constraintEnd_toEndOf">parent</item>
+ </style>
+
+ <style name="SafetyCenterIssueSafetyProtectionSection">
+ <item name="android:gravity">center</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_width">0dp</item>
+ <item name="layout_constraintTop_toBottomOf">@id/issue_card_action_button_list</item>
+ <item name="layout_constraintStart_toStartOf">parent</item>
+ <item name="layout_constraintEnd_toEndOf">parent</item>
+ <item name="android:paddingTop">@dimen/sc_spacing_xxlarge</item>
+ <item name="android:paddingBottom">@dimen/sc_spacing_xxlarge</item>
+ </style>
+
+ <style name="SafetyCenterIssueCardResolvedImage" parent="android:Widget.DeviceDefault">
+ <item name="android:layout_width">0dp</item>
+ <item name="android:layout_height">0dp</item>
+ <item name="android:gravity">center</item>
+ <item name="layout_constraintWidth_default">wrap</item>
+ <item name="layout_constraintHeight_default">wrap</item>
+ <item name="layout_constraintWidth_max">112dp</item>
+ <item name="layout_constraintHeight_max">112dp</item>
+ <item name="layout_constraintWidth_min">84dp</item>
+ <item name="layout_constraintHeight_min">84dp</item>
+ <item name="layout_constraintTop_toTopOf">parent</item>
+ <item name="layout_constraintBottom_toTopOf">@id/resolved_issue_text</item>
+ <item name="layout_constraintStart_toStartOf">parent</item>
+ <item name="layout_constraintEnd_toEndOf">parent</item>
+ <item name="layout_constraintVertical_chainStyle">packed</item>
+ </style>
+
+ <style name="SafetyCenterIssueCardResolvedTitle"
+ parent="SafetyCenterBaseTextContainer">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textSize">16sp</item>
+ <item name="android:lineHeight">24sp</item>
+ <item name="android:textAppearance">@style/TextAppearance.SafetyCenter.Medium</item>
+ <item name="android:paddingTop">@dimen/sc_spacing_large</item>
+ <item name="android:gravity">center</item>
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="layout_constraintTop_toBottomOf">@id/resolved_issue_image</item>
+ <item name="layout_constraintBottom_toBottomOf">parent</item>
+ <item name="layout_constraintStart_toStartOf">parent</item>
+ <item name="layout_constraintEnd_toEndOf">parent</item>
+ </style>
+
+ <style name="SafetyCenterMoreIssuesCollapsed"
+ parent="SafetyCenterCard.Issue">
+ <item name="android:layout_marginTop">@dimen/sc_spacing_xlarge</item>
+ <item name="android:paddingVertical">@dimen/sc_spacing_xlarge</item>
+ <item name="android:background">@drawable/safety_center_more_issues_card_background</item>
+ </style>
+
+ <style name="SafetyCenterMoreIssuesTitle"
+ parent="SafetyCenterBaseTextContainer">
+ <item name="android:textAppearance">@style/TextAppearance.Material3.LabelLarge</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_width">0dp</item>
+ <item name="android:layout_marginStart">@dimen/sc_spacing_xxlarge</item>
+ <item name="android:layout_marginEnd">@dimen/sc_spacing_xxlarge</item>
+ <item name="android:maxLines">2</item>
+ <item name="android:ellipsize">end</item>
+ <item name="layout_constraintTop_toTopOf">parent</item>
+ <item name="layout_constraintBottom_toBottomOf">parent</item>
+ <item name="layout_constraintStart_toEndOf">@id/status_icon</item>
+ <item name="layout_constraintEnd_toStartOf">@android:id/widget_frame</item>
+ <item name="layout_constraintHorizontal_bias">0</item>
+ <item name="layout_goneMarginStart">0dp</item>
+ </style>
+
+ <style name="SafetyCenterMoreIssuesIcon"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:layout_height">20dp</item>
+ <item name="android:layout_width">20dp</item>
+ <item name="android:gravity">center</item>
+ <item name="layout_constraintTop_toTopOf">parent</item>
+ <item name="layout_constraintBottom_toBottomOf">parent</item>
+ <item name="layout_constraintStart_toStartOf">parent</item>
+ </style>
+
+ <style name="SafetyCenterMoreIssuesCounter"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:layout_height">24dp</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:background">@drawable/safety_center_card_widget_background</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="layout_constraintTop_toTopOf">parent</item>
+ <item name="layout_constraintBottom_toBottomOf">parent</item>
+ <item name="layout_constraintEnd_toEndOf">parent</item>
+ </style>
+
+ <style name="SafetyCenterMoreIssuesWidgetTitle"
+ parent="SafetyCenterBaseTextContainer">
+ <item name="android:textAppearance">@style/TextAppearance.SafetyCenter.Body</item>
+ <item name="android:lineHeight">@dimen/sc_line_height_medium</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>
+ <item name="android:layout_marginEnd">@dimen/sc_spacing_xxxsmall</item>
+ <item name="android:maxLines">1</item>
+ </style>
+
+ <style name="SafetyCenterMoreIssuesWidgetIcon"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:layout_height">16dp</item>
+ <item name="android:layout_width">16dp</item>
+ <item name="android:gravity">center</item>
+ <item name="android:scaleType">fitCenter</item>
+ </style>
+
+ <style name="SafetyCenterEntry"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginStart">@dimen/sc_spacing_large</item>
+ <item name="android:layout_marginEnd">@dimen/sc_spacing_large</item>
+ <item name="android:paddingEnd">@dimen/sc_entry_padding_end</item>
+ <item name="android:paddingTop">@dimen/sc_spacing_large</item>
+ <item name="android:paddingBottom">@dimen/sc_spacing_large</item>
+ <item name="android:baselineAligned">false</item>
+ <item name="android:minHeight">?android:attr/listPreferredItemHeight</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:orientation">horizontal</item>
+ </style>
+
+ <style name="SafetyCenterEntryDivider"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:layout_width">1dp</item>
+ <item name="android:layout_height">28dp</item>
+ <item name="android:background">?android:attr/textColorSecondary</item>
+ </style>
+
+ <style name="SafetyCenterEntryWidgetFrame"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:orientation">horizontal</item>
+ </style>
+
+ <style name="SafetyCenterEntryIconFrame"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:paddingStart">@dimen/sc_spacing_xxxlarge</item>
+ <item name="android:paddingEnd">@dimen/sc_spacing_xxlarge</item>
+ </style>
+
+ <style name="SafetyCenterEntryIcon"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:layout_width">20dp</item>
+ <item name="android:layout_height">20dp</item>
+ <item name="android:layout_gravity">center</item>
+ </style>
+
+ <style name="SafetyCenterEntryEmptySpace"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:layout_width">@dimen/sc_spacing_xxxlarge</item>
+ <item name="android:layout_height">match_parent</item>
+ </style>
+
+ <style name="SafetyCenterEntryTextContainer"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:layout_width">0dp</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:layout_weight">1</item>
+ <item name="android:orientation">vertical</item>
+ </style>
+
+ <style name="SafetyCenterEntryTitle"
+ parent="SafetyCenterBaseTextWidget">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:textAppearance">
+ @style/TextAppearance.SafetyCenter.Headline.Entry
+ </item>
+ <item name="android:lineHeight">@dimen/sc_line_height_large</item>
+ <item name="android:ellipsize">end</item>
+ <item name="android:maxLines">4</item>
+ </style>
+
+ <style name="SafetyCenterEntrySummary"
+ parent="SafetyCenterBaseTextWidget">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:textAppearance">@style/TextAppearance.SafetyCenter.Body</item>
+ <item name="android:lineHeight">@dimen/sc_line_height_medium</item>
+ <item name="android:ellipsize">end</item>
+ <item name="android:maxLines">4</item>
+ </style>
+
+ <style name="SafetyCenterEntryIconAction"
+ parent="android:Widget.DeviceDefault.Button.Borderless">
+ <item name="android:layout_width">68dp</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:layout_gravity">center</item>
+ <item name="android:paddingStart">@dimen/sc_spacing_xxlarge</item>
+ <item name="android:paddingEnd">@dimen/sc_entry_padding_end</item>
+ <item name="android:background">@drawable/safety_entry_icon_action_background</item>
+ </style>
+
+ <style name="SafetyCenterGroup"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginStart">@dimen/sc_spacing_large</item>
+ <item name="android:layout_marginEnd">@dimen/sc_spacing_large</item>
+ <item name="android:baselineAligned">false</item>
+ <item name="android:minHeight">?android:attr/listPreferredItemHeight</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:orientation">vertical</item>
+ </style>
+
+ <style name="SafetyCenterGroupHeader"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:paddingEnd">@dimen/sc_spacing_xxxlarge</item>
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:baselineAligned">false</item>
+ <item name="android:orientation">horizontal</item>
+ </style>
+
+ <style name="SafetyCenterCollapsedGroupHeader"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:layout_width">0dp</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_weight">1</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:orientation">horizontal</item>
+ </style>
+
+ <style name="SafetyCenterExpandedGroupHeader"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:paddingStart">@dimen/sc_spacing_xxxlarge</item>
+ <item name="android:paddingTop">@dimen/sc_spacing_xxxsmall</item>
+ <item name="android:paddingBottom">@dimen/sc_spacing_medium</item>
+ <item name="android:layout_width">0dp</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_weight">1</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:orientation">horizontal</item>
+ </style>
+
+ <style name="SafetyCenterExpandedGroupTitle"
+ parent="SafetyCenterBaseTextWidget">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:textAppearance">@style/TextAppearance.SafetyCenter.Body</item>
+ <item name="android:lineHeight">@dimen/sc_line_height_medium</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:ellipsize">end</item>
+ <item name="android:maxLines">4</item>
+ </style>
+
+ <style name="SafetyCenterGroupEntries"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:paddingBottom">@dimen/sc_spacing_medium</item>
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:orientation">vertical</item>
+ </style>
+
+ <style name="SafetyCenterGroupWidgetFrame"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:orientation">vertical</item>
+ </style>
+
+ <style name="SafetyCenterExpandedGroupIcon"
+ parent="android:Widget.DeviceDefault">
+ <item name="android:layout_width">24dp</item>
+ <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>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:paddingEnd">@dimen/sc_entry_padding_end</item>
+ <item name="android:paddingTop">@dimen/sc_spacing_large</item>
+ <item name="android:paddingBottom">@dimen/sc_spacing_large</item>
+ <item name="android:baselineAligned">false</item>
+ <item name="android:minHeight">?android:attr/listPreferredItemHeight</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:orientation">horizontal</item>
+ </style>
+</resources>
diff --git a/PermissionController/res/values-v33/themes.xml b/PermissionController/res/values-v33/themes.xml
new file mode 100644
index 000000000..338cbaa01
--- /dev/null
+++ b/PermissionController/res/values-v33/themes.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <style name="Theme.SafetyCenterQsBase" parent="@android:style/Theme.DeviceDefault.NoActionBar">
+ <item name="android:filterTouchesWhenObscured">true</item>
+
+ <!-- Safety Center Quick Settings uses dark mode resources -->
+ <item name="colorSurface">@color/sc_surface_dark</item>
+ <item name="colorSurfaceVariant">@color/sc_surface_variant_dark</item>
+ <item name="colorAccentPrimary">@color/sc_accent_primary_dark</item>
+
+ <item name="colorScStatusInfo">@color/sc_status_info_dark</item>
+ <item name="colorScStatusRecommend">@color/sc_status_recommend_dark</item>
+ <item name="colorScStatusWarn">@color/sc_status_warn_dark</item>
+
+ <item name="colorScStatusBackgroundInfo">@color/sc_status_background_info_dark</item>
+ <item name="colorScStatusBackgroundRecommend">
+ @color/sc_status_background_recommend_dark
+ </item>
+ <item name="colorScStatusBackgroundWarn">@color/sc_status_background_warn_dark</item>
+
+ <item name="colorScIconInfo">@color/sc_icon_info_dark</item>
+ <item name="colorScIconRecommend">@color/sc_icon_recommend_dark</item>
+ <item name="colorScIconWarn">@color/sc_icon_warn_dark</item>
+ <item name="colorScIconNull">@color/sc_icon_null_dark</item>
+
+ <item name="colorScShieldAccent">@color/sc_shield_accent</item>
+
+ <item name="scStatusTitleAndSummaryContainerStyle">
+ @style/SafetyCenterStatusTitleAndSummaryContainer.Fixed
+ </item>
+ <item name="scStatusButtonStyle">@style/SafetyCenterStatusButton.Fixed</item>
+
+ <!-- Buttons -->
+ <item name="scActionButtonStyle">@style/SafetyCenterActionButton</item>
+ <item name="scSecondaryActionButtonStyle">@style/SafetyCenterActionButton.Secondary</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="colorScOutlineButtonInfoBase">@color/sc_outline_button_info_base_dark</item>
+ <item name="colorScOutlineButtonRecommendBase">
+ @color/sc_outline_button_recommend_base_dark
+ </item>
+ <item name="colorScOutlineButtonWarnBase">@color/sc_outline_button_warn_base_dark</item>
+ </style>
+
+ <style name="Theme.SafetyCenterQs" parent="Theme.SafetyCenterQsBase" />
+
+ <style name="Theme.SafetyCenterBase" parent="Theme.PermissionController.Settings.FilterTouches">
+ <item name="colorSurface">@color/sc_surface_light</item>
+ <item name="colorSurfaceVariant">@color/sc_surface_variant_light</item>
+ <item name="colorAccentPrimary">@color/sc_accent_primary_light</item>
+
+ <item name="colorScStatusInfo">@color/sc_status_info_light</item>
+ <item name="colorScStatusRecommend">@color/sc_status_recommend_light</item>
+ <item name="colorScStatusWarn">@color/sc_status_warn_light</item>
+
+ <item name="colorScStatusBackgroundInfo">@color/sc_status_background_info_light</item>
+ <item name="colorScStatusBackgroundRecommend">
+ @color/sc_status_background_recommend_light
+ </item>
+ <item name="colorScStatusBackgroundWarn">@color/sc_status_background_warn_light</item>
+
+ <item name="colorScIconInfo">@color/sc_icon_info_light</item>
+ <item name="colorScIconRecommend">@color/sc_icon_recommend_light</item>
+ <item name="colorScIconWarn">@color/sc_icon_warn_light</item>
+ <item name="colorScIconNull">@color/sc_icon_null_light</item>
+
+ <item name="colorScShieldAccent">@color/sc_shield_accent</item>
+
+ <item name="scStatusTitleAndSummaryContainerStyle">
+ @style/SafetyCenterStatusTitleAndSummaryContainer.Responsive
+ </item>
+ <item name="scStatusButtonStyle">@style/SafetyCenterStatusButton.Responsive</item>
+
+ <!-- Buttons -->
+ <item name="scActionButtonStyle">@style/SafetyCenterActionButton</item>
+ <item name="scSecondaryActionButtonStyle">@style/SafetyCenterActionButton.Secondary</item>
+
+ <item name="textColorScActionButton">@color/sc_primary_action_button_text</item>
+ <item name="textColorScSecondaryActionButton">?android:attr/textColorPrimary</item>
+
+ <item name="colorScOutlineButtonInfoBase">@color/sc_outline_button_info_base_light</item>
+ <item name="colorScOutlineButtonRecommendBase">
+ @color/sc_outline_button_recommend_base_light
+ </item>
+ <item name="colorScOutlineButtonWarnBase">@color/sc_outline_button_warn_base_light</item>
+ </style>
+
+ <style name="Theme.SafetyCenter" parent="Theme.SafetyCenterBase" />
+</resources> \ No newline at end of file
diff --git a/PermissionController/res/values-v34/bools.xml b/PermissionController/res/values-v34/bools.xml
new file mode 100644
index 000000000..a0e3741a9
--- /dev/null
+++ b/PermissionController/res/values-v34/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_u">true</bool>
+</resources>
diff --git a/PermissionController/res/values-v34/colors.xml b/PermissionController/res/values-v34/colors.xml
new file mode 100644
index 000000000..1bc237188
--- /dev/null
+++ b/PermissionController/res/values-v34/colors.xml
@@ -0,0 +1,55 @@
+<?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>
+ <!-- colorAccentPrimaryVariant is not visible from mainline, so UX provided this alternative -->
+ <color name="permission_rationale_accent_primary_variant">@android:color/system_accent1_600</color>
+
+ <color name="sc_surface_light">@android:color/system_surface_bright_light</color>
+ <color name="sc_surface_dark">@android:color/system_surface_bright_dark</color>
+
+ <color name="sc_surface_variant_light">@android:color/system_surface_container_high_light</color>
+ <color name="sc_surface_variant_dark">@android:color/system_surface_container_high_dark</color>
+
+ <color name="sc_accent_primary_light">@android:color/system_primary_light</color>
+ <color name="sc_accent_primary_dark">@android:color/system_primary_dark</color>
+
+ <color name="sc_status_info_light">@color/sc_semantic_green</color>
+
+ <color name="sc_status_info_dark">@color/gm_green_400</color>
+ <color name="sc_status_recommend_dark">@color/gm_yellow_400</color>
+ <color name="sc_status_warn_dark">@color/gm_red_400</color>
+
+ <color name="sc_icon_info_dark">@color/gm_green_400</color>
+ <color name="sc_icon_recommend_dark">@color/gm_yellow_400</color>
+ <color name="sc_icon_warn_dark">@color/gm_red_400</color>
+ <color name="sc_icon_null_dark">@color/gm_grey_400</color>
+
+ <color name="sc_shield_accent_light">@color/sc_shield_accent</color>
+ <color name="sc_shield_accent_dark">@color/gm_grey_900</color>
+ <color name="sc_shield_accent_fixed_variant">@color/sc_shield_accent_dark</color>
+
+ <color name="sc_primary_action_button_text">@color/gm_grey_900</color>
+
+ <color name="sc_outline_button_info_base_light">@color/gm_green_500</color>
+ <color name="sc_outline_button_recommend_base_light">@color/gm_yellow_500</color>
+ <color name="sc_outline_button_warn_base_light">@color/gm_red_500</color>
+
+ <color name="sc_outline_button_info_base_dark">@color/gm_green_400</color>
+ <color name="sc_outline_button_recommend_base_dark">@color/gm_yellow_400</color>
+ <color name="sc_outline_button_warn_base_dark">@color/gm_red_400</color>
+</resources>
diff --git a/PermissionController/res/values-v34/dimens.xml b/PermissionController/res/values-v34/dimens.xml
new file mode 100644
index 000000000..2e8b50fd0
--- /dev/null
+++ b/PermissionController/res/values-v34/dimens.xml
@@ -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.
+ -->
+
+<resources>
+ <dimen name="permission_rationale_purpose_list_bullet_radius">1.5dp</dimen>
+ <dimen name="permission_rationale_purpose_list_bullet_indent">9dp</dimen>
+
+ <dimen name="sc_action_button_list_margin">@dimen/sc_spacing_xxsmall</dimen>
+ <dimen name="sc_button_corner_radius_small">4dp</dimen>
+ <dimen name="sc_brand_chip_corner_radius">20dp</dimen>
+ <dimen name="sc_brand_chip_padding">6dp</dimen>
+</resources> \ No newline at end of file
diff --git a/PermissionController/res/values-v34/ids.xml b/PermissionController/res/values-v34/ids.xml
new file mode 100644
index 000000000..179c30745
--- /dev/null
+++ b/PermissionController/res/values-v34/ids.xml
@@ -0,0 +1,19 @@
+<!--
+ ~ 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>
+ <item type="id" name="preference_highlighted" />
+</resources> \ No newline at end of file
diff --git a/PermissionController/res/values-v34/strings.xml b/PermissionController/res/values-v34/strings.xml
new file mode 100644
index 000000000..30181aa02
--- /dev/null
+++ b/PermissionController/res/values-v34/strings.xml
@@ -0,0 +1,35 @@
+<?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">
+ <!-- String representing the security and privacy brand name [CHAR LIMIT=NONE] -->
+ <string name="security_privacy_brand_name">Security &amp; privacy</string>
+ <!-- Header for the controls category on the privacy subpage of Safety Center [CHAR LIMIT=NONE] -->
+ <string name="privacy_subpage_controls_header">Controls</string>
+
+ <!-- Title shown for Health Connect [CHAR LIMIT=50] -->
+ <string name="health_connect_title" description="Health connect title">Health&#160;Connect</string>
+ <string name="health_connect_summary" description="Health connect summary, which describes what user can do when they click Health Connect">Manage app access to health data</string>
+
+ <!-- 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] -->
+ <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>
+</resources>
diff --git a/PermissionController/res/values-v34/styles.xml b/PermissionController/res/values-v34/styles.xml
new file mode 100644
index 000000000..53780ce76
--- /dev/null
+++ b/PermissionController/res/values-v34/styles.xml
@@ -0,0 +1,374 @@
+<?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>
+
+ <!-- START PERMISSION RATIONALE DIALOG -->
+
+ <style name="PermissionRationaleScrollView">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">0dp</item>
+ <item name="android:layout_weight">1</item>
+ <item name="android:scrollbars">none</item>
+ <item name="android:scrollIndicators">bottom</item>
+ <item name="android:fillViewport">true</item>
+ <item name="android:clipChildren">false</item>
+ </style>
+
+ <style name="PermissionRationaleSingleton">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:gravity">center</item>
+ </style>
+
+ <style name="PermissionRationaleDialog">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:background">?android:attr/windowBackground</item>
+ <item name="android:orientation">vertical</item>
+ <item name="android:showDividers">middle</item>
+ </style>
+
+ <style name="PermissionRationaleContent">
+ <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">24dp</item>
+ <item name="android:paddingBottom">8dp</item>
+ <item name="android:paddingStart">24dp</item>
+ <item name="android:paddingEnd">24dp</item>
+ </style>
+
+ <style name="PermissionRationaleTitleContainer">
+ <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:gravity">center</item>
+ </style>
+
+ <style name="PermissionRationaleTitleIcon">
+ <item name="android:layout_width">32dp</item>
+ <item name="android:layout_height">32dp</item>
+ <item name="android:layout_marginBottom">16dp</item>
+ <item name="android:tint">?android:attr/textColorSecondary</item>
+ <item name="android:scaleType">centerInside</item>
+ </style>
+
+ <style name="PermissionRationaleTitleMessage"
+ parent="@android:style/TextAppearance.DeviceDefault">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:fontFamily">google-sans</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textSize">24sp</item>
+ <item name="android:lineHeight">32sp</item>
+ <item name="android:gravity">center</item>
+ </style>
+
+ <style name="PermissionRationaleSectionOuterContainer">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:orientation">horizontal</item>
+ <item name="android:layout_marginTop">16dp</item>
+ </style>
+
+ <style name="PermissionRationaleSectionIcon">
+ <item name="android:layout_width">20dp</item>
+ <item name="android:layout_height">20dp</item>
+ <item name="android:tint">?android:attr/textColorSecondary</item>
+ <item name="android:scaleType">centerInside</item>
+ </style>
+
+ <style name="PermissionRationaleSectionInnerContainer">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:orientation">vertical</item>
+ <item name="android:layout_marginStart">16dp</item>
+ </style>
+
+ <style name="PermissionRationaleSectionTitle"
+ parent="@android:style/TextAppearance.DeviceDefault.Medium">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:fontFamily">google-sans-text-medium</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textColorLink">@color/permission_rationale_accent_primary_variant</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:lineHeight">20sp</item>
+ <item name="android:lineSpacingMultiplier">1.25</item>
+ </style>
+
+ <style name="PermissionRationaleSectionMessage"
+ parent="@android:style/TextAppearance.DeviceDefault">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginTop">4dp</item>
+ <item name="android:fontFamily">google-sans-text</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:textColorLink">@color/permission_rationale_accent_primary_variant</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:lineHeight">20sp</item>
+ <item name="android:lineSpacingMultiplier">1.25</item>
+ </style>
+
+ <style name="PermissionRationaleSectionPurposeList"
+ parent="@style/PermissionRationaleSectionMessage">
+ <item name="android:layout_marginStart">@dimen/permission_rationale_purpose_list_bullet_indent</item>
+ </style>
+
+ <style name="PermissionRationaleButtonContainer">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_weight">0</item>
+ <item name="android:paddingStart">24dp</item>
+ <item name="android:paddingEnd">24dp</item>
+ <item name="android:paddingTop">20dp</item>
+ <item name="android:paddingBottom">20dp</item>
+ <item name="android:orientation">horizontal</item>
+ <item name="android:gravity">end</item>
+ </style>
+
+ <style name="PermissionRationaleBackButton"
+ parent="@style/Widget.Material3.Button.OutlinedButton">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:gravity">center</item>
+ <item name="android:insetTop">6dp</item>
+ <item name="android:insetBottom">6dp</item>
+ <item name="android:minWidth">48dp</item>
+ <item name="android:minHeight">48dp</item>
+ <item name="android:paddingTop">8dp</item>
+ <item name="android:paddingBottom">8dp</item>
+ <item name="android:paddingStart">16dp</item>
+ <item name="android:paddingEnd">16dp</item>
+ <item name="android:fontFamily">google-sans-text-medium</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:lineHeight">20sp</item>
+ <item name="android:lineSpacingMultiplier">1.25</item>
+ <item name="strokeColor">@color/permission_rationale_accent_primary_variant</item>
+ </style>
+
+ <!-- END PERMISSION RATIONALE DIALOG -->
+
+ <!-- START APP DATA SHARING UPDATES PAGE -->
+
+ <style name="AppDataSharingDetailsContainer">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginStart">24dp</item>
+ <item name="android:layout_marginEnd">24dp</item>
+ <item name="android:orientation">vertical</item>
+ <item name="android:clipToPadding">false</item>
+ <item name="android:textDirection">locale</item>
+ <item name="android:layoutDirection">locale</item>
+ </style>
+
+ <style name="AppDataSharingDetailsTextAppearance"
+ parent="@android:style/TextAppearance.DeviceDefault">
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:lineHeight">20sp</item>
+ </style>
+
+ <style name="AppDataSharingDetailsMessage">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginTop">8dp</item>
+ <item name="android:layout_marginBottom">12dp</item>
+ <item name="android:textAppearance">@style/AppDataSharingDetailsTextAppearance</item>
+ </style>
+
+ <style name="AppDataSharingNoUpdatesTextAppearance"
+ parent="@android:style/TextAppearance.DeviceDefault">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textSize">20sp</item>
+ <item name="android:lineHeight">24sp</item>
+ </style>
+
+ <style name="AppDataSharingNoUpdatesMessage">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginTop">28dp</item>
+ <item name="android:layout_marginBottom">24dp</item>
+ <item name="android:textAppearance">@style/AppDataSharingNoUpdatesTextAppearance</item>
+ </style>
+
+ <style name="AppDataSharingUpdatesFooterContainer">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginStart">24dp</item>
+ <item name="android:layout_marginEnd">24dp</item>
+ <item name="android:orientation">vertical</item>
+ <item name="android:clipToPadding">false</item>
+ <item name="android:textDirection">locale</item>
+ <item name="android:layoutDirection">locale</item>
+ </style>
+
+ <style name="AppDataSharingUpdatesFooterIconFrame">
+ <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:background">@android:color/transparent</item>
+ </style>
+
+ <style name="AppDataSharingUpdatesFooterIcon">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="maxHeight">24dp</item>
+ <item name="maxWidth">24dp</item>
+ </style>
+
+ <style name="AppDataSharingUpdatesFooterTextAppearance"
+ parent="@android:style/TextAppearance.DeviceDefault">
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:lineHeight">20sp</item>
+ </style>
+
+ <style name="AppDataSharingUpdatesFooterMessage">
+ <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:layout_marginBottom">8dp</item>
+ <item name="android:textAppearance">@style/AppDataSharingUpdatesFooterTextAppearance</item>
+ </style>
+
+ <style name="AppDataSharingUpdatesFooterLink"
+ parent="@android:style/TextAppearance.DeviceDefault">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:lineHeight">20sp</item>
+ <item name="android:textColorLink">@color/permission_rationale_accent_primary_variant</item>
+ </style>
+
+ <style name="AppDataSharingUpdatePreference">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:minHeight">?android:attr/listPreferredItemHeightSmall</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:paddingTop">20dp</item>
+ <item name="android:paddingBottom">20dp</item>
+ <item name="android:paddingStart">24dp</item>
+ <item name="android:paddingEnd">24dp</item>
+ <item name="android:clipToPadding">false</item>
+ <item name="android:textDirection">locale</item>
+ <item name="android:layoutDirection">locale</item>
+ </style>
+
+ <style name="AppDataSharingUpdateAppIconFrame">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:paddingEnd">20dp</item>
+ </style>
+
+ <style name="AppDataSharingUpdateAppIcon">
+ <item name="android:id">@android:id/icon</item>
+ <item name="android:layout_width">32dp</item>
+ <item name="android:layout_height">32dp</item>
+ <item name="android:layout_gravity">center_vertical</item>
+ </style>
+
+ <style name="AppDataSharingUpdatePreferenceTitleAndSummaryContainer">
+ <item name="android:layout_width">0px</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_weight">1</item>
+ </style>
+
+ <style name="AppDataSharingUpdatePreferenceTitle">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:textAppearance">?android:attr/textAppearanceListItem</item>
+ <item name="android:ellipsize">marquee</item>
+ </style>
+
+ <style name="AppDataSharingUpdatePreferenceSummary">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_below">@android:id/title</item>
+ <item name="android:layout_alignStart">@android:id/title</item>
+ <item name="android:textAppearance">?android:attr/textAppearanceListItemSecondary</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:maxLines">10</item>
+ </style>
+
+ <style name="AppDataSharingUpdateSettingsIconFrame">
+ <item name="android:layout_width">48dp</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:gravity">end|center_vertical</item>
+ <item name="android:orientation">vertical</item>
+ <item name="android:paddingStart">24dp</item>
+ </style>
+
+ <style name="AppDataSharingUpdateSettingsIcon">
+ <item name="android:layout_width">24dp</item>
+ <item name="android:layout_height">24dp</item>
+ <item name="android:layout_gravity">end|center_vertical</item>
+ <item name="android:contentDescription">@string/settings</item>
+ <item name="android:src">@drawable/ic_settings_gear</item>
+ </style>
+
+ <!-- END APP DATA SHARING UPDATES PAGE -->
+
+ <!-- START SAFETY CENTER SUBPAGE -->
+
+ <style name="SafetyCenterBrandChip">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:paddingHorizontal">@dimen/sc_list_margin</item>
+ </style>
+
+ <style name="SafetyCenterBrandChipButton"
+ parent="android:Widget.DeviceDefault.Button.Borderless">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <!-- Widget.DeviceDefault.Button has a minHeight that's larger than our chip spec. -->
+ <item name="android:minHeight">0dp</item>
+ <item name="android:layout_gravity">center_vertical|start</item>
+ <item name="android:paddingVertical">@dimen/sc_brand_chip_padding</item>
+ <item name="android:paddingHorizontal">@dimen/sc_spacing_small</item>
+ <item name="android:drawableStart">@drawable/ic_safety_center_brand_chip</item>
+ <item name="android:drawablePadding">@dimen/sc_brand_chip_padding</item>
+ <item name="android:background">@drawable/safety_center_brand_chip_background</item>
+ <item name="android:textAppearance">@style/TextAppearance.SafetyCenter.BrandChip</item>
+ </style>
+
+ <style name="TextAppearance.SafetyCenter.BrandChip"
+ parent="TextAppearance.SafetyCenter.IssueSubtitle">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
+
+ <style name="SafetyCenterIllustration">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:importantForAccessibility">noHideDescendants</item>
+ <item name="android:layout_marginTop">@dimen/sc_spacing_large</item>
+ <item name="android:paddingHorizontal">@dimen/sc_spacing_large</item>
+ </style>
+
+ <style name="SafetyCenterIllustrationView">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center</item>
+ <item name="android:adjustViewBounds">true</item>
+ </style>
+
+ <!-- END SAFETY CENTER SUBPAGE -->
+
+</resources> \ No newline at end of file
diff --git a/PermissionController/res/values-v34/themes.xml b/PermissionController/res/values-v34/themes.xml
new file mode 100644
index 000000000..b96bdb9f9
--- /dev/null
+++ b/PermissionController/res/values-v34/themes.xml
@@ -0,0 +1,30 @@
+<?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>
+ <style name="Theme.PermissionRationaleDialog"
+ parent="@android:style/Theme.DeviceDefault.Light.Dialog">
+ </style>
+
+ <style name="Theme.SafetyCenterQs" parent="Theme.SafetyCenterQsBase">
+ <item name="colorScShieldAccent">@color/sc_shield_accent_dark</item>
+ </style>
+
+ <style name="Theme.SafetyCenter" parent="Theme.SafetyCenterBase">
+ <item name="colorScShieldAccent">@color/sc_shield_accent_light</item>
+ </style>
+</resources> \ No newline at end of file
diff --git a/PermissionController/res/values-vi-v33/strings.xml b/PermissionController/res/values-vi-v33/strings.xml
index ed9eb018f..d5fdffc1e 100644
--- a/PermissionController/res/values-vi-v33/strings.xml
+++ b/PermissionController/res/values-vi-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Ứng dụng này sẽ được phép gửi Thông báo cũng như cấp quyền truy cập vào Máy ảnh, Danh bạ, Micrô, Điện thoại và tin nhắn SMS của bạn"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Ứng dụng này sẽ được phép gửi Thông báo cũng như được cấp quyền truy cập vào Máy ảnh, Danh bạ, Tệp, Micrô, Điện thoại và tin nhắn SMS của bạn"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Ứng dụng được cấp quyền này có thể truy cập tất cả các tệp trên thiết bị này"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Thông tin về chính sách công việc của bạn"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Chế độ cài đặt do quản trị viên CNTT quản lý"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Mở rộng và hiện danh sách"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Thu gọn danh sách và ẩn chế độ cài đặt"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Danh sách. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Danh sách. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Việc cần làm. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Mục trong danh sách. <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Đóng"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Mở rộng và hiển thị các tùy chọn"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Thu gọn"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Chuyển. <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">"Bật/tắt"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Mở"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Xem lại các chế độ cài đặt"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Cài đặt"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Thông tin"</string>
</resources>
diff --git a/PermissionController/res/values-vi-v34/strings.xml b/PermissionController/res/values-vi-v34/strings.xml
new file mode 100644
index 000000000..618a266d8
--- /dev/null
+++ b/PermissionController/res/values-vi-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Bảo mật và quyền riêng tư"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Các chế độ kiểm soát"</string>
+ <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">"Á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 621ddc1b2..3fa50ca58 100644
--- a/PermissionController/res/values-vi/strings.xml
+++ b/PermissionController/res/values-vi/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Quay lại"</string>
<string name="available" msgid="6007778121920339498">"Được phép"</string>
<string name="blocked" msgid="9195547604866033708">"Bị chặn"</string>
+ <string name="on" msgid="280241003226755921">"Đang bật"</string>
+ <string name="off" msgid="1438489226422866263">"Tắt"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Gỡ cài đặt hoặc vô hiệu hóa"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"Không tìm thấy ứng dụng"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Không cho phép"</string>
@@ -30,11 +32,16 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Duy trì tùy chọn “Khi đang dùng ứng dụng”"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Duy trì tùy chọn “Chỉ lần này”"</string>
<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_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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Đã phát hiện lớp phủ màn hình"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Để thay đổi tùy chọn cài đặt quyền này, trước tiên, bạn phải tắt lớp phủ màn hình trong phần Cài đặt &gt; Ứng dụng"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Mở cài đặt"</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>
@@ -130,21 +134,20 @@
<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>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Tìm hiểu thêm về <xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Kiểm soát quyền truy cập của ứng dụng vào <xliff:g id="PERMGROUP">%1$s</xliff:g> của bạn"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 ngày}other{# ngày}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 giờ}other{# giờ}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 phút}other{# phút}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 giây}other{# giây}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# ngày}other{# ngày}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# giờ}other{# giờ}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# phút}other{# phút}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# giây}other{# giây}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Mọi quyền"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Mọi lúc"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"7 ngày qua"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"24 giờ qua"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"1 giờ qua"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"15 phút qua"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"1 phút qua"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{# ngày qua}other{# ngày qua}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{# giờ qua}other{# giờ qua}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{# phút qua}other{# phút qua}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Không sử dụng quyền"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Lần truy cập gần đây nhất vào bất kỳ thời gian nào"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Lần truy cập gần đây nhất trong 7 ngày qua"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Tần suất sử dụng quyền trong 1 giờ trước"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Tần suất sử dụng quyền trong 15 phút trước"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Tần suất sử dụng quyền trong 1 phút trước"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Không sử dụng trong 24 giờ qua"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Không sử dụng trong 7 ngày qua"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Không sử dụng trong # ngày qua}other{Không sử dụng trong # ngày qua}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Không sử dụng trong # giờ qua}other{Không sử dụng trong # giờ qua}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{1 ứng dụng đã dùng}other{# ứng dụng đã dùng}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Xem tất cả trong Trang tổng quan"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Lọc theo: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Chỉ cho phép truy cập vào nội dung nghe nhìn"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Luôn cho phép"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Chỉ cho phép khi dùng ứng dụng"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Luôn cho phép tất cả"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Luôn hỏi"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Không cho phép"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Vị trí chính xác"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Các quyền <xliff:g id="PERM_0">%1$s</xliff:g> và <xliff:g id="PERM_1">%2$s</xliff:g> sẽ bị xóa."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Các quyền sau sẽ bị xóa: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Tự động quản lý các quyền"</string>
- <string name="off" msgid="1438489226422866263">"Tắt"</string>
<string name="auto_revoked_app_summary_one" msgid="7093213590301252970">"Đã thu hồi quyền sử dụng <xliff:g id="PERMISSION_NAME">%s</xliff:g>"</string>
<string name="auto_revoked_app_summary_two" msgid="1910545340763709389">"Đã thu hồi quyền đối với <xliff:g id="PERMISSION_NAME_0">%1$s</xliff:g> và <xliff:g id="PERMISSION_NAME_1">%2$s</xliff:g>"</string>
<string name="auto_revoked_app_summary_many" msgid="5930976230827378798">"Đã thu hồi quyền sử dụng <xliff:g id="PERMISSION_NAME">%1$s</xliff:g> và <xliff:g id="NUMBER">%2$s</xliff:g> quyền khác"</string>
<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="3685907153054355671">"Nếu bạn không dùng một ứng dụng trong vài 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="7871347400611202595">"Mở lần cuối cách đây hơn <xliff:g id="NUMBER">%s</xliff:g> tháng trước"</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{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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Không được phép"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Xem thêm ứng dụng có thể truy cập tất cả các tệp"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{1 ngày}other{# ngày}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 giờ}other{# giờ}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 phút}other{# phút}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 giây}other{# giây}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# giờ}other{# giờ}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{# phút}other{# phút}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{# giây}other{# giây}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Lời nhắc về quyền"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"1 ứng dụng không dùng đến"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"<xliff:g id="NUMBER_OF_APPS">%s</xliff:g> ứng dụng không dùng đến"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Bạn không dùng một số ứng dụng trong vài tháng qua. Nhấn để xem."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# ứng dụng không dùng đến}other{# ứng dụng không dùng đến}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Các quyền và tệp tạm thời đã bị xóa. Thông báo đã bị chặn. Hãy nhấn để xem lại."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Xem lại ứng dụng bị xoá quyền"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Đối với ứng dụng bạn không dùng đến sau một thời gian, các quyền và tệp tạm thời đã bị xoá và các thông báo không được gửi nữa."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Xem lại ứng dụng"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Kiểm tra các quyền đã cấp gần đây"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Trong khi lái xe, bạn đã cấp cho <xliff:g id="APP">%1$s</xliff:g> quyền truy cập vào <xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Trong khi lái xe, bạn đã cấp cho <xliff:g id="APP">%1$s</xliff:g> quyền truy cập vào <xliff:g id="PERMISSION_1">%2$s</xliff:g> và <xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Đã thu hồi các quyền để bảo vệ quyền riêng tư của bạn"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> đã truy cập thông tin vị trí của bạn trong nền"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Ứng dụng này luôn có thể truy cập vào thông tin vị trí của bạn. Hãy nhấn để thay đổi."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Xem lại ứng dụng có quyền truy cập vào thông báo"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"<xliff:g id="APP_NAME">%s</xliff:g> có thể loại bỏ, xử lý và truy cập nội dung bên trong thông báo của bạn"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Ứng dụng này có thể loại bỏ, xử lý và truy cập nội dung bên trong thông báo của bạn Một số ứng dụng cần có quyền truy cập này để cung cấp được chức năng như mong muốn."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Xóa quyền truy cập"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Xem tuỳ chọn khác"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Đã xóa quyền truy cập"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Xem lại ứng dụng có đầy đủ quyền truy cập trên thiết bị"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"<xliff:g id="APP_NAME">%s</xliff:g> có thể xem màn hình và thực hiện thao tác trên thiết bị của bạn. Ứng dụng hỗ trợ tiếp cận cần loại quyền truy cập này để cung cấp được chức năng như mong muốn."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Ứng dụng này có thể xem màn hình và thực hiện thao tác trên thiết bị của bạn. Ứng dụng hỗ trợ tiếp cận cần loại quyền truy cập này để cung cấp được chức năng như mong muốn, nhưng hãy kiểm tra để đảm bảo ứng dụng này đáng tin cậy."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Xoá quyền truy cập"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Xem những ứng dụng có đầy đủ quyền truy cập"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Đã xoá quyền truy cập"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Hệ thống Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Đã thu hồi các quyền ứng dụng nhằm bảo vệ quyền riêng tư"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"Bạn chưa dùng <xliff:g id="APP_NAME">%s</xliff:g> trong vài tháng. Nhấn để xem lại."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"Bạn chưa dùng <xliff:g id="APP_NAME">%s</xliff:g> và 1 ứng dụng khác trong vài tháng. Nhấn để xem lại."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"<xliff:g id="APP_NAME">%1$s</xliff:g> sẽ được phép tương tác với thông báo cũng như truy cập vào Điện thoại, SMS, Danh bạ và Lịch."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"<xliff:g id="APP_NAME">%1$s</xliff:g> sẽ được phép tương tác với thông báo cũng như truyền trực tuyến các ứng dụng đến thiết bị đã kết nối."</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Dịch vụ này sẽ chia sẻ ảnh, nội dung nghe nhìn và thông báo trên điện thoại của bạn với các thiết bị khác."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"Ứng dụng ghi chú mặc định"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Các quyền bị kiểm soát"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Ứng dụng có thể truy cập thông tin vị trí"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Quản trị viên CNTT đang cho phép ứng dụng <xliff:g id="APP_NAME">%s</xliff:g> truy cập vào thông tin vị trí của bạn"</string>
+ <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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"Bảo mật và quyền riêng tư"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Quét"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Bảo mật và quyền riêng tư"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Quét thiết bị"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Đóng"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Đóng cảnh báo này?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Hãy xem lại chế độ cài đặt quyền riêng tư và bảo mật để tăng cường biện pháp bảo vệ"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Đóng"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Huỷ"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Cài đặt"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Trạng thái bảo mật và quyền riêng tư. <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">"Cài đặt bảo mật"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Quyền sử dụng cảm biến"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Chế độ kiểm soát quyền riêng tư"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Quyền truy cập"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Bảo mật và quyền riêng tư"</string>
+ <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">"Quyền truy cập máy ảnh"</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="7943349178368641820">"Xem thêm về hoạt động sử dụng máy ảnh"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Xem thêm về hoạt động sử dụng micrô"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Thu hồi quyền sử dụng máy ảnh"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Thu hồi quyền sử dụng micrô"</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>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Xóa quyền truy cập đối với ứng dụng này"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Xóa quyền truy cập đối với ứng dụng này"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Quản lý dịch vụ"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Quản lý quyền"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Đang được dùng cho một cuộc gọi điện thoại"</string>
@@ -517,8 +552,6 @@
<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>) đã dùng gần đây"</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>) đang dùng"</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>) đã dùng gần đây"</string>
- <string name="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Bảo mật và quyền riêng tư"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Kiểm tra trạng thái"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Xác nhận"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Quay lại"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Quyền truy cập vào các tệp khác cũng sẽ được cấp."</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Ứng dụng này không hỗ trợ phiên bản Android mới nhất. Nếu ứng dụng này không thể truy cập vào tệp nhạc và âm thanh, nó cũng sẽ không được phép truy cập vào ảnh và video."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Ứng dụng này không hỗ trợ phiên bản Android mới nhất. Nếu ứng dụng này có thể truy cập vào ảnh và video, nó cũng sẽ được phép truy cập vào các tệp âm thanh và nhạc."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Ứng dụng này không hỗ trợ phiên bản Android mới nhất. Nếu ứng dụng này không thể truy cập vào tệp nhạc và âm thanh, nó cũng sẽ không được phép truy cập vào ảnh và video."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"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_notification_content" msgid="4066560182507301022">"<xliff:g id="APP_NAME">%s</xliff:g> luôn truy cập được vào thông tin vị trí của bạn, ngay cả khi đang đóng"</string>
+ <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 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="mic_toggle_title" msgid="2649991093496110162">"Quyền truy cập micrô"</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 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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Cách thức xử lý 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. "<annotation id="link">"Tìm hiểu thêm về chế độ chia sẻ dữ liệu"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Cách thức xử lý 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="permission_rationale_location_settings_title" msgid="7204145004850190953">"Dữ liệu vị trí của bạn"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Thay đổi quyền truy cập của ứng dụng này trong "<annotation id="link">"chế độ cài đặt quyền riêng tư"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Chức năng của ứng dụng"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Số liệu phân tích"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Thông tin liên lạc của nhà phát triển"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Quảng cáo hoặc tiếp thị"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Chống lừa đảo, bảo mật và tuân thủ quy định"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Cá nhân hoá"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Quản lý tài khoản"</string>
+ <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="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 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>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Cập nhật trong ngày vừa qua}=1{Cập nhật trong ngày vừa qua}other{Cập nhật trong # ngày vừa qua}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Hiện không có nội dung cập nhật nào"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values-w492dp-v33/styles.xml b/PermissionController/res/values-w492dp-v33/styles.xml
new file mode 100644
index 000000000..26d432369
--- /dev/null
+++ b/PermissionController/res/values-w492dp-v33/styles.xml
@@ -0,0 +1,38 @@
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <!-- START SAFETY CENTER QUICK SETTINGS PAGE -->
+
+ <style name="SafetyCenterQsContainer"
+ parent="android:Widget.DeviceDefault">
+ <!-- Limit width on larger screen devices. -->
+ <item name="android:layout_width">@dimen/sc_qs_max_width</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center_horizontal</item>
+ <item name="android:clipChildren">false</item>
+ </style>
+
+ <style name="SafetyCenterQsBody">
+ <!-- Limit width on larger screen devices. -->
+ <item name="android:layout_width">@dimen/sc_qs_max_width</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:orientation">vertical</item>
+ <item name="android:layout_gravity">center_horizontal</item>
+ </style>
+</resources>
diff --git a/PermissionController/res/values-w764dp-v33/dimens.xml b/PermissionController/res/values-w764dp-v33/dimens.xml
new file mode 100644
index 000000000..78b4675f2
--- /dev/null
+++ b/PermissionController/res/values-w764dp-v33/dimens.xml
@@ -0,0 +1,19 @@
+<!--
+ ~ 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>
+ <dimen name="sc_button_horizontal_padding">@dimen/sc_large_screen_button_padding</dimen>
+</resources>
diff --git a/PermissionController/res/values-w764dp-v33/styles.xml b/PermissionController/res/values-w764dp-v33/styles.xml
new file mode 100644
index 000000000..a836e4aa5
--- /dev/null
+++ b/PermissionController/res/values-w764dp-v33/styles.xml
@@ -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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <!-- START SAFETY STATUS CARD -->
+ <style name="SafetyCenterStatusTitleAndSummaryContainer.Responsive">
+ <item name="layout_constraintEnd_toStartOf">@id/sc_status_buttons_start_barrier</item>
+ <!-- Clear the base style constraints so they don't conflict with this style's constraints
+ on the same sides. -->
+ <item name="layout_constraintEnd_toEndOf">@null</item>
+ </style>
+
+ <style name="SafetyCenterStatusButton.Responsive">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="layout_constraintTop_toTopOf">parent</item>
+ <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>
+ <!-- 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>
+ <item name="layout_constraintStart_toStartOf">@null</item>
+ </style>
+</resources>
diff --git a/PermissionController/res/values-w764dp-v34/dimens.xml b/PermissionController/res/values-w764dp-v34/dimens.xml
new file mode 100644
index 000000000..cb336fc3e
--- /dev/null
+++ b/PermissionController/res/values-w764dp-v34/dimens.xml
@@ -0,0 +1,19 @@
+<!--
+ ~ 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>
+ <dimen name="sc_action_button_list_margin">@dimen/sc_spacing_large</dimen>
+</resources>
diff --git a/PermissionController/res/values-w800dp-v33/styles.xml b/PermissionController/res/values-w800dp-v33/styles.xml
new file mode 100644
index 000000000..38ba9d498
--- /dev/null
+++ b/PermissionController/res/values-w800dp-v33/styles.xml
@@ -0,0 +1,38 @@
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <!-- START SAFETY CENTER QUICK SETTINGS PAGE -->
+
+ <style name="SafetyCenterQsContainer"
+ parent="android:Widget.DeviceDefault">
+ <!-- Make width match_parent (mainly for the close button. -->
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center_horizontal</item>
+ <item name="android:clipChildren">false</item>
+ </style>
+
+ <style name="SafetyCenterQsBody">
+ <!-- Continue to limit width on larger screen devices -->
+ <item name="android:layout_width">@dimen/sc_qs_max_width</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center_horizontal</item>
+ <item name="android:orientation">vertical</item>
+ </style>
+</resources>
diff --git a/PermissionController/res/values-zh-rCN-v33/strings.xml b/PermissionController/res/values-zh-rCN-v33/strings.xml
index d48285c67..064e8b581 100644
--- a/PermissionController/res/values-zh-rCN-v33/strings.xml
+++ b/PermissionController/res/values-zh-rCN-v33/strings.xml
@@ -19,4 +19,28 @@
<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_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>
+ <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>
+ <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{展开并查看另外一项提醒}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"关闭"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"展开并显示选项"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"收起"</string>
+ <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_gear_label" msgid="5175877094379694098">"设置"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"信息"</string>
</resources>
diff --git a/PermissionController/res/values-zh-rCN-v34/strings.xml b/PermissionController/res/values-zh-rCN-v34/strings.xml
new file mode 100644
index 000000000..0ba05798b
--- /dev/null
+++ b/PermissionController/res/values-zh-rCN-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-zh-rCN/strings.xml b/PermissionController/res/values-zh-rCN/strings.xml
index 5f1c7e8a9..bde1c8f89 100644
--- a/PermissionController/res/values-zh-rCN/strings.xml
+++ b/PermissionController/res/values-zh-rCN/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"始终全部允许"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"检测到屏幕叠加层"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"要更改此权限设置,您必须首先在“设置”&gt;“应用”中关闭屏幕叠加层"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"打开“设置”"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 天}other{# 天}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 小时}other{# 小时}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 分钟}other{# 分钟}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 秒}other{# 秒}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# 天}other{# 天}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# 小时}other{# 小时}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# 分钟}other{# 分钟}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# 秒}other{# 秒}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"不限权限"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"不限时间"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"过去 7 天"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"过去 24 小时"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"过去 1 小时"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"过去 15 分钟"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"过去 1 分钟"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{过去 # 天}other{过去 # 天}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{过去 # 小时}other{过去 # 小时}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{过去 # 分钟}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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"过去 24 小时内未使用"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"过去 7 天内未使用过"</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_view_details" msgid="6675335735468752787">"在信息中心查看全部详细信息"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"过滤条件:<xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"始终全部允许"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"每次都询问"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"不允许"</string>
<string name="precise_image_description" msgid="6349638632303619872">"确切位置"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"<xliff:g id="PERM_0">%1$s</xliff:g>和<xliff:g id="PERM_1">%2$s</xliff:g>权限将被移除。"</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"即将被移除的权限:<xliff:g id="PERMS">%1$s</xliff:g>。"</string>
<string name="auto_manage_title" msgid="7693181026874842935">"自动管理权限"</string>
- <string name="off" msgid="1438489226422866263">"关闭"</string>
<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_tv_summary" msgid="3685907153054355671">"如果您连续几个月未使用某个应用,系统将对该应用采取以下措施:\n\n• 取消权限以保护您的数据\n• 移除临时文件以释放空间\n\n如需重新授予权限,请打开该应用。"</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"距上次打开已超过 <xliff:g id="NUMBER">%s</xliff:g> 个月"</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>
<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>
@@ -251,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 小时}other{# 小时}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 分钟}other{# 分钟}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 秒}other{# 秒}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# 小时}other{# 小时}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<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_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_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>
<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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android 系统"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"为保护隐私,系统已移除应用权限"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"<xliff:g id="APP_NAME">%s</xliff:g>在几个月内未使用过。点按即可查看。"</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"<xliff:g id="APP_NAME">%s</xliff:g>和另外 1 个应用在几个月内未使用过。点按即可查看。"</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"记事"</string>
<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>
@@ -452,6 +475,7 @@
<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_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="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>
@@ -474,8 +498,8 @@
<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="auto_granted_permissions" msgid="6009452264824455892">"受控权限"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"应用可使用位置信息"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"您的 IT 管理员允许“<xliff:g id="APP_NAME">%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>
@@ -489,24 +513,35 @@
<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>
<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="7514620345152008005">"安全和隐私"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"扫描"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"传感器权限"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"隐私控件"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"已移除权限"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"查看更多相机使用信息"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"查看更多麦克风使用信息"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"移除相机权限"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"移除麦克风权限"</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="manage_service_qs" msgid="7862555549364153805">"管理服务"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"管理权限"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"目前正由手机通话使用"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"安全和隐私"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"查看状态"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"开发者通讯"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{过去 1 天内更新过}=1{过去 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>
</resources>
diff --git a/PermissionController/res/values-zh-rHK-v33/strings.xml b/PermissionController/res/values-zh-rHK-v33/strings.xml
index c9d081dcc..da31b6eae 100644
--- a/PermissionController/res/values-zh-rHK-v33/strings.xml
+++ b/PermissionController/res/values-zh-rHK-v33/strings.xml
@@ -19,4 +19,28 @@
<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_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>
+ <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>
+ <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{展開即可查看多一個警示}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"關閉"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"展開並顯示選項"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"收合"</string>
+ <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_gear_label" msgid="5175877094379694098">"設定"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"資料"</string>
</resources>
diff --git a/PermissionController/res/values-zh-rHK-v34/strings.xml b/PermissionController/res/values-zh-rHK-v34/strings.xml
new file mode 100644
index 000000000..99e078541
--- /dev/null
+++ b/PermissionController/res/values-zh-rHK-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-zh-rHK/strings.xml b/PermissionController/res/values-zh-rHK/strings.xml
index 57a77c403..21bb30b35 100644
--- a/PermissionController/res/values-zh-rHK/strings.xml
+++ b/PermissionController/res/values-zh-rHK/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"一律全部允許"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"偵測到重疊式畫面功能"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"如要變更此權限設定,請先前往 [設定] &gt; [應用程式],以關閉重疊式畫面功能"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"開啟設定"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 天}other{# 天}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 小時}other{# 小時}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 分鐘}other{# 分鐘}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 秒}other{# 秒}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# 天}other{# 天}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# 小時}other{# 小時}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# 分鐘}other{# 分鐘}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# 秒}other{# 秒}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"任何權限"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"不限時間"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"過去 7 天"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"過去 24 小時"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"過去 1 小時"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"過去 15 分鐘"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"過去 1 分鐘"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{過去 # 日}other{過去 # 日}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{過去 # 小時}other{過去 # 小時}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{過去 # 分鐘}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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"過去 24 小時內未使用"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"過去 7 天內未使用"</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_view_details" msgid="6675335735468752787">"在「資訊主頁」查看全部"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"篩選條件:<xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"一律全部允許"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"每次都詢問"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"不允許"</string>
<string name="precise_image_description" msgid="6349638632303619872">"精確位置"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"「<xliff:g id="PERM_0">%1$s</xliff:g>」和「<xliff:g id="PERM_1">%2$s</xliff:g>」權限將被移除。"</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"系統將移除以下權限:<xliff:g id="PERMS">%1$s</xliff:g>。"</string>
<string name="auto_manage_title" msgid="7693181026874842935">"自動管理權限"</string>
- <string name="off" msgid="1438489226422866263">"關閉"</string>
<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_tv_summary" msgid="3685907153054355671">"如果你在過去幾個月未曾使用應用程式,系統將會:\n\n• 移除權限以保護你的資料\n• 移除暫存檔案以騰出空間\n\n如要再次允許權限,請開啟應用程式。"</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"上次開啟:超過 <xliff:g id="NUMBER">%s</xliff:g> 個月前"</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>
@@ -251,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 小時}other{# 小時}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 分鐘}other{# 分鐘}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 秒}other{# 秒}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# 小時}other{# 小時}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<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_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_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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android 系統"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"為保護私隱權,系統已移除應用程式權限"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"「<xliff:g id="APP_NAME">%s</xliff:g>」在過去幾個月未有使用。輕按即可查看。"</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"「<xliff:g id="APP_NAME">%s</xliff:g>」和另外 1 個應用程式在過去幾個月未有使用。輕按即可查看。"</string>
@@ -372,12 +391,16 @@
<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_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_search_keywords" msgid="7710756695666744631">"筆記"</string>
<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>
@@ -452,6 +475,7 @@
<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_more_photos" msgid="128933814654231321">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&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="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;錄音嗎?"</string>
@@ -472,10 +496,10 @@
<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="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="permgrouprequest_notifications" msgid="6396739062335106181">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;傳送通知給你嗎?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"由管理員控制的權限"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"應用程式可存取位置"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"你的 IT 管理員允許「<xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"安全性與私隱權"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"掃瞄"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"感應器權限"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"私隱權設定"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"已移除權限"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"查看更多相機使用情況"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"查看更多麥克風使用情況"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"移除相機權限"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"移除麥克風權限"</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="manage_service_qs" msgid="7862555549364153805">"管理服務"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"管理權限"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"手機通話正在使用此權限"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"安全性與私隱權"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"檢查狀態"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"開發人員通訊"</string>
+ <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="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="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="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>
</resources>
diff --git a/PermissionController/res/values-zh-rTW-v33/strings.xml b/PermissionController/res/values-zh-rTW-v33/strings.xml
index b6a0c704e..a1ca5c673 100644
--- a/PermissionController/res/values-zh-rTW-v33/strings.xml
+++ b/PermissionController/res/values-zh-rTW-v33/strings.xml
@@ -19,4 +19,28 @@
<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_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>
+ <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>
+ <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{展開並查看另外 1 則快訊}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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"關閉"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"展開並顯示選項"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"收合"</string>
+ <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_gear_label" msgid="5175877094379694098">"設定"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"資訊"</string>
</resources>
diff --git a/PermissionController/res/values-zh-rTW-v34/strings.xml b/PermissionController/res/values-zh-rTW-v34/strings.xml
new file mode 100644
index 000000000..e473ca41b
--- /dev/null
+++ b/PermissionController/res/values-zh-rTW-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="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="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-zh-rTW/strings.xml b/PermissionController/res/values-zh-rTW/strings.xml
index 1a2b9e287..422b072a8 100644
--- a/PermissionController/res/values-zh-rTW/strings.xml
+++ b/PermissionController/res/values-zh-rTW/strings.xml
@@ -23,6 +23,8 @@
<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="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>
@@ -30,6 +32,11 @@
<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_always_allow_all" msgid="1719900027660252167">"一律全部允許"</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>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"偵測到畫面重疊顯示"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"如要變更這項權限設定,你必須先依序前往 [設定] &gt; [應用程式] 停用畫面重疊顯示"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"開啟設定"</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>
@@ -130,21 +134,20 @@
<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>
+ <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>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{1 天}other{# 天}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{1 小時}other{# 小時}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{1 分鐘}other{# 分鐘}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{1 秒鐘}other{# 秒鐘}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{# 天}other{# 天}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{# 小時}other{# 小時}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{# 分鐘}other{# 分鐘}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{# 秒鐘}other{# 秒鐘}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"不限權限"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"不限時間"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"過去 7 天"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"過去 24 小時"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"過去 1 小時"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"過去 15 分鐘"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"過去 1 分鐘內"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{過去 # 天內}other{過去 # 天內}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{過去 # 小時內}other{過去 # 小時內}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{過去 # 分鐘內}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>
@@ -158,8 +161,8 @@
<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_24h" msgid="3087783232178611025">"過去 24 小時內未使用"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"過去 7 天內未使用"</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_view_details" msgid="6675335735468752787">"在資訊主頁查看所有詳細資料"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"篩選依據:<xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<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_always_allow_all" msgid="4905699259378428855">"一律全部允許"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"每次都詢問"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"不允許"</string>
<string name="precise_image_description" msgid="6349638632303619872">"精確位置"</string>
@@ -211,14 +215,13 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"系統將移除<xliff:g id="PERM_0">%1$s</xliff:g>和<xliff:g id="PERM_1">%2$s</xliff:g>權限。"</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"系統將移除以下權限:<xliff:g id="PERMS">%1$s</xliff:g>。"</string>
<string name="auto_manage_title" msgid="7693181026874842935">"自動管理權限"</string>
- <string name="off" msgid="1438489226422866263">"關閉"</string>
<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_tv_summary" msgid="3685907153054355671">"如果你數個月未使用某個應用程式,系統將對該應用程式採取以下措施:\n\n• 移除權限以保護你的資料\n• 移除暫存檔以釋出空間\n\n如要重新授予權限,請開啟應用程式。"</string>
- <string name="last_opened_category_title" msgid="7871347400611202595">"距離上次開啟時間已超過 <xliff:g id="NUMBER">%s</xliff:g> 個月"</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>
@@ -251,9 +254,9 @@
<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>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{1 小時}other{# 小時}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{1 分鐘}other{# 分鐘}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{1 秒鐘}other{# 秒鐘}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{# 小時}other{# 小時}}"</string>
+ <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>
@@ -262,6 +265,9 @@
<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_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_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>
@@ -276,6 +282,19 @@
<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_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_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>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Android 系統"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"為保護隱私,系統已移除應用程式權限"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"「<xliff:g id="APP_NAME">%s</xliff:g>」已有數個月未使用。輕觸即可查看。"</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"「<xliff:g id="APP_NAME">%s</xliff:g>」和另外 1 個應用程式已有數個月未使用。輕觸即可查看。"</string>
@@ -378,6 +397,10 @@
<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_search_keywords" msgid="7710756695666744631">"記事"</string>
<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>
@@ -452,6 +475,7 @@
<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_read_media_visual" msgid="5548780620779729975">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&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_microphone" msgid="2825208549114811299">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」錄音嗎?"</string>
<string name="permgrouprequestdetail_microphone" msgid="8510456971528228861">"這個應用程式只有在你使用時才能錄音"</string>
<string name="permgroupbackgroundrequest_microphone" msgid="8874462606796368183">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」錄音嗎?"</string>
@@ -474,8 +498,8 @@
<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">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;b&gt;&lt;/b&gt;傳送通知嗎?"</string>
<string name="auto_granted_permissions" msgid="6009452264824455892">"由管理員控管的權限"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"應用程式可存取你的位置資訊"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"目前 IT 管理員允許「<xliff:g id="APP_NAME">%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>
@@ -496,17 +520,28 @@
<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="7514620345152008005">"安全性與隱私權"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"掃描"</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>
+ <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="sensor_permissions_qs" msgid="4365989229426201877">"感應器權限"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"隱私權控制項"</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>
+ <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="permissions_removed_qs" msgid="8957319130625294572">"已移除權限"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"查看其他相機使用情形"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"查看其他麥克風使用情形"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"移除相機權限"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"移除麥克風權限"</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="manage_service_qs" msgid="7862555549364153805">"管理服務"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"管理權限"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"手機通話正在使用這項權限"</string>
@@ -517,8 +552,6 @@
<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"安全性與隱私權"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"檢查狀態"</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>
@@ -537,4 +570,53 @@
<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_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="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>
+ <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_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>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"開發人員通知"</string>
+ <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="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="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="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{在 1 天內曾更新}=1{在 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>
</resources>
diff --git a/PermissionController/res/values-zu-v33/strings.xml b/PermissionController/res/values-zu-v33/strings.xml
index 57f8fec8f..2b1861644 100644
--- a/PermissionController/res/values-zu-v33/strings.xml
+++ b/PermissionController/res/values-zu-v33/strings.xml
@@ -19,4 +19,28 @@
<string name="role_dialer_request_description" msgid="6188305064871543419">"Le app izovunyelwa ukukuthumelela Izaziso, futhi izonikezwa ukufinyelela kukhamera yakho, Oxhumana nabo, Imakrofoni, Ifoni, kanye ne-SMS"</string>
<string name="role_sms_request_description" msgid="1506966389698625395">"Le app izovunyelwa ukukuthumelela Izaziso, futhi izonikezwa ukufinyelela kukhamera yakho, Oxhumana nabo, i-Files Imakrofoni, Ifoni, kanye ne-SMS"</string>
<string name="permission_description_summary_storage" msgid="1917071243213043858">"Ama-app anale mvume angafinyelela wonke amafayela kule divayisi"</string>
+ <string name="work_policy_title" msgid="832967780713677409">"Ulwazi lwenqubomgomo yakho yomsebenzi"</string>
+ <string name="work_policy_summary" msgid="3886113358084963931">"Amasethingi aphethwe umphathi wakho we-IT"</string>
+ <string name="safety_center_entry_group_expand_action" msgid="5358289574941779652">"Nweba futhi ubonise uhlu"</string>
+ <string name="safety_center_entry_group_collapse_action" msgid="1525710152244405656">"Goqa uhlu bese ufihla amasethingi"</string>
+ <string name="safety_center_entry_group_content_description" msgid="7048420958214443333">"Uhlu. <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_with_actions_needed_content_description" msgid="2708884606775932657">"Uhlu. <xliff:g id="ENTRY_TITLE">%1$s</xliff:g>. Izenzo ezidingekayo. <xliff:g id="ENTRY_SUMMARY">%2$s</xliff:g>"</string>
+ <string name="safety_center_entry_group_item_content_description" msgid="7348298582877249787">"Faka into ohlwini <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">"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>
+ <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>
+ <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Vala"</string>
+ <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Nweba futhi ubonise izinketho"</string>
+ <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Goqa"</string>
+ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Shintsha. <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">"Guqula"</string>
+ <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Vula"</string>
+ <string name="safety_center_review_settings_button" msgid="938981137942443930">"Buyekeza amasethingi"</string>
+ <string name="safety_center_gear_label" msgid="5175877094379694098">"Amasethingi"</string>
+ <string name="safety_center_info_label" msgid="8993181584061825412">"Ulwazi"</string>
</resources>
diff --git a/PermissionController/res/values-zu-v34/strings.xml b/PermissionController/res/values-zu-v34/strings.xml
new file mode 100644
index 000000000..cb348a889
--- /dev/null
+++ b/PermissionController/res/values-zu-v34/strings.xml
@@ -0,0 +1,27 @@
+<?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="security_privacy_brand_name" msgid="7303621734258440812">"Ukuvikeleka nobumfihlo"</string>
+ <string name="privacy_subpage_controls_header" msgid="4152396976713749322">"Izilawuli"</string>
+ <string name="health_connect_title" msgid="2132233890867430855">"Health Connect"</string>
+ <string name="health_connect_summary" msgid="815473513776882296">"Phatha ukufinyelela kwe-app kudatha yezempilo"</string>
+ <string name="location_settings" msgid="8863940440881290182">"Setha indawo"</string>
+ <string name="mic_toggle_description" msgid="1504101620086616040">"Okwama-app namasevisi. Uma leli sethingi livaliwe, idatha yemakrofoni ingabiwa uma ushayela inombolo yezimo eziphuthumayo."</string>
+ <string name="location_settings_subtitle" msgid="6846532794702613851">"Okwama-app namasevisi"</string>
+</resources>
diff --git a/PermissionController/res/values-zu/strings.xml b/PermissionController/res/values-zu/strings.xml
index e61561990..d1abf785d 100644
--- a/PermissionController/res/values-zu/strings.xml
+++ b/PermissionController/res/values-zu/strings.xml
@@ -23,6 +23,8 @@
<string name="back" msgid="6249950659061523680">"Emuva"</string>
<string name="available" msgid="6007778121920339498">"Iyatholakala"</string>
<string name="blocked" msgid="9195547604866033708">"Uvinjiwe"</string>
+ <string name="on" msgid="280241003226755921">"Vuliwe"</string>
+ <string name="off" msgid="1438489226422866263">"Valiwe"</string>
<string name="uninstall_or_disable" msgid="4496612999740858933">"Khipha noma ukhubaze"</string>
<string name="app_not_found_dlg_title" msgid="6029482906093859756">"I-App ayitholakalanga"</string>
<string name="grant_dialog_button_deny" msgid="88262611492697192">"Ungavumeli"</string>
@@ -30,6 +32,11 @@
<string name="grant_dialog_button_no_upgrade" msgid="8344732743633736625">"Gcina okuthi “Ngenkathi uhlelo lokusebenza lusebenza”"</string>
<string name="grant_dialog_button_no_upgrade_one_time" msgid="5125892775684968694">"Gcina “Kulesi sikhathi kuphela”"</string>
<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_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>
<string name="grant_dialog_button_deny_anyway" msgid="7225905870668915151">"Ungavumeli noma kunjalo"</string>
<string name="grant_dialog_button_dismiss" msgid="1930399742250226393">"Vula"</string>
<string name="current_permission_template" msgid="7452035392573329375">"<xliff:g id="CURRENT_PERMISSION_INDEX">%1$s</xliff:g> kokungu-<xliff:g id="PERMISSION_COUNT">%2$s</xliff:g>"</string>
@@ -107,9 +114,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="screen_overlay_title" msgid="6977038513913222078">"Kutholwe imbondela yesikrini"</string>
- <string name="screen_overlay_message" msgid="5622563069757142102">"Ukuze uguqule lesi silungiselelo semvume, kuzomele uqale uvale imbondela yesikrini kusukela ku-Izilungiselelo &gt; Izinhlelo zokusebenza"</string>
- <string name="screen_overlay_button" msgid="4655005928054025250">"Vula izilungiselelo"</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>
@@ -130,21 +134,20 @@
<string name="permission_group_usage_subtitle_7d" msgid="1465828402260324654">"Isikhathi esimisiwe lapho ama-app esebenzise i-<xliff:g id="PERMGROUP">%1$s</xliff:g> yakho ezinsukwini ezi-7 ezedlule"</string>
<string name="permission_usage_access_dialog_subtitle" msgid="4171772805196955753">"Lapho le app isebenzisa imvume yakho ye-<xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="permission_usage_access_dialog_learn_more" msgid="7121468469493184613">"Funda kabanzi"</string>
+ <string name="learn_more_content_description" msgid="8673699744544502539">"Funda kabanzi nge-<xliff:g id="PERMGROUP">%1$s</xliff:g>"</string>
<string name="manage_permission_summary" msgid="4117555482684114317">"Lawula ukufinyelela kwe-app ku-<xliff:g id="PERMGROUP">%1$s</xliff:g> yakho"</string>
<string name="auto_permission_usage_timeline_summary" msgid="2713135806453218703">"<xliff:g id="ACCESS_TIME">%1$s</xliff:g> • <xliff:g id="SUMMARY_TEXT">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_2" msgid="1521763591164293683">"<xliff:g id="APP_NAME">%1$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%2$s</xliff:g>"</string>
<string name="history_preference_subtext_3" msgid="758761785983094351">"<xliff:g id="ATTRIBUTION_NAME">%1$s</xliff:g> • <xliff:g id="APP_NAME">%2$s</xliff:g> • <xliff:g id="TRUNCATED_TIME">%3$s</xliff:g>"</string>
- <string name="duration_used_days" msgid="8293010131040301793">"{count,plural, =1{usuku 1}one{izinsuku #}other{izinsuku #}}"</string>
- <string name="duration_used_hours" msgid="1128716208752263576">"{count,plural, =1{ihora 1}one{amahora #}other{amahora #}}"</string>
- <string name="duration_used_minutes" msgid="5335824115042576567">"{count,plural, =1{umzuzu 1}one{imizuzu #}other{imizuzu #}}"</string>
- <string name="duration_used_seconds" msgid="6543746449171675028">"{count,plural, =1{umzuzwana 1}one{imizuzwana #}other{imizuzwana #}}"</string>
+ <string name="duration_used_days" msgid="8238355545812998877">"{count,plural, =1{Usuku olungu-#}one{Izinsuku ezingu-#}other{Izinsuku ezingu-#}}"</string>
+ <string name="duration_used_hours" msgid="4983814806123370332">"{count,plural, =1{Ihora elingu-#}one{Amahora angu-#}other{Amahora angu-#}}"</string>
+ <string name="duration_used_minutes" msgid="1701379522897227819">"{count,plural, =1{Umzuzu ongu-#}one{Imizuzu engu-#}other{Imizuzu engu-#}}"</string>
+ <string name="duration_used_seconds" msgid="4067390990568727715">"{count,plural, =1{Isekhondi elingu-#}one{Amasekhondi angu-#}other{Amasekhondi angu-#}}"</string>
<string name="permission_usage_any_permission" msgid="6358023078298106997">"Noma iyiphi imvume"</string>
<string name="permission_usage_any_time" msgid="3802087027301631827">"Noma yisiphi isikhathi"</string>
- <string name="permission_usage_last_7_days" msgid="7386221251886130065">"Izinsuku zokugcina ezingu-7"</string>
- <string name="permission_usage_last_day" msgid="1512880889737305115">"Amahora angu-24 okugcina"</string>
- <string name="permission_usage_last_hour" msgid="3866005205535400264">"Ihora lokugcina elingu-1"</string>
- <string name="permission_usage_last_15_minutes" msgid="9077554653436200702">"Amaminithi angu-15 okugcina"</string>
- <string name="permission_usage_last_minute" msgid="7297055967335176238">"Iminithi lokugcina elingu-1"</string>
+ <string name="permission_usage_last_n_days" msgid="7882626467375714145">"{count,plural, =1{Usuku lokugcina olungu-#}one{Izinsuku zokugcina ezingu-#}other{Izinsuku zokugcina ezingu-#}}"</string>
+ <string name="permission_usage_last_n_hours" msgid="8490466053680267858">"{count,plural, =1{Ihora lokugcina elingu-#}one{Amahora okugcina angu-#}other{Amahora okugcina angu-#}}"</string>
+ <string name="permission_usage_last_n_minutes" msgid="7817864229878281983">"{count,plural, =1{Umzuzu wokugcina ongu-#}one{Imizuzu yokugcina engu-#}other{Imizuzu yokugcina engu-#}}"</string>
<string name="no_permission_usages" msgid="9119517454177289331">"Akukho ukusetshenziswa kwemvume"</string>
<string name="permission_usage_list_title_any_time" msgid="8718257027381592407">"Ukufinyelela kwakamuva kakhulu noma kunini"</string>
<string name="permission_usage_list_title_last_7_days" msgid="9048542342670890615">"Ukufinyelela kwakamuva kakhulu ezinsukwini zokugcina ezingu-7"</string>
@@ -158,8 +161,8 @@
<string name="permission_usage_bar_chart_title_last_hour" msgid="6571647509660009185">"Ukusetshenziswa kwembume kuhora lokugcina elingu-1"</string>
<string name="permission_usage_bar_chart_title_last_15_minutes" msgid="2743143675412824819">"Ukusetshenziswa kwemvume kumaminithi okugcina okungu-15"</string>
<string name="permission_usage_bar_chart_title_last_minute" msgid="820450867183487607">"Ukusetshenziswa kwemvume ngeminithi elingu-1 lokugcina"</string>
- <string name="permission_usage_preference_summary_not_used_24h" msgid="3087783232178611025">"Ayisetshenziswanga emahoreni angama-24 adlule"</string>
- <string name="permission_usage_preference_summary_not_used_7d" msgid="4592301300810120096">"Akusetshenziswanga ezinsukwini ezi-7 ezedlule"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days" msgid="4771868094611359651">"{count,plural, =1{Akusetshenziswanga osukwini olungu-# olwedlule}one{Akusetshenziswanga ezinsukwini ezingu-# ezedlule}other{Akusetshenziswanga ezinsukwini ezingu-# ezedlule}}"</string>
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours" msgid="3828973177433435742">"{count,plural, =1{Akusetshenziswanga ehoreni elingu-# eledlule}one{Akusetshenziswanga emahoreni angu-# adlule}other{Akusetshenziswanga emahoreni angu-# adlule}}"</string>
<string name="permission_usage_preference_label" msgid="8343167938128676378">"{count,plural, =1{Kusetshenziswe i-app e-1}one{Kusetshenziswe ama-app angu-#}other{Kusetshenziswe ama-app angu-#}}"</string>
<string name="permission_usage_view_details" msgid="6675335735468752787">"Bona konke kudeshibhodi"</string>
<string name="app_permission_usage_filter_label" msgid="7182861154638631550">"Kuhlungwe ngalokhu: <xliff:g id="PERM">%1$s</xliff:g>"</string>
@@ -185,6 +188,7 @@
<string name="app_permission_button_allow_media_only" msgid="2834282724426046154">"Vumela ukufinyelela kumidiya kuphela"</string>
<string name="app_permission_button_allow_always" msgid="4573292371734011171">"Vumela sonke isikhathi"</string>
<string name="app_permission_button_allow_foreground" msgid="1991570451498943207">"Vumela ngenkathi usebenzisa i-app kuphela"</string>
+ <string name="app_permission_button_always_allow_all" msgid="4905699259378428855">"Njalo vumela konke"</string>
<string name="app_permission_button_ask" msgid="3342950658789427">"Buza njalo"</string>
<string name="app_permission_button_deny" msgid="6016454069832050300">"Ungavumeli"</string>
<string name="precise_image_description" msgid="6349638632303619872">"Indawo eqondile"</string>
@@ -211,19 +215,18 @@
<string name="auto_revocable_permissions_two" msgid="4874067408752041716">"Izimvume ze-<xliff:g id="PERM_0">%1$s</xliff:g> ne-<xliff:g id="PERM_1">%2$s</xliff:g> zizosuswa."</string>
<string name="auto_revocable_permissions_many" msgid="1521807896206032992">"Izimvume ezizosuswa: <xliff:g id="PERMS">%1$s</xliff:g>."</string>
<string name="auto_manage_title" msgid="7693181026874842935">"Phatha izimvume ngokuzenzekelayo"</string>
- <string name="off" msgid="1438489226422866263">"Valiwe"</string>
<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">"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="3685907153054355671">"Uma i-app ingasetshenziswa izinyanga ezimbalwa:\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="7871347400611202595">"Kugcine ukuvulwa ngaphezu kwezinyanga ezingu-<xliff:g id="NUMBER">%s</xliff:g> ezedlule"</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>
<string name="last_opened_summary" msgid="5248984030024968808">"Uhlelo lokusebenza lugcine ukuvulwa ngo-<xliff:g id="DATE">%s</xliff:g>"</string>
<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">"Ama-app anale mvume angafunda idatha kumhlinzeki wokuqukethwe we-Google Talk <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>
@@ -251,9 +254,9 @@
<string name="denied_header" msgid="903209608358177654">"Akuvumelekile"</string>
<string name="storage_footer_hyperlink_text" msgid="8873343987957834810">"Bona ama-app engeziwe akwazi ukufinyelela wonke amafayela"</string>
<string name="days" msgid="609563020985571393">"{count,plural, =1{usuku 1}one{izinsuku #}other{izinsuku #}}"</string>
- <string name="hours" msgid="3447767892295843282">"{count,plural, =1{ihora 1}one{amahora #}other{amahora #}}"</string>
- <string name="minutes" msgid="4408293038068503157">"{count,plural, =1{umzuzu 1}one{imizuzu #}other{imizuzu #}}"</string>
- <string name="seconds" msgid="5397771912131132690">"{count,plural, =1{umzuzwana 1}one{imizuzwana #}other{imizuzwana #}}"</string>
+ <string name="hours" msgid="7302866489666950038">"{count,plural, =1{Ihora elingu-#}one{Amahora angu-#}other{Amahora angu-#}}"</string>
+ <string name="minutes" msgid="4868414855445375753">"{count,plural, =1{Umzuzu ongu-#}one{Imizuzu engu-#}other{Imizuzu engu-#}}"</string>
+ <string name="seconds" msgid="5893958182059842734">"{count,plural, =1{Isekhondi engu-#}one{Amasekhondi angu-#}other{Amasekhondi angu-#}}"</string>
<string name="permission_reminders" msgid="6528257957664832636">"Izikhumbuzi zemvume"</string>
<string name="auto_revoke_permission_reminder_notification_title_one" msgid="6690347469376854137">"Uhlelo lokusebenza olungasetshenzisiwe olu-1"</string>
<string name="auto_revoke_permission_reminder_notification_title_many" msgid="6062217713645069960">"Izinhlelo zokusebenza ezingasetshenzisiwe ezingu-<xliff:g id="NUMBER_OF_APPS">%s</xliff:g>"</string>
@@ -262,6 +265,9 @@
<string name="auto_revoke_permission_notification_content" msgid="5125990886047799375">"Ezinye izinhlelo azikakasetshenziswa ezinyangeni ezimbalwa. Thepha ukuze ubuyekeze."</string>
<string name="unused_apps_notification_title" msgid="4314832015894238019">"{count,plural, =1{# unused app}one{# unused apps}other{# unused apps}}"</string>
<string name="unused_apps_notification_content" msgid="9195026773244581246">"Izimvume namafayela wesikhashana asusiwe futhi izaziso ziye zamiswa. Thepha ukuze ubuyekeze."</string>
+ <string name="unused_apps_safety_center_card_title" msgid="5638409355530099149">"Buyekeza ama-app asuswe imvume"</string>
+ <string name="unused_apps_safety_center_card_content" msgid="1088557243627427820">"Kuma-app ongakaze uwasebenzise muva nje, izimvume namafayela esikhashana kususiwe futhi izaziso zimisiwe."</string>
+ <string name="unused_apps_safety_center_action_title" msgid="8865914432518993194">"Buyekeza ama-app"</string>
<string name="post_drive_permission_decision_reminder_title" msgid="1290697371418139976">"Hlola izimvume zakamuva"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_1_permission" msgid="670521503734140711">"Ngenkathi ushayela, unikeze i-<xliff:g id="APP">%1$s</xliff:g> ukufinyelela ku-<xliff:g id="PERMISSION">%2$s</xliff:g>"</string>
<string name="post_drive_permission_decision_reminder_summary_1_app_2_permissions" msgid="671791184670801301">"Ngenkathi ushayela, unikeze i-<xliff:g id="APP">%1$s</xliff:g> ukufinyelela ku-<xliff:g id="PERMISSION_1">%2$s</xliff:g> ne-<xliff:g id="PERMISSION_2">%3$s</xliff:g>"</string>
@@ -276,6 +282,19 @@
<string name="auto_revoke_preference_summary" msgid="5517958331781391481">"Izimvume zisuselwe ukuvikela ubumfihlo bakho"</string>
<string name="background_location_access_reminder_notification_title" msgid="1140797924301941262">"<xliff:g id="APP_NAME">%s</xliff:g> inendawo yakho ngasemuva"</string>
<string name="background_location_access_reminder_notification_content" msgid="7787084707336546245">"Lolu hlelo lokusebenza lungahlala lufinyelela indawo yakho. Thepha ukuze ushintshe."</string>
+ <string name="notification_listener_reminder_notification_title" msgid="3747210460187479091">"Buyekeza i-app ekwazi ukufinyelela izaziso zakho"</string>
+ <string name="notification_listener_reminder_notification_content" msgid="831476101108863427">"I-<xliff:g id="APP_NAME">%s</xliff:g> ingacashisa, ithathe isinyathelo, futhi ifinyelele okuqukethwe ngaphakathi kwezaziso zakho"</string>
+ <string name="notification_listener_warning_card_content" msgid="7840973324284115893">"Le app ingacashisa, ithathe isinyathelo, futhi ifinyelele okuqukethwe ngaphakathi kwezaziso zakho. Amanye ama-app adinga lokhu kufinyelela ukuze asebenze ngendlela ehlosiwe."</string>
+ <string name="notification_listener_remove_access_button_label" msgid="7101898782417817097">"Susa ukufinyelela"</string>
+ <string name="notification_listener_review_app_button_label" msgid="3433073281029143924">"Bona okunye okungakhethwa"</string>
+ <string name="notification_listener_remove_access_success_label" msgid="2477611529875633107">"Ukufinyelela kususiwe"</string>
+ <string name="accessibility_access_reminder_notification_title" msgid="2971317234668807566">"Buyekeza i-app enokufinyelela kwedivayisi okugcwele"</string>
+ <string name="accessibility_access_reminder_notification_content" msgid="7389454158175306720">"I-<xliff:g id="APP_NAME">%s</xliff:g> ingakwazi ukubuka isikrini sakho futhi yenze izenzo kudivayisi yakho. Ama-app okufinyeleleka adinga lolu hlobo lokufinyelela ukuze asebenze ngendlela ehlosiwe."</string>
+ <string name="accessibility_access_warning_card_content" msgid="4370327190293217358">"Le app ingakwazi ukubuka isikrini sakho futhi yenze izenzo kudivayisi yakho. Ama-app okufinyeleleka adinga lolu hlobo lokufinyelela ukuze asebenze ngendlela ehlosiwe, kodwa hlola i-app futhi wenze isiqinisekiso sokuthi uyayithemba."</string>
+ <string name="accessibility_remove_access_button_label" msgid="44145801526711640">"Susa ukufinyelela"</string>
+ <string name="accessibility_show_all_apps_button_label" msgid="960067249326392280">"Buka ama-app anokufinyelela okugcwele"</string>
+ <string name="accessibility_remove_access_success_label" msgid="4380995302917014670">"Ukufinyelela kususiwe"</string>
+ <string name="safety_center_notification_app_label" msgid="2457720616141926534">"Isistimu ye-Android"</string>
<string name="auto_revoke_after_notification_title" msgid="5417761027669887431">"Izimvume zohlelo lokusebenza zisusiwe ukuze kuvikelwe ubumfihlo"</string>
<string name="auto_revoke_after_notification_content_one" msgid="6804038707453662753">"I-<xliff:g id="APP_NAME">%s</xliff:g> ayisetshenziswanga ezinyangeni ezimbalwa. Thepha ukuze ubuyekeze."</string>
<string name="auto_revoke_after_notification_content_two" msgid="9108709764831425172">"I-<xliff:g id="APP_NAME">%s</xliff:g> nolunye uhlelo lokusebenza olungu-1 awasetshenziswanga ezinyangeni ezimbalwa. Thepha ukuze ubuyekeze."</string>
@@ -378,6 +397,10 @@
<string name="role_watch_description" msgid="267003778693177779">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> izovunyelwa ukuxhumana nezaziso zakho futhi ifinyelele izimvume Zefoni yakho, -SMS, Abathintwayo kanye Nekhalenda."</string>
<string name="role_app_streaming_description" msgid="7341638576226183992">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> izovunyelwa ukuthi isebenzisane nezaziso zakho futhi isakaze ama-app wakho kudivayisi exhunyiwe"</string>
<string name="role_companion_device_computer_description" msgid="416099879217066377">"Le sevisi yabelana ngezithombe zakho, imidiya, nezaziso, kusuka efonini yakho kuya kwamanye amadivayisi."</string>
+ <string name="role_notes_label" msgid="7451627001058089536">"I-app yamanothi azenzakalelayo"</string>
+ <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>
<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>
@@ -452,6 +475,7 @@
<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_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_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_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="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>
@@ -474,8 +498,8 @@
<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="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="auto_granted_permissions" msgid="6009452264824455892">"Izimvume ezilawuliwe"</string>
- <string name="auto_granted_location_permission_notification_title" msgid="1438871159268985993">"Indawo ingafinyelelwa"</string>
- <string name="auto_granted_permission_notification_body" msgid="6919835973190443695">"Umphathi wakho we-IT uvumela i-<xliff:g id="APP_NAME">%s</xliff:g> ukuba ifinyelele indawo okuyo"</string>
+ <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>
@@ -496,17 +520,28 @@
<string name="blocked_sensor_summary" msgid="4443707628305027375">"Okwama-app namasevisi"</string>
<string name="blocked_mic_summary" msgid="8960466941528458347">"Idatha yemakrofoni isengabiwa lapho wenza ikholi yenombolo yezimo eziphuthumayo"</string>
<string name="blocked_sensor_button_label" msgid="6742092634984289658">"Shintsha"</string>
- <string name="safety_center_dashboard_page_title" msgid="7514620345152008005">"Ukuphepha Nobumfihlo"</string>
- <string name="safety_center_rescan_button" msgid="8047036829052958144">"Skena"</string>
+ <string name="safety_center_dashboard_page_title" msgid="2810774008694315854">"Ukuvikeleka nobumfihlo"</string>
+ <string name="safety_center_rescan_button" msgid="4517514567809409596">"Skena idivayisi"</string>
<string name="safety_center_issue_card_dismiss_button" msgid="5113965506144222402">"Chitha"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_title" msgid="2734809473425036382">"Chitha lesi sexwayiso?"</string>
+ <string name="safety_center_issue_card_dismiss_confirmation_message" msgid="3775418736671093563">"Buyekeza amasethingi akho okuphepha nobumfihlo noma nini ukuze ungeze ukuvikeleka okwengeziwe"</string>
+ <string name="safety_center_issue_card_confirm_dismiss_button" msgid="5884137843083634556">"Chitha"</string>
+ <string name="safety_center_issue_card_cancel_dismiss_button" msgid="2874578798877712346">"Khansela"</string>
+ <string name="safety_center_entries_category_title" msgid="34356964062813115">"Amasethingi"</string>
+ <string name="safety_status_preference_title_and_summary_content_description" msgid="3511373256505058464">"Isimo sokuvikeleka nobumfihlo. <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">"Amasethingi wokuvikeleka"</string>
- <string name="sensor_permissions_qs" msgid="4365989229426201877">"Izimvume Zenzwa"</string>
- <string name="privacy_controls_qs" msgid="471793881466080745">"Izilawuli Zokwemfihlo"</string>
+ <string name="sensor_permissions_qs" msgid="1022267900031317472">"Izimvume"</string>
+ <string name="safety_privacy_qs_tile_title" msgid="727301867710374052">"Ukuvikeleka nobumfihlo"</string>
+ <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Hlola isimo"</string>
+ <string name="privacy_controls_qs" msgid="5780144882040591169">"Izilawuli zakho zobumfihlo"</string>
+ <string name="security_settings_button_label_qs" msgid="8280343822465962330">"Amasethingi amaningi"</string>
+ <string name="camera_toggle_label_qs" msgid="3880261453066157285">"Ukufinyelela kwekhamera"</string>
+ <string name="microphone_toggle_label_qs" msgid="8132912469813396552">"Ukufinyelela kwemakrofoni"</string>
<string name="permissions_removed_qs" msgid="8957319130625294572">"Imvume isusiwe"</string>
- <string name="camera_usage_qs" msgid="7943349178368641820">"Bona ukusetshenziswa okwengeziwe kwekhamera"</string>
- <string name="microphone_usage_qs" msgid="2393193350541830472">"Bona ukusetshenziswa okwengeziwe kwemakrofoni"</string>
- <string name="remove_camera_qs" msgid="8209716677879809162">"Susa imvume yekhamera"</string>
- <string name="remove_microphone_qs" msgid="2893536836641560183">"Susa imvume yemakrofoni"</string>
+ <string name="camera_usage_qs" msgid="4394233566086665994">"Ukusetshenziswa kwekhamera kwakamuva"</string>
+ <string name="microphone_usage_qs" msgid="8527666682168170417">"Bona ukusetshenziswa kwe-mic kwakamuva"</string>
+ <string name="remove_camera_qs" msgid="3649996161066883350">"Susa imvume yale app"</string>
+ <string name="remove_microphone_qs" msgid="1276551965129953198">"Susa imvume yale app"</string>
<string name="manage_service_qs" msgid="7862555549364153805">"Phatha isevisi"</string>
<string name="manage_permissions_qs" msgid="3780541819763475434">"Phatha izimvume"</string>
<string name="active_call_usage_qs" msgid="8559974395932523391">"Bekusetshenziswa yikholi yefoni"</string>
@@ -517,8 +552,6 @@
<string name="recent_app_usage_1_qs" msgid="261450184773310741">"Kusetshenziswe kamuva yi-<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">"Kusetshenziswa yi-<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">"Kusetshenziswe kamuva yi-<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="safety_privacy_qs_tile_title" msgid="5431148204168066203">"Ukuphepha Nobumfihlo"</string>
- <string name="safety_privacy_qs_tile_subtitle" msgid="3621544532041936749">"Hlola isimo"</string>
<string name="media_confirm_dialog_positive_button" msgid="9020793594051526399">"Qinisekisa"</string>
<string name="media_confirm_dialog_negative_button" msgid="226987376924861785">"Emuva"</string>
<string name="media_confirm_dialog_title_a_to_p_aural_allow" msgid="8560601114044699903">"Ukufinyelela kwamanye amafayela nakho kuzovunyelwa"</string>
@@ -537,4 +570,53 @@
<string name="media_confirm_dialog_message_q_to_s_aural_deny" msgid="6832087393653561911">"Le app ayilusekeli uhlobo lwakamuva le-Android. Uma le app ingakwazi ukufinyelela umculo nomsindo kumafayela, ngeke ivunyelwe nokufinyelela izithombe namavidiyo."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_allow" msgid="3504335060843147760">"Le app ayilusekeli uhlobo lwakamuva le-Android. Uma le app ikwazi ukufinyelela izithombe namavidiyo, izovunyelwa nokufinyelela umculo namanye amafayela omsindo."</string>
<string name="media_confirm_dialog_message_q_to_s_visual_deny" msgid="2145973462806481992">"Le app ayilusekeli uhlobo lwakamuva le-Android. Uma le app ingakwazi ukufinyelela umculo nomsindo kumafayela, ngeke ivunyelwe nokufinyelela izithombe namavidiyo."</string>
+ <string name="safety_center_background_location_access_notification_title" msgid="8933610618810588237">"Buyekeza i-app ekwazi ukufinyelela indawo engemuva"</string>
+ <string name="safety_center_background_location_access_reminder_notification_content" msgid="4066560182507301022">"I-<xliff:g id="APP_NAME">%s</xliff:g> ingakwazi njalo ukufinyelela indawo yakho, ngisho nalapho i-app ivaliwe"</string>
+ <string name="safety_center_background_location_access_reminder_title" msgid="5477847038103863843">"Buyekeza i-app ekwazi ukufinyelela indawo engemuva"</string>
+ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Le app ingahlala ifinyelela indawo yakho, ngisho noma ivaliwe.\n\nAmanye ama-app wokuphepha nokuphuthumayo adinga ukufinyelela endaweni yakho ngemuva ukuze asebenze njengokuhlosiwe."</string>
+ <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Ukufinyelela kushintshiwe"</string>
+ <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Bona ukusetshenziswa kwakamuva kwendawo"</string>
+ <string name="privacy_controls_title" msgid="7605929972256835199">"Izilawuli zobumfihlo"</string>
+ <string name="camera_toggle_title" msgid="1251201397431837666">"Ukufinyelela kwekhamera"</string>
+ <string name="mic_toggle_title" msgid="2649991093496110162">"Ukuvula imakrofoni"</string>
+ <string name="perm_toggle_description" msgid="7801326363741451379">"Okwama-app namasevisi"</string>
+ <string name="mic_toggle_description" msgid="9163104307990677157">"Okwama-app namasevisi. Uma leli sethingi livaliwe, idatha yemakrofoni ingabiwa uma ushayela inombolo yezimo eziphuthumayo."</string>
+ <string name="location_settings_subtitle" msgid="2328360561197430695">"Bona ama-app namasevisi anokufinyelela endaweni"</string>
+ <string name="show_clip_access_notification_title" msgid="5168467637351109096">"Bonisa ukufinyelela kubhodi yokunamathisela"</string>
+ <string name="show_clip_access_notification_summary" msgid="3532020182782112687">"Bonisa umlayezo uma ama-app wakho afinyelela umbhalo, izithombe, noma okunye okuqukethwe okukopishile"</string>
+ <string name="show_password_title" msgid="2877269286984684659">"Bonisa amaphasiwedi"</string>
+ <string name="show_password_summary" msgid="1110166488865981610">"Bonisa izinhlamvu kancane njengoba uthayipha"</string>
+ <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>
+ <string name="permission_rationale_data_sharing_varies_message" msgid="4224469559084489222">"Izinqubo zedatha zingahluka kuye ngohlobo lwe-app yakho, ukusetshenziswa, indawo, nobudala. "<annotation id="link">"Okuningi mayelana nokwabelana ngedatha"</annotation></string>
+ <string name="permission_rationale_data_sharing_varies_message_without_link" msgid="4912763761399025094">"Izinqubo zedatha zingahluka kuye ngohlobo lwe-app yakho, ukusetshenziswa, indawo, nobudala."</string>
+ <string name="permission_rationale_location_settings_title" msgid="7204145004850190953">"Idatha yendawo yakho"</string>
+ <string name="permission_rationale_permission_settings_message" msgid="631286040979660267">"Shintsha ukufinyelela kwale app "<annotation id="link">"kumasethingi emqubomgomo"</annotation></string>
+ <string name="permission_rationale_purpose_app_functionality" msgid="8397736681065841405">"Okwenziwa yi-app"</string>
+ <string name="permission_rationale_purpose_analytics" msgid="2070800501189620712">"Izibalo"</string>
+ <string name="permission_rationale_purpose_developer_communications" msgid="6453047018892062374">"Ukuxhumana konjiniyela"</string>
+ <string name="permission_rationale_purpose_advertising" msgid="7156966429245180236">"Ukukhangisa noma ukumaketha"</string>
+ <string name="permission_rationale_purpose_fraud_prevention_security" msgid="4262104770357031902">"Ukugwema ukukhwabanisa, ukuvikeleka, nokuthobela"</string>
+ <string name="permission_rationale_purpose_personalization" msgid="1589973273682238708">"Ukwenza ngokomuntu ngamunye"</string>
+ <string name="permission_rationale_purpose_account_management" msgid="2985772421946688879">"Ukuphathwa kwe-akhawunti"</string>
+ <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="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>
+ <string name="data_sharing_updates_footer_message" msgid="1582711655172892107">"Onjiniyela balama-app banikeze ulwazi mayelana nezinqubo zabo zokwabelana ngedatha ku-app store. Bangase bayibuyekeze ngokuhamba kwesikhathi.\n\nIzinqubo zokwabelana ngedatha zingahluka kuya ngohlobo lwe-app yakho, ukusetshenziswa, indawo, nobudala."</string>
+ <string name="learn_about_data_sharing" msgid="4200480587079488045">"Funda mayelana nokwabelana ngedatha"</string>
+ <string name="shares_location_with_third_parties" msgid="2278051743742057767">"Idatha yendawo yakho manje seyabiwe nezinkampani ezingahlangane ngqo"</string>
+ <string name="shares_location_with_third_parties_for_advertising" msgid="1918588064014480513">"Idatha yendawo yakho manje seyabiwe nezinkampani ezingahlangene ngqo zokukhangisa noma ukumaketha"</string>
+ <string name="updated_in_last_days" msgid="8371811947153042322">"{count,plural, =0{Kubuyekezwe phakathi nosuku lokugcina}=1{Kubuyekezwe phakathi nosuku lokugcina}one{Kubuyekezwe phakathi kwezinsuku ezingu-#}other{Kubuyekezwe phakathi kwezinsuku ezingu-#}}"</string>
+ <string name="no_updates_at_this_time" msgid="9031085635689982935">"Azikho izibuyekezo ngalesi sikhathi"</string>
+ <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>
</resources>
diff --git a/PermissionController/res/values/bools.xml b/PermissionController/res/values/bools.xml
new file mode 100644
index 000000000..e97761843
--- /dev/null
+++ b/PermissionController/res/values/bools.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <bool name="is_at_least_t">false</bool>
+ <bool name="is_at_least_u">false</bool>
+</resources>
diff --git a/PermissionController/res/values/colors.xml b/PermissionController/res/values/colors.xml
index 083a32194..e54edb506 100644
--- a/PermissionController/res/values/colors.xml
+++ b/PermissionController/res/values/colors.xml
@@ -22,7 +22,6 @@
<color name="incident_reason_bullet_color">#de000000</color>
<color name="divider_color_primary">#24000000</color>
<color name="divider_color_secondary">#85FFFFFF</color>
- <color name="safety_center_secondary">#FF777777</color>
<!-- Auto related colors -->
<color name="car_tint">#fff8f9fa</color>
@@ -30,12 +29,7 @@
<color name="car_accent">#ff60a8f0</color>
<color name="car_divider_color">#1fffffff</color>
- <!-- Safety center colors -->
- <color name="safety_center_card_background">#D3D3D3</color>
- <color name="safety_center_info">#1E8E3E</color>
- <color name="safety_center_recommend">#F9AB00</color>
- <color name="safety_center_warn">#D93025</color>
- <color name="safety_center_status_unfilled_wedge">#DADCE0</color> <!-- Material Gray 300 -->
- <color name="safety_center_done">#767676</color>
- <color name="safety_center_qs_background">#2f3133</color>
+ <!-- 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>
</resources>
diff --git a/PermissionController/res/values/config.xml b/PermissionController/res/values/config.xml
index 2dfcf7102..8e3a58abd 100644
--- a/PermissionController/res/values/config.xml
+++ b/PermissionController/res/values/config.xml
@@ -24,4 +24,7 @@
<bool name="config_useMaterial3PermissionGrantDialog">false</bool>
<!-- Name of a font family to use for headlines in SettingsLib. -->
<string name="config_headlineFontFamily" translatable="false"></string>
+
+ <!-- Whether to show the "Show password" toggle -->
+ <bool name="config_display_show_password_toggle">true</bool>
</resources>
diff --git a/PermissionController/res/values/overlayable.xml b/PermissionController/res/values/overlayable.xml
index 7d36d2742..850b5df40 100644
--- a/PermissionController/res/values/overlayable.xml
+++ b/PermissionController/res/values/overlayable.xml
@@ -19,10 +19,11 @@
<!-- TODO(evanseverson) rename this overlayable -->
<overlayable name="PermissionControllerStyles">
- <policy type="product|system|vendor">
+ <policy type="product|system|vendor|odm|oem">
<!-- START HELP LINKS -->
<item type="string" name="help_app_permissions" />
+ <item type="string" name="data_sharing_help_center_link" />
<!-- END HELP LINKS -->
<!-- START PERMISSION GRANT DIALOG -->
@@ -58,10 +59,42 @@
<item type="style" name="PermissionGrantButtonAllow" />
<item type="style" name="PermissionGrantButtonAllowForeground" />
+ <item type="style" name="PermissionGrantButtonAllowOneTime" />
<item type="style" name="PermissionGrantButtonDeny" />
<item type="style" name="PermissionGrantButtonNoUpgrade" />
+
+ <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 PERMISSION GRANT DIALOG -->
+ <!-- START PERMISSION RATIONALE DIALOG -->
+
+ <item type="style" name="PermissionRationaleScrollView" />
+ <item type="style" name="PermissionRationaleSingleton" />
+ <item type="style" name="PermissionRationaleDialog" />
+ <item type="style" name="PermissionRationaleContent" />
+
+ <item type="style" name="PermissionRationaleTitleContainer" />
+ <item type="style" name="PermissionRationaleTitleIcon" />
+ <item type="style" name="PermissionRationaleTitleMessage" />
+
+ <item type="style" name="PermissionRationaleSectionOuterContainer" />
+ <item type="style" name="PermissionRationaleSectionIcon" />
+ <item type="style" name="PermissionRationaleSectionInnerContainer" />
+ <item type="style" name="PermissionRationaleSectionTitle" />
+ <item type="style" name="PermissionRationaleSectionMessage" />
+
+ <item type="style" name="PermissionRationaleButtonContainer" />
+ <item type="style" name="PermissionRationaleBackButton" />
+
+ <item type="color" name="permission_rationale_accent_primary_variant" />
+
+ <!-- END PERMISSION RATIONALE DIALOG -->
<!-- START PERMISSION REVIEW SCREEN -->
<item type="style" name="PermissionReview" />
@@ -100,6 +133,13 @@
<item type="style" name="LargeHeaderLink" />
<item type="style" name="LargeHeaderDivider" />
+ <item type="style" name="AppPermissionRationaleContainer"/>
+ <item type="style" name="AppPermissionRationaleContent"/>
+ <item type="style" name="AppPermissionRationaleTextContent"/>
+ <item type="style" name="AppPermissionRationaleTitle"/>
+ <item type="style" name="AppPermissionRationaleSubtitle"/>
+ <item type="style" name="AppPermissionRationaleIcon"/>
+
<item type="style" name="AppPermissionSelection" />
<item type="style" name="AppPermissionMessage" />
<item type="style" name="AppPermissionRadioButton" />
@@ -292,8 +332,198 @@
<item type="style" name="WarningBannerWidgetFrame" />
<!-- END WARNING BANNER PREFERENCE STYLE -->
+ <!-- START PRIVACY CONTROLS CONFIGS -->
+ <item type="string" name="camera_toggle_enable_config"/>
+ <item type="string" name="mic_toggle_enable_config"/>
+ <item type="string" name="clipboard_show_access_notifications_config"/>
+ <item type="string" name="show_access_notifications_default_config"/>
+ <item type="bool" name="config_display_show_password_toggle"/>
+ <!-- END PRIVACY CONTROLS CONFIGS -->
+
+ <!-- START SAFETY LABELS STYLE -->
+ <item type="style" name="AppDataSharingDetailsContainer" />
+ <item type="style" name="AppDataSharingDetailsTextAppearance" />
+ <item type="style" name="AppDataSharingDetailsMessage" />
+ <item type="style" name="AppDataSharingNoUpdatesTextAppearance" />
+ <item type="style" name="AppDataSharingNoUpdatesMessage" />
+ <item type="style" name="AppDataSharingUpdatesFooterContainer" />
+ <item type="style" name="AppDataSharingUpdatesFooterIconFrame" />
+ <item type="style" name="AppDataSharingUpdatesFooterIcon" />
+ <item type="style" name="AppDataSharingUpdatesFooterTextAppearance" />
+ <item type="style" name="AppDataSharingUpdatesFooterMessage" />
+ <item type="style" name="AppDataSharingUpdatesFooterLink" />
+ <item type="style" name="AppDataSharingUpdatePreference" />
+ <item type="style" name="AppDataSharingUpdateAppIconFrame" />
+ <item type="style" name="AppDataSharingUpdateAppIcon" />
+ <item type="style" name="AppDataSharingUpdatePreferenceTitleAndSummaryContainer" />
+ <item type="style" name="AppDataSharingUpdatePreferenceTitle" />
+ <item type="style" name="AppDataSharingUpdatePreferenceSummary" />
+ <item type="style" name="AppDataSharingUpdateSettingsIconFrame" />
+ <item type="style" name="AppDataSharingUpdateSettingsIcon" />
+ <!-- END SAFETY LABELS STYLE -->
+
</policy>
</overlayable>
-</resources>
+ <overlayable name="SafetyCenterStyles">
+ <policy type="product|system|vendor|odm|oem">
+ <item type="style" name="Theme.SafetyCenterQs" />
+ <item type="style" name="Theme.SafetyCenter" />
+
+ <item type="dimen" name="sc_spacing_xxxsmall" />
+ <item type="dimen" name="sc_spacing_xxsmall" />
+ <item type="dimen" name="sc_spacing_xsmall" />
+ <item type="dimen" name="sc_spacing_small" />
+ <item type="dimen" name="sc_spacing_medium" />
+ <item type="dimen" name="sc_spacing_large" />
+ <item type="dimen" name="sc_spacing_xlarge" />
+ <item type="dimen" name="sc_spacing_xxlarge" />
+ <item type="dimen" name="sc_spacing_xxxlarge" />
+ <item type="dimen" name="sc_card_margin" />
+ <item type="dimen" name="sc_list_margin" />
+ <item type="dimen" name="sc_list_margin_top" />
+ <item type="dimen" name="sc_action_button_list_margin" />
+ <item type="dimen" name="sc_top_action_button_margin" />
+ <item type="dimen" name="sc_entry_padding_end" />
+ <item type="dimen" name="sc_entry_group_expanded_padding_top" />
+ <item type="dimen" name="sc_entry_group_expanded_padding_bottom" />
+ <item type="dimen" name="sc_entry_group_collapsed_padding_top" />
+ <item type="dimen" name="sc_entry_group_collapsed_padding_bottom" />
+ <item type="dimen" name="sc_card_margin_bottom" />
+ <item type="dimen" name="sc_button_corner_radius" />
+ <item type="dimen" name="sc_button_corner_radius_small" />
+ <item type="dimen" name="sc_card_corner_radius_large" />
+ <item type="dimen" name="sc_card_corner_radius_medium" />
+ <item type="dimen" name="sc_card_corner_radius_xsmall" />
+ <item type="dimen" name="sc_card_widget_corner_radius" />
+ <item type="dimen" name="sc_brand_chip_corner_radius" />
+ <item type="dimen" name="sc_brand_chip_padding" />
+
+ <item type="color" name="safety_center_button_info" />
+ <item type="color" name="safety_center_button_recommend" />
+ <item type="color" name="safety_center_button_warn" />
+ <item type="color" name="safety_center_outline_button_info" />
+ <item type="color" name="safety_center_outline_button_recommend" />
+ <item type="color" name="safety_center_outline_button_warn" />
+ <item type="color" name="sc_surface_light" />
+ <item type="color" name="sc_surface_dark" />
+ <item type="color" name="sc_surface_variant_light" />
+ <item type="color" name="sc_surface_variant_dark" />
+ <item type="color" name="sc_accent_primary_light" />
+ <item type="color" name="sc_accent_primary_dark" />
+ <item type="color" name="sc_shield_accent" />
+ <item type="color" name="sc_shield_accent_dark" />
+ <item type="color" name="sc_shield_accent_fixed_variant" />
+ <item type="color" name="safety_center_info" />
+ <item type="color" name="safety_center_recommend" />
+ <item type="color" name="safety_center_warn" />
+
+ <item type="color" name="sc_status_info_light" />
+ <item type="color" name="sc_status_recommend_light" />
+ <item type="color" name="sc_status_warn_light" />
+ <item type="color" name="sc_status_info_dark" />
+ <item type="color" name="sc_status_recommend_dark" />
+ <item type="color" name="sc_status_warn_dark" />
+ <item type="color" name="sc_status_background_info_light" />
+ <item type="color" name="sc_status_background_recommend_light" />
+ <item type="color" name="sc_status_background_warn_light" />
+ <item type="color" name="sc_status_background_info_dark" />
+ <item type="color" name="sc_status_background_recommend_dark" />
+ <item type="color" name="sc_status_background_warn_dark" />
+ <item type="color" name="sc_icon_info_light" />
+ <item type="color" name="sc_icon_recommend_light" />
+ <item type="color" name="sc_icon_warn_light" />
+ <item type="color" name="sc_icon_null_light" />
+ <item type="color" name="sc_icon_info_dark" />
+ <item type="color" name="sc_icon_recommend_dark" />
+ <item type="color" name="sc_icon_warn_dark" />
+ <item type="color" name="sc_icon_null_dark" />
+
+ <item type="drawable" name="ic_check" />
+ <item type="drawable" name="ic_chevron_right" />
+ <item type="drawable" name="ic_collapse_issues" />
+ <item type="drawable" name="ic_expand_issues" />
+ <item type="drawable" name="ic_expand_less" />
+ <item type="drawable" name="ic_expand_more" />
+ <item type="drawable" name="ic_privacy" />
+ <item type="drawable" name="ic_safety_center_shield" />
+ <item type="drawable" name="ic_safety_empty" /> <!-- rename -->
+ <item type="drawable" name="ic_safety_group_collapse" />
+ <item type="drawable" name="ic_safety_group_expand" />
+ <item type="drawable" name="ic_safety_info" />
+ <item type="drawable" name="ic_safety_issue_dismiss" />
+ <item type="drawable" name="ic_safety_null_state" />
+ <item type="drawable" name="ic_safety_recommendation" />
+ <item type="drawable" name="ic_safety_warn" />
+ <item type="drawable" name="ic_settings_gear" />
+ <item type="drawable" name="ic_settings_info" />
+ <item type="drawable" name="indicator_background_circle" />
+ <item type="drawable" name="more_issues_collapse_anim" />
+ <item type="drawable" name="more_issues_expand_anim" />
+ <item type="drawable" name="safety_center_card_background" />
+ <item type="drawable" name="safety_center_card_widget_background" />
+ <item type="drawable" name="safety_center_group_collapse_anim" />
+ <item type="drawable" name="safety_center_group_expand_anim" />
+ <item type="drawable" name="safety_center_issue_resolved_avd" />
+ <item type="drawable" name="safety_center_more_issues_card_background" />
+ <item type="drawable" name="safety_entity_top_flat_bottom_flat_background" />
+ <item type="drawable" name="safety_entity_top_flat_bottom_large_background" />
+ <item type="drawable" name="safety_entity_top_flat_bottom_small_background" />
+ <item type="drawable" name="safety_entity_top_large_bottom_flat_background" />
+ <item type="drawable" name="safety_entity_top_large_bottom_large_background" />
+ <item type="drawable" name="safety_entity_top_large_bottom_small_background" />
+ <item type="drawable" name="safety_entity_top_small_bottom_flat_background" />
+ <item type="drawable" name="safety_entity_top_small_bottom_large_background" />
+ <item type="drawable" name="safety_entity_top_small_bottom_small_background" />
+ <item type="drawable" name="safety_entry_icon_action_background" />
+ <item type="drawable" name="safety_group_entry_background" />
+ <item type="drawable" name="safety_status_info" />
+ <item type="drawable" name="safety_status_info_to_info_anim" />
+ <item type="drawable" name="safety_status_recommend_to_info_anim" />
+ <item type="drawable" name="safety_status_recommendation" />
+ <item type="drawable" name="safety_status_small_info_to_info_anim" />
+ <item type="drawable" name="safety_status_small_info_to_recommendation_anim" />
+ <item type="drawable" name="safety_status_small_info_to_warn_anim" />
+ <item type="drawable" name="safety_status_small_recommendation_to_info_anim" />
+ <item type="drawable" name="safety_status_small_recommendation_to_recommendation_anim" />
+ <item type="drawable" name="safety_status_small_recommendation_to_warn_anim" />
+ <item type="drawable" name="safety_status_small_warn_to_info_anim" />
+ <item type="drawable" name="safety_status_small_warn_to_recommendation_anim" />
+ <item type="drawable" name="safety_status_small_warn_to_warn_anim" />
+ <item type="drawable" name="safety_status_warn" />
+ <item type="drawable" name="safety_status_warn_to_info_anim" />
+ <item type="drawable" name="safety_status_warn_to_recommend_anim" />
+ <item type="drawable" name="status_info_to_scanning_anim" />
+ <item type="drawable" name="status_recommend_to_scanning_anim" />
+ <item type="drawable" name="status_scanning_anim_info" />
+ <item type="drawable" name="status_scanning_anim_recommend" />
+ <item type="drawable" name="status_scanning_anim_warn" />
+ <item type="drawable" name="status_scanning_end_anim_info_to_info" />
+ <item type="drawable" name="status_scanning_end_anim_info_to_recommend" />
+ <item type="drawable" name="status_scanning_end_anim_info_to_warn" />
+ <item type="drawable" name="status_scanning_end_anim_recommend_to_info" />
+ <item type="drawable" name="status_scanning_end_anim_recommend_to_recommend" />
+ <item type="drawable" name="status_scanning_end_anim_recommend_to_warn" />
+ <item type="drawable" name="status_scanning_end_anim_warn_to_info" />
+ <item type="drawable" name="status_scanning_end_anim_warn_to_recommend" />
+ <item type="drawable" name="status_scanning_end_anim_warn_to_warn" />
+ <item type="drawable" name="status_warn_to_scanning_anim" />
+ <item type="drawable" name="safety_center_brand_chip_background" />
+ <item type="drawable" name="ic_safety_center_brand_chip" />
+
+ <item type="style" name="TextAppearance.SafetyCenter.Headline" />
+ <item type="style" name="TextAppearance.SafetyCenter.Headline.Status" />
+ <item type="style" name="TextAppearance.SafetyCenter.Headline.Issue" />
+ <item type="style" name="TextAppearance.SafetyCenter.Headline.Entry" />
+ <item type="style" name="TextAppearance.SafetyCenter.Body" />
+ <item type="style" name="TextAppearance.SafetyCenter.IssueAttribution" />
+ <item type="style" name="TextAppearance.SafetyCenter.Medium" />
+ <item type="style" name="TextAppearance.SafetyCenter.IssueSubtitle" />
+ <item type="style" name="TextAppearance.SafetyCenter.ActionButton" />
+ <item type="style" name="TextAppearance.SafetyCenter.ActionButton.Secondary" />
+ <item type="style" name="TextAppearance.SafetyCenter.BrandChip" />
+ </policy>
+ </overlayable>
+
+</resources> \ No newline at end of file
diff --git a/PermissionController/res/values/strings.xml b/PermissionController/res/values/strings.xml
index 882fc4181..08d1b6b2d 100644
--- a/PermissionController/res/values/strings.xml
+++ b/PermissionController/res/values/strings.xml
@@ -38,6 +38,14 @@
update the string "quick_settings_camera_mic_blocked" in SystemUi [CHAR LIMIT=NONE] -->
<string name="blocked">Blocked</string>
+ <!-- Label indicating sensor is on. If you update this string, please update the string
+ "switch_bar_on" in SystemUI or do not use the default string for the LocationTile [CHAR LIMIT=NONE] -->
+ <string name="on">On</string>
+
+ <!-- Label indicating sensor is off. If you update this string, please update the string
+ "switch_bar_off" in SystemUI or do not use the default string for the LocationTile [CHAR LIMIT=NONE] -->
+ <string name="off">Off</string>
+
<!-- Button label for uninstall or disable actions [CHAR LIMIT=none] -->
<string name="uninstall_or_disable">Uninstall or disable</string>
@@ -59,6 +67,21 @@
<!-- Title for the dialog button to get more info about a permission. [CHAR LIMIT=15] -->
<string name="grant_dialog_button_more_info">More info</string>
+ <!-- Title for the dialog button to allow access to all of a resource. [CHAR LIMIT=60] -->
+ <string name="grant_dialog_button_allow_all">Allow all</string>
+
+ <!-- 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 access to select photos to be shared. [CHAR LIMIT=60] -->
+ <string name="grant_dialog_button_allow_selected_photos">Select photos and videos</string>
+
+ <!-- Title for the dialog button to allow access to select more photos to be shared. [CHAR LIMIT=60] -->
+ <string name="grant_dialog_button_allow_more_selected_photos">Select more</string>
+
+ <!-- Title for the dialog button to not select more data (example: photos or contacts) to be shared. [CHAR LIMIT=60] -->
+ <string name="grant_dialog_button_dont_select_more">Don\u2019t select more</string>
+
<!-- Title for the dialog button to deny a permission grant despite a warning of implications. [CHAR LIMIT=30] -->
<string name="grant_dialog_button_deny_anyway">Don\u2019t allow anyway</string>
@@ -307,19 +330,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 for the dialog that warns the user they need to turn off screen overlays
- before permissions can be changed. [CHAR LIMIT=NONE] -->
- <string name="screen_overlay_title">Screen overlay detected</string>
-
- <!-- Message for the dialog that warns the user they need to turn off screen overlays
- before permissions can be changed. The "Settings > Apps" conveys to the user to
- go to Settings and click on apps, this may need updates in RTL languages. [CHAR LIMIT=NONE] -->
- <string name="screen_overlay_message">To change this permission setting, you first have to turn off the screen overlay from Settings \u003e Apps</string>
-
- <!-- Button for the dialog that warns the user they need to turn off screen overlays
- before permissions can be changed. [CHAR LIMIT=NONE] -->
- <string name="screen_overlay_button">Open settings</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] -->
@@ -387,6 +397,9 @@
<!-- Link text for intent out to location provider [CHAR LIMIT=20] -->
<string name="permission_usage_access_dialog_learn_more">Learn more</string>
+ <!-- Content description for the learn more info icon on Privacy Dashboard and app permission groups page [CHAR LIMIT=100] -->
+ <string name="learn_more_content_description">Learn more about <xliff:g id="permgroup" example="Location">%1$s</xliff:g></string>
+
<!-- Summary for preference to manage a permission for a group like location or microphone [CHAR LIMIT=60] -->
<string name="manage_permission_summary">Control app access to your <xliff:g id="permgroup" example="Location">%1$s</xliff:g></string>
@@ -401,25 +414,25 @@
<!-- Duration used for a permission in days -->
<string name="duration_used_days">{count, plural,
- =1 {1 day}
+ =1 {# day}
other {# days}
}</string>
<!-- Duration used for a permission in hours -->
<string name="duration_used_hours">{count, plural,
- =1 {1 hour}
+ =1 {# hour}
other {# hours}
}</string>
<!-- Duration used for a permission in minutes -->
<string name="duration_used_minutes">{count, plural,
- =1 {1 min}
+ =1 {# min}
other {# mins}
}</string>
<!-- Duration used for a permission in seconds -->
<string name="duration_used_seconds">{count, plural,
- =1 {1 sec}
+ =1 {# sec}
other {# secs}
}</string>
@@ -429,20 +442,23 @@
<!-- Description for showing permission accesses accessed any time [CHAR LIMIT=30] -->
<string name="permission_usage_any_time">Any time</string>
- <!-- Description for showing permissions accessed in the last 7 days [CHAR LIMIT=30] -->
- <string name="permission_usage_last_7_days">Last 7 days</string>
-
- <!-- Description for showing permissions accessed in the last day [CHAR LIMIT=30] -->
- <string name="permission_usage_last_day">Last 24 hours</string>
-
- <!-- Description for showing permissions accessed in the last hour [CHAR LIMIT=30] -->
- <string name="permission_usage_last_hour">Last 1 hour</string>
+ <!-- Description for showing permissions accessed in the last n days [CHAR LIMIT=30] -->
+ <string name="permission_usage_last_n_days">{count, plural,
+ =1 {Last # day}
+ other {Last # days}
+ }</string>
- <!-- Description for showing permissions accessed in the last 15 minutes [CHAR LIMIT=30] -->
- <string name="permission_usage_last_15_minutes">Last 15 minutes</string>
+ <!-- Description for showing permissions accessed in the last n hours [CHAR LIMIT=30] -->
+ <string name="permission_usage_last_n_hours">{count, plural,
+ =1 {Last # hour}
+ other {Last # hours}
+ }</string>
- <!-- Description for showing permissions accessed in the last minute [CHAR LIMIT=30] -->
- <string name="permission_usage_last_minute">Last 1 minute</string>
+ <!-- Description for showing permissions accessed in the last n minutes [CHAR LIMIT=30] -->
+ <string name="permission_usage_last_n_minutes">{count, plural,
+ =1 {Last # minute}
+ other {Last # minutes}
+ }</string>
<!-- Label when no apps have used the requested permissions [CHAR LIMIT=30] -->
<string name="no_permission_usages">No permission usages</string>
@@ -483,11 +499,17 @@
<!-- Label for the title of the permission bar chart showing how often the most common permissions are used [CHAR LIMIT=50] -->
<string name="permission_usage_bar_chart_title_last_minute">Permission usage in last 1 minute</string>
- <!-- Summary text if a permission usage is not used in past 24 hours [CHAR LIMIT=60] -->
- <string name="permission_usage_preference_summary_not_used_24h">Not used in past 24 hours</string>
+ <!-- Summary text if a permission usage is not used in past n days [CHAR LIMIT=60] -->
+ <string name="permission_usage_preference_summary_not_used_in_past_n_days">{count, plural,
+ =1 {Not used in past # day}
+ other {Not used in past # days}
+ }</string>
- <!-- Summary text if a permission usage is not used in past 7 days [CHAR LIMIT=60] -->
- <string name="permission_usage_preference_summary_not_used_7d">Not used in past 7 days</string>
+ <!-- Summary text if a permission usage is not used in past n hours [CHAR LIMIT=60] -->
+ <string name="permission_usage_preference_summary_not_used_in_past_n_hours">{count, plural,
+ =1 {Not used in past # hour}
+ other {Not used in past # hours}
+ }</string>
<!-- Label for the permission usage preference that shows how many apps have used various permissions [CHAR LIMIT=50] -->
<string name="permission_usage_preference_label">{count, plural,
@@ -573,6 +595,9 @@
<!-- Title for the dialog button to allow a permission grant only when the app is in the foreground. [CHAR LIMIT=60] -->
<string name="app_permission_button_allow_foreground">Allow only while using the app</string>
+ <!-- Title for the dialog button to allow the user to always allow access to all resources guarded by a permission. [CHAR LIMIT=60] -->
+ <string name="app_permission_button_always_allow_all">Always allow all</string>
+
<!-- Title for the dialog button to require an app to ask for a permission next time they need it. [CHAR LIMIT=60] -->
<string name="app_permission_button_ask">Ask every time</string>
@@ -651,9 +676,6 @@
<!-- Title for a page where users can manage whether or not they want Android to automatically remove permissions [CHAR LIMIT=40] -->
<string name="auto_manage_title">Manage permissions automatically</string>
- <!-- Label for an "off" button [CHAR LIMIT=30] -->
- <string name="off">Off</string>
-
<!-- Summary describing the permissions that have been removed from an app, when one permission is removed [CHAR LIMIT=none] -->
<string name="auto_revoked_app_summary_one"><xliff:g id="permission_name" example="Location">%s</xliff:g> permission removed</string>
@@ -670,10 +692,14 @@
<string name="unused_apps_page_summary">If an app is unused for a few months:\n\n\u2022 Permissions are removed to protect your data\n\u2022 Notifications are stopped to save battery\n\u2022 Temporary files are removed to free up space\n\nTo allow permissions and notifications again, open the app.</string>
<!-- Summary for the screen on TV that shows all unused apps that have been hibernated [CHAR LIMIT=none] -->
- <string name="unused_apps_page_tv_summary">If an app is unused for a few months:\n\n\u2022 Permissions are removed to protect your data\n\u2022 Temporary files are removed to free up space\n\nTo allow permissions again, open the app.</string>
+ <string name="unused_apps_page_tv_summary">If an app is unused for a month:\n\n\u2022 Permissions are removed to protect your data\n\u2022 Temporary files are removed to free up space\n\nTo allow permissions again, open the app.</string>
<!-- Title for a category of apps that were last used several months ago [CHAR LIMIT=none] -->
- <string name="last_opened_category_title">Last opened more than <xliff:g id="number" example="3">%s</xliff:g> months ago</string>
+ <string name="last_opened_category_title"> {count, plural,
+ =1{Last opened more than # month ago}
+ other{Last opened more than # months ago}
+ }
+ </string>
<!-- Summary for showing when an app was last used [CHAR LIMIT=none] -->
<string name="last_opened_summary">App last opened on <xliff:g id="date" example="March 12, 2020">%s</xliff:g></string>
@@ -776,19 +802,19 @@
<!-- Time in hours -->
<string name="hours">{count, plural,
- =1 {1 hour}
+ =1 {# hour}
other {# hours}
}</string>
<!-- Time in minutes -->
<string name="minutes">{count, plural,
- =1 {1 minute}
+ =1 {# minute}
other {# minutes}
}</string>
<!-- Time in seconds -->
<string name="seconds">{count, plural,
- =1 {1 second}
+ =1 {# second}
other {# seconds}
}</string>
@@ -819,6 +845,15 @@
<!-- The notification content for the hibernation reminder notification [CHAR LIMIT=none] -->
<string name="unused_apps_notification_content">Permissions and temporary files have been removed and notifications were stopped. Tap to review.</string>
+ <!-- The safety center card title for apps being auto-revoked [CHAR LIMIT=60] -->
+ <string name="unused_apps_safety_center_card_title">Review apps with permissions removed</string>
+
+ <!-- The safety center card summary for apps being auto-revoked [CHAR LIMIT=none] -->
+ <string name="unused_apps_safety_center_card_content">For apps that you haven\u2019t used in a while, permissions and temporary files were removed and notifications were stopped.</string>
+
+ <!-- The action on the auto-revoked card to see unused apps [CHAR LIMIT=60] -->
+ <string name="unused_apps_safety_center_action_title">Review apps</string>
+
<!-- The notification title for the notification that shows up at the end of a drive where the user made a permission decision [CHAR LIMIT=60] -->
<string name="post_drive_permission_decision_reminder_title">Check recent permissions</string>
@@ -864,23 +899,44 @@
<!-- The notification content for background location access reminder notification [CHAR LIMIT=none] -->
<string name="background_location_access_reminder_notification_content">This app can always access your location. Tap to change.</string>
- <!-- The notification title for background location access reminder notification [DO NOT TRANSLATE] [CHAR LIMIT=60] -->
- <string name="notification_listener_reminder_notification_title">Review app with notification listener access</string>
+ <!-- The notification title for notification listener reminder notification [CHAR LIMIT=60] -->
+ <string name="notification_listener_reminder_notification_title">Review app with access to your notifications</string>
- <!-- The notification title for background location access reminder notification [DO NOT TRANSLATE] [CHAR LIMIT=60] -->
- <string name="notification_listener_reminder_notification_title_plural">{count, plural,
- =1 {Review app with notification listener access}
- other {Review apps with notification listener access}
- }</string>
+ <!-- The notification content for notification listener reminder notification [CHAR LIMIT=none] -->
+ <string name="notification_listener_reminder_notification_content"><xliff:g id="app_name" example="Gmail">%s</xliff:g> can dismiss, act on, and access content inside your notifications</string>
- <!-- The notification content for background location access reminder notification [DO NOT TRANSLATE] [CHAR LIMIT=none] -->
- <string name="notification_listener_reminder_notification_content"><xliff:g id="app_name" example="Gmail">%s</xliff:g> can read all your notifications.</string>
+ <!-- The warning card (in safety center) content for notification listener access [CHAR LIMIT=none] -->
+ <string name="notification_listener_warning_card_content">This app can dismiss, act on, and access content inside your notifications. Some apps require this access to function as intended.</string>
- <!-- The notification content for background location access reminder notification [DO NOT TRANSLATE] [CHAR LIMIT=none] -->
- <string name="notification_listener_reminder_notification_content_plural">{count, plural,
- =1 {<xliff:g id="app_name" example="Gmail">%s</xliff:g> can read all your notifications.}
- other {# apps can read all your notifications.}
- }</string>
+ <!-- The label for remove access button on safety center warning card [CHAR LIMIT=60] -->
+ <string name="notification_listener_remove_access_button_label">Remove access</string>
+
+ <!-- The label for notification listener settings button from safety center warning card [CHAR LIMIT=60] -->
+ <string name="notification_listener_review_app_button_label">See more options</string>
+
+ <!-- Success message for remove access action on safety center warning card [CHAR LIMIT=60] -->
+ <string name="notification_listener_remove_access_success_label">Access removed</string>
+
+ <!-- The title for notification reminders, and for warning cards in safety center, for apps with full device (accessibility) access [CHAR LIMIT=60] -->
+ <string name="accessibility_access_reminder_notification_title">Review app with full device access</string>
+
+ <!-- The notification content for full device (accessibility) access reminder notification [CHAR LIMIT=none] -->
+ <string name="accessibility_access_reminder_notification_content"><xliff:g id="app_name" example="Gmail">%s</xliff:g> can view your screen and perform actions on your device. Accessibility apps need this type of access to function as intended.</string>
+
+ <!-- The warning card (in safety center) content for full device (accessibility) access [CHAR LIMIT=none] -->
+ <string name="accessibility_access_warning_card_content">This app can view your screen and perform actions on your device. Accessibility apps need this type of access to function as intended, but check the app and make sure you trust it.</string>
+
+ <!-- The label for button on safety center warning card to remove full (accessibility) access from a given app [CHAR LIMIT=60] -->
+ <string name="accessibility_remove_access_button_label">Remove access</string>
+
+ <!-- The label button on safety center warning card to view full list of apps with full (accessibility) access [CHAR LIMIT=60] -->
+ <string name="accessibility_show_all_apps_button_label">View apps with full access</string>
+
+ <!-- Success message for remove access action on safety center warning card [CHAR LIMIT=60] -->
+ <string name="accessibility_remove_access_success_label">Access removed</string>
+
+ <!-- Fallback for notification title (name of app delivering notification) in case PbA string not defined [CHAR LIMIT=60] -->
+ <string name="safety_center_notification_app_label">Android System</string>
<!-- The notification title for the notification that a permission auto revoke has happened [CHAR LIMIT=60] -->
<string name="auto_revoke_after_notification_title">App permissions removed to protect privacy</string>
@@ -1150,6 +1206,15 @@
<!-- Description for the companion device computer profile role. [CHAR LIMIT=NONE] -->
<string name="role_companion_device_computer_description">This service shares your photos, media, and notifications from your phone to other devices.</string>
+ <!-- Label for the NOTES role. [CHAR LIMIT=30] -->
+ <string name="role_notes_label">Default notes app</string>
+ <!-- Short label for the NOTES role. [CHAR LIMIT=30] -->
+ <string name="role_notes_short_label">Notes app</string>
+ <!-- Description for the NOTES role. [CHAR LIMIT=NONE] -->
+ <string name="role_notes_description">Apps that allow you to take notes on your device</string>
+ <!-- Search keywords for the NOTES role. [CHAR LIMIT=NONE] -->
+ <string name="role_notes_search_keywords">notes</string>
+
<!-- Subtitle for the application that is the current default application [CHAR LIMIT=30] -->
<string name="request_role_current_default">Current default</string>
@@ -1387,6 +1452,10 @@ Allow <xliff:g id="app_name" example="Gmail">%4$s</xliff:g> to upload a bug repo
<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. 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. 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>
<!-- 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]-->
@@ -1448,10 +1517,10 @@ Allow <xliff:g id="app_name" example="Gmail">%4$s</xliff:g> to upload a bug repo
<!-- 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>
- <!-- Content of the notification [CHAR LIMIT=120]-->
- <string name="auto_granted_location_permission_notification_title">Location can be accessed</string>
+ <!-- Title of the notification [CHAR LIMIT=120]-->
+ <string name="auto_granted_location_permission_notification_title"><xliff:g id="app_name" example="Gmail">%1$s</xliff:g> has location access</string>
<!-- Body of the notification, that does not include the app name and is specific to location permissions. [CHAR LIMIT=120]-->
- <string name="auto_granted_permission_notification_body">Your IT admin is allowing <xliff:g id="app_name" example="Gmail">%s</xliff:g> to access your location</string>
+ <string name="auto_granted_permission_notification_body">Your organization allows <xliff:g id="app_name" example="Gmail">%1$s</xliff:g> to access your location</string>
<!-- The title of (and the button label for a link to) the screen that lists permissions that aren't considered the most relevant to the user at the moment, and thus did not make to the "main" screen. [CHAR LIMIT=80] -->
<string name="other_permissions_label">Other permissions</string>
@@ -1500,27 +1569,49 @@ Allow <xliff:g id="app_name" example="Gmail">%4$s</xliff:g> to upload a bug repo
<string name="blocked_sensor_button_label">Change</string>
<!-- Title for page containing overall view of device safety status [CHAR LIMIT=30] -->
- <string name="safety_center_dashboard_page_title">Security &amp; Privacy</string>
+ <string name="safety_center_dashboard_page_title">Security &amp; privacy</string>
<!-- Label for the button that triggers a new scan for safety center data [CHAR LIMIT=60] -->
- <string name="safety_center_rescan_button">Scan</string>
+ <string name="safety_center_rescan_button">Scan device</string>
<!-- Content description for the button dismisses a safety center issue [CHAR LIMIT=NONE] -->
<string name="safety_center_issue_card_dismiss_button">Dismiss</string>
+ <!-- Title for a dialog confirming if a user wants to dismiss a safety center issue [CHAR LIMIT=NONE] -->
+ <string name="safety_center_issue_card_dismiss_confirmation_title">Dismiss this alert?</string>
+ <!-- Message for a dialog confirming if a user wants to dismiss a safety center issue [CHAR LIMIT=NONE] -->
+ <string name="safety_center_issue_card_dismiss_confirmation_message">Review your security and privacy settings any time to add more protection</string>
+ <!-- Label for a button to dismiss a safety center issue in a confirmation dialog [CHAR LIMIT=30] -->
+ <string name="safety_center_issue_card_confirm_dismiss_button">Dismiss</string>
+ <!-- Label for a button to cancel dismissing a safety center issue in a confirmation dialog [CHAR LIMIT=30] -->
+ <string name="safety_center_issue_card_cancel_dismiss_button">Cancel</string>
+ <!-- Title for a section that contains security and privacy related settings on the Security and Privacy page [CHAR LIMIT=60] -->
+ <string name="safety_center_entries_category_title">Settings</string>
+ <!-- Content description for the safety status preference title and summary in the Safety Center [CHAR LIMIT=NONE]-->
+ <string name="safety_status_preference_title_and_summary_content_description">Security and privacy status. <xliff:g id="overall safety status" example="Looks Good">%1$s</xliff:g>. <xliff:g id="summary of device status" example="This device is up to date">%2$s</xliff:g></string>
<!-- Label for the button that takes the user to the settings page for Android Security [CHAR LIMIT=60] -->
<string name="security_settings">Security Settings</string>
<!-- Label for the permission usage section of safety center QS page[CHAR LIMIT=30] -->
- <string name="sensor_permissions_qs">Sensor Permissions</string>
+ <string name="sensor_permissions_qs">Permissions</string>
+ <!-- Title of the safety and privacy quick settings tile [CHAR LIMIT=NONE] -->
+ <string name="safety_privacy_qs_tile_title">Security &amp; privacy</string>
+ <!-- Subtitle of the safety and privacy quick settings tile [CHAR LIMIT=NONE] -->
+ <string name="safety_privacy_qs_tile_subtitle">Check status</string>
<!-- Label for the privacy controls section of safety center QS page [CHAR LIMIT=30] -->
- <string name="privacy_controls_qs">Privacy Controls</string>
+ <string name="privacy_controls_qs">Your privacy controls</string>
+ <!-- Label for the button that opens safety center in safety center QS page [CHAR LIMIT=30] -->
+ <string name="security_settings_button_label_qs">More settings</string>
+ <!-- Label for the toggle that changes camera access in safety center QS page [CHAR LIMIT=30] -->
+ <string name="camera_toggle_label_qs">Camera access</string>
+ <!-- Label for the toggle that changes microphone access in safety center QS page [CHAR LIMIT=30] -->
+ <string name="microphone_toggle_label_qs">Mic access</string>
<!-- Label when permissions were removed via safety center QS page [CHAR LIMIT=30] -->
<string name="permissions_removed_qs">Permission removed</string>
<!-- Label to see camera usage in safety center QS page [CHAR LIMIT=50] -->
- <string name="camera_usage_qs">See more camera usage</string>
+ <string name="camera_usage_qs">See recent camera usage</string>
<!-- Label to see microphone usage in safety center QS page [CHAR LIMIT=50] -->
- <string name="microphone_usage_qs">See more microphone usage</string>
- <!-- Label to remove camera permission in safety center QS page [CHAR LIMIT=50] -->
- <string name="remove_camera_qs">Remove camera permission</string>
- <!-- Label to remove microphone permission in safety center QS page [CHAR LIMIT=50] -->
- <string name="remove_microphone_qs">Remove microphone permission</string>
+ <string name="microphone_usage_qs">See recent mic usage</string>
+ <!-- Label to remove camera permission for an app in safety center QS page [CHAR LIMIT=50] -->
+ <string name="remove_camera_qs">Remove permission for this app</string>
+ <!-- Label to remove microphone permission for an app in safety center QS page [CHAR LIMIT=50] -->
+ <string name="remove_microphone_qs">Remove permission for this app</string>
<!-- Label to manage service in safety center QS page [CHAR LIMIT=50] -->
<string name="manage_service_qs">Manage service</string>
<!-- Label to manage permissions in safety center QS page [CHAR LIMIT=50] -->
@@ -1542,11 +1633,6 @@ Allow <xliff:g id="app_name" example="Gmail">%4$s</xliff:g> to upload a bug repo
<!-- Label for recent app usage with sub-attribution and proxy label in safety center QS page [CHAR LIMIT=NONE] -->
<string name="recent_app_usage_2_qs">Recently used by <xliff:g id="app_name" example="Gmail">%1$s</xliff:g> (<xliff:g id="attribution_label" example="For Wallet">%2$s</xliff:g> \u2022 <xliff:g id="proxy_label" example="Speech services">%3$s</xliff:g>)</string>
- <!-- Title of the safety and privacy quick settings tile [CHAR LIMIT=NONE] -->
- <string name="safety_privacy_qs_tile_title">Security &amp; Privacy</string>
- <!-- Subtitle of the safety and privacy quick settings tile [CHAR LIMIT=NONE] -->
- <string name="safety_privacy_qs_tile_subtitle">Check status</string>
-
<!-- Positive button for media confirm dialog [CHAR LIMIT=40] -->
<string name="media_confirm_dialog_positive_button">Confirm</string>
<!-- Negative button for media confirm dialog [CHAR LIMIT=40] -->
@@ -1583,4 +1669,185 @@ Allow <xliff:g id="app_name" example="Gmail">%4$s</xliff:g> to upload a bug repo
<string name="media_confirm_dialog_message_q_to_s_visual_allow">This app doesn\u2019t support the latest version of Android. If this app can access photos and videos, it will also be allowed to access music and audio files.</string>
<!-- Message for media confirm dialog (when user denies visual group of q_to_s app) [CHAR LIMIT=NONE] -->
<string name="media_confirm_dialog_message_q_to_s_visual_deny">This app doesn\u2019t support the latest version of Android. If this app can\u2019t access music and audio files, it also won\u2019t be allowed to access photos and videos.</string>
+
+ <!-- Title for background location access reminder notification [CHAR LIMIT=80] -->
+ <string name="safety_center_background_location_access_notification_title">Review app with background location access</string>
+ <!-- Content for background location access reminder notification [CHAR LIMIT=80]-->
+ <string name="safety_center_background_location_access_reminder_notification_content"><xliff:g id="app_name" example="Gmail">%s</xliff:g> can always access your location, even when the app is closed</string>
+ <!-- Title for background location access reminder warning card [CHAR LIMIT=80]-->
+ <string name="safety_center_background_location_access_reminder_title">Review app with background location access</string>
+ <!-- Content for background location access reminder warning card [CHAR LIMIT=NONE] -->
+ <string name="safety_center_background_location_access_reminder_summary">This app can always access your location, even when it\u2019s closed.\u000a\u000aSome safety and emergency apps require access to your location in the background to work as intended.</string>
+ <!-- Success message when background location access permission is changed [CHAR LIMIT=40]-->
+ <string name="safety_center_background_location_access_revoked">Access changed</string>
+ <!-- Label for button to view recent location access [CHAR LIMIT=60]-->
+ <string name="safety_center_view_recent_location_access">See recent location usage</string>
+
+ <!-- Do not translate. config value for the camera toggle -->
+ <string name="camera_toggle_enable_config">camera_toggle_enabled</string>
+ <!-- Do not translate. config value for the mic toggle -->
+ <string name="mic_toggle_enable_config">mic_toggle_enabled</string>
+ <!-- Do not translate. config value for whether to show clipboard access notifications -->
+ <string name="clipboard_show_access_notifications_config">clipboard_show_access_notifications</string>
+ <!-- Do not translate. config value for the default state of the clipboard access notifications -->
+ <string name="show_access_notifications_default_config">show_access_notifications</string>
+
+ <!-- Title of the Privacy controls page[CHAR LIMIT=NONE] -->
+ <string name="privacy_controls_title">Privacy controls</string>
+ <!-- Label for the camera use toggle [CHAR LIMIT=40] -->
+ <string name="camera_toggle_title">Camera access</string>
+ <!-- Label for the mic use toggle [CHAR LIMIT=40] -->
+ <string name="mic_toggle_title">Microphone access</string>
+ <!-- Describes what is affected by a permission toggle [CHAR LIMIT=NONE] -->
+ <string name="perm_toggle_description">For apps and services</string>
+ <!-- Describes what is affected by the mic toggle [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">See apps and services that have access to location</string>
+ <!-- Title for toggle controlling whether notifications are shown when an app pastes from clipboard. [CHAR LIMIT=50] -->
+ <string name="show_clip_access_notification_title">Show clipboard access</string>
+ <!-- Summary for toggle controlling whether notifications are shown when an app pastes from clipboard. [CHAR LIMIT=NONE] -->
+ <string name="show_clip_access_notification_summary">Show a message when apps access text, images, or other content you\u2019ve copied</string>
+ <!-- Title for toggle controlling whether to show the first letter while typing passwords. [CHAR LIMIT=50]-->
+ <string name="show_password_title">Show passwords</string>
+ <!-- Summary for toggle controlling whether to show the first letter while typing passwords. [CHAR LIMIT=NONE] -->
+ <string name="show_password_summary">Display characters briefly as you type</string>
+
+ <!-- Link for Safety Label Data Sharing help center page. [CHAR LIMIT=NONE]-->
+ <string name="data_sharing_help_center_link" translatable="false"></string>
+
+ <!-- Permission Rationale - Start -->
+
+ <!-- Permission rationale message when an app requests a location permission. Third parties are
+ other organizations outside of the app developer. These could be companies or even governmental
+ organizations. But because we aren't able to be inclusive of all possibilities, phrasing should
+ be as generic as possible while still helping users understand they aren't just sharing data
+ with the developer company. [CHAR LIMIT=130] -->
+ <string name="permission_rationale_message_location">This app stated it may share location data with third parties</string>
+
+ <!-- Title message shown for Permission Rationale dialog for Location permission [CHAR LIMIT=50] -->
+ <string name="permission_rationale_location_title">Data sharing and location</string>
+
+ <!-- Title shown for Permission Rationale "where data sharing come from" section [CHAR LIMIT=70] -->
+ <string name="permission_rationale_data_sharing_source_title">Where data sharing info comes from</string>
+
+ <!-- Message shown to the user letting them know that data usage information was provided by
+ the developer to the device manufacturer." [CHAR LIMIT=200] -->
+ <string name="permission_rationale_data_sharing_device_manufacturer_message">The developer provided info to this device\'s manufacturer about how this app shares data. The developer may update this info over time.</string>
+
+ <!-- Message shown to the user letting them know where data usage information came from which
+ will map to app store labels/names." [CHAR LIMIT=200] -->
+ <string name="permission_rationale_data_sharing_source_message">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>
+
+ <!-- Title shown for Permission Rationale data sharing purposes section [CHAR LIMIT=50] -->
+ <string name="permission_rationale_location_purpose_title">This app may share location data for:</string>
+
+ <!-- Message shown to the user letting them know that data will be shared and for which
+ purposes. Purposes will be in bullet list form and are one or many of the following: "app
+ functionality", "analytics", "developer communications", "advertising or marketing",
+ "fraud prevention, security, and compliance", "personalization", "account management".
+ [CHAR LIMIT=NONE] -->
+ <string name="permission_rationale_purpose_message" translatable="false"><annotation id="purpose_list" example="purpose 1, purpose 2, purpose 3">%1$s</annotation></string>
+
+ <!-- Title shown for Permission Rationale "Data sharing varies" section [CHAR LIMIT=50] -->
+ <string name="permission_rationale_permission_data_sharing_varies_title">Data sharing varies</string>
+
+ <!-- Message shown for Permission Rationale "Data sharing varies" section [CHAR LIMIT=200] -->
+ <string name="permission_rationale_data_sharing_varies_message">Data practices may vary based on your app version, use, region, and age. <annotation id="link">More about data sharing</annotation></string>
+
+ <!-- Message shown for Permission Rationale "Data sharing varies" section, but without learn more link [CHAR LIMIT=200] -->
+ <string name="permission_rationale_data_sharing_varies_message_without_link">Data practices may vary based on your app version, use, region, and age.</string>
+
+ <!-- Title shown for Permission Rationale location permission settings section [CHAR LIMIT=40] -->
+ <string name="permission_rationale_location_settings_title">Your location data</string>
+
+ <!-- Message shown to the user letting them where to change permission settings in the future [CHAR LIMIT=100] -->
+ <string name="permission_rationale_permission_settings_message">Change this app’s access in <annotation id="link">privacy settings</annotation></string>
+
+ <!-- Permission usage purpose shown for Permission Rationale. This will be used with the
+ permission_rationale_purpose_message string in for of bullet list. [CHAR LIMIT=30] -->
+ <string name="permission_rationale_purpose_app_functionality">App functionality</string>
+
+ <!-- Permission usage purpose shown for Permission Rationale. This will be used with the
+ permission_rationale_purpose_message string in for of bullet list. [CHAR LIMIT=30] -->
+ <string name="permission_rationale_purpose_analytics">Analytics</string>
+
+ <!-- Permission usage purpose shown for Permission Rationale. This will be used with the
+ permission_rationale_purpose_message string in for of bullet list. [CHAR LIMIT=50] -->
+ <string name="permission_rationale_purpose_developer_communications">Developer communications</string>
+
+ <!-- Permission usage purpose shown for Permission Rationale. This will be used with the
+ permission_rationale_purpose_message string in for of bullet list. [CHAR LIMIT=50] -->
+ <string name="permission_rationale_purpose_advertising">Advertising or marketing</string>
+
+ <!-- Permission usage purpose shown for Permission Rationale. This will be used with the
+ permission_rationale_purpose_message string in for of bullet list. [CHAR LIMIT=75] -->
+ <string name="permission_rationale_purpose_fraud_prevention_security">Fraud prevention, security, and compliance</string>
+
+ <!-- Permission usage purpose shown for Permission Rationale. This will be used with the
+ permission_rationale_purpose_message string in for of bullet list. [CHAR LIMIT=50] -->
+ <string name="permission_rationale_purpose_personalization">Personalization</string>
+
+ <!-- Permission usage purpose shown for Permission Rationale. This will be used with the
+ permission_rationale_purpose_message string in for of bullet list. [CHAR LIMIT=50] -->
+ <string name="permission_rationale_purpose_account_management">Account management</string>
+
+ <!-- Text for an app's permission rationale header [CHAR LIMIT=60]-->
+ <string name="app_permission_rationale_message">Data safety</string>
+
+ <!-- Text for linking to an app's location permission rationale dialog. [CHAR LIMIT=60] -->
+ <string name="app_location_permission_rationale_title">Location data may be shared</string>
+
+ <!-- Description for the app's location permission rationale dialog content. [CHAR LIMIT=130] -->
+ <string name="app_location_permission_rationale_subtitle">This app stated it may share your location data with third parties</string>
+
+ <!-- Permission Rationale - End -->
+
+ <!-- Safety Label Change Notifications Start -->
+
+ <!-- Title for Data Sharing updates page, which displays updates from apps on their data sharing
+ practices. Also used as the title for Data Sharing updates page entry point from Safety Center.
+ [CHAR LIMIT=70] -->
+ <string name="data_sharing_updates_title">Data sharing updates for location</string>
+ <!-- Summary for Data Sharing updates page entry point in Safety Center. Clicking on the entry
+ will navigate to Data Sharing updates page, which displays updates from apps on their data
+ sharing practices. [CHAR LIMIT=130] -->
+ <string name="data_sharing_updates_summary">Review apps that changed the way they may share your location data</string>
+ <!-- Subtitle for Data Sharing updates page, which displays updates from apps on their data
+ sharing practices. [CHAR LIMIT=320] -->
+ <string name="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.</string>
+ <!-- Footer message for Data Sharing updates page, which displays updates from apps on their
+ data sharing practices. [CHAR LIMIT=420] -->
+ <string name="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.</string>
+ <!-- Link for Data Sharing Help Center page, which will open a web page detailing what app data
+ sharing policies mean. [CHAR LIMIT=60] -->
+ <string name="learn_about_data_sharing">Learn about data sharing</string>
+ <!-- Message indicating that an app now shares location data with third parties for the purpose
+ of advertising, when it earlier did not share location data for the purpose of advertising, but
+ did for other purposes. Third parties are other companies or organizations.
+ [CHAR LIMIT=100] -->
+ <string name="shares_location_with_third_parties">Your location data is now shared with third parties</string>
+ <!-- Message indicating that an app now shares location data with third parties for the purpose
+ of advertising, when it earlier did not. Third parties are other companies or organizations.
+ [CHAR LIMIT=160] -->
+ <string name="shares_location_with_third_parties_for_advertising">Your location data is now shared with third parties for advertising or marketing</string>
+ <!-- Header for the number of updates in the last days. [CHAR LIMIT=40] -->
+ <!-- TODO(b/261914980): Update with final strings for 0 and 1 case. -->
+ <string name="updated_in_last_days">{count, plural,
+ =0 {Updated within the last day}
+ =1 {Updated within the last day}
+ other {Updated within # days}
+ }</string>
+ <!-- Message indicating that no apps have provided recent updates. [CHAR LIMIT=100] -->
+ <string name="no_updates_at_this_time">No updates at this time</string>
+
+ <!-- Notification title for safety label changes notification [CHAR LIMIT=70] -->
+ <string name="safety_label_changes_notification_title">Data sharing updates</string>
+ <!-- Notification description for safety label changes notification [CHAR LIMIT=120] -->
+ <string name="safety_label_changes_notification_desc">Some apps changed the way they may share your location data</string>
+
+ <!-- Content description for the Gear icon -->
+ <string name="safety_label_changes_gear_description">Settings</string>
+
+ <!-- Safety Label Change Notifications End -->
</resources>
diff --git a/PermissionController/res/values/styles.xml b/PermissionController/res/values/styles.xml
index a7424bfbc..11b9ebec1 100644
--- a/PermissionController/res/values/styles.xml
+++ b/PermissionController/res/values/styles.xml
@@ -104,13 +104,20 @@
<item name="android:orientation">horizontal</item>
</style>
+ <style name="PermissionLocationAccuracyRadioGroupMaterial3">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginBottom">24dp</item>
+ <item name="android:gravity">center_horizontal</item>
+ <item name="android:orientation">horizontal</item>
+ </style>
+
<style name="PermissionLocationAccuracyRadioFine">
<item name="android:button">@null</item>
<item name="android:background">@null</item>
<item name="android:gravity">center_horizontal</item>
<item name="android:layout_marginEnd">16dp</item>
<item name="android:drawablePadding">8dp</item>
- <item name="android:gravity">center_horizontal</item>
</style>
<style name="PermissionLocationAccuracyRadioCoarse">
@@ -119,7 +126,6 @@
<item name="android:gravity">center_horizontal</item>
<item name="android:layout_marginStart">16dp</item>
<item name="android:drawablePadding">8dp</item>
- <item name="android:gravity">center_horizontal</item>
</style>
<style name="PermissionLocationAccuracyFineImageView">
@@ -129,6 +135,12 @@
<item name="android:layout_marginBottom">24dp</item>
</style>
+ <style name="PermissionLocationAccuracyFineImageViewMaterial3">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginBottom">24dp</item>
+ </style>
+
<style name="PermissionLocationAccuracyCoarseImageView">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
@@ -136,6 +148,12 @@
<item name="android:layout_marginBottom">24dp</item>
</style>
+ <style name="PermissionLocationAccuracyCoarseImageViewMaterial3">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginBottom">24dp</item>
+ </style>
+
<style name="PermissionGrantButtonList">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
@@ -165,6 +183,49 @@
<item name="android:background">?android:attr/selectableItemBackground</item>
</style>
+ <style name="PermissionGrantPermissionRationaleContent">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginStart">24dp</item>
+ <item name="android:layout_marginEnd">24dp</item>
+ <item name="android:layout_marginBottom">24dp</item>
+ <item name="android:paddingTop">12dp</item>
+ <item name="android:paddingBottom">12dp</item>
+ <item name="android:paddingStart">16dp</item>
+ <item name="android:paddingEnd">16dp</item>
+ <item name="android:orientation">horizontal</item>
+ <item name="android:background">@drawable/grant_dialog_permission_rationale_background</item>
+ </style>
+
+ <style name="PermissionGrantPermissionRationaleIcon">
+ <item name="android:layout_width">20dp</item>
+ <item name="android:layout_height">20dp</item>
+ <item name="android:layout_gravity">start|center_vertical</item>
+ <item name="android:scaleType">centerInside</item>
+ <item name="android:tint">?android:attr/textColorSecondary</item>
+ </style>
+
+ <style name="PermissionGrantPermissionRationaleMessage"
+ parent="@android:style/TextAppearance.DeviceDefault">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:layout_width">0dp</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_weight">1</item>
+ <item name="android:layout_marginStart">12dp</item>
+ <item name="android:layout_marginEnd">12dp</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:lineHeight">20sp</item>
+ <item name="android:lineSpacingMultiplier">1.25</item>
+ </style>
+
+ <style name="PermissionGrantPermissionRationaleMoreInfoIcon">
+ <item name="android:layout_width">20dp</item>
+ <item name="android:layout_height">20dp</item>
+ <item name="android:layout_gravity">end|center_vertical</item>
+ <item name="android:scaleType">centerInside</item>
+ <item name="android:tint">?android:attr/textColorSecondary</item>
+ </style>
+
<!-- for use in overlays -->
<style name="PermissionGrantButtonAllow"
parent="@style/PermissionGrantButton"></style>
@@ -172,6 +233,12 @@
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"
+ parent="@style/PermissionGrantButton"></style>
<style name="PermissionGrantButtonDeny"
parent="@style/PermissionGrantButton"></style>
<style name="PermissionGrantButtonNoUpgrade"
@@ -187,6 +254,12 @@
parent="@style/PermissionGrantButton"></style>
<style name="PermissionGrantButtonNoUpgradeMaterial3"
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 -->
@@ -373,15 +446,68 @@
<item name="android:background">?android:attr/selectableItemBackground</item>
</style>
- <style name="AppPermissionMessage"
- parent="@style/TextAppearance.CategoryTitle">
+ <style name="AppPermissionMessage">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
- <item name="android:paddingStart">8dp</item>
+ <item name="android:layout_marginTop">20dp</item>
+ <item name="android:layout_marginBottom">8dp</item>
+ <item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
<item name="android:textColor">?android:attr/colorAccent</item>
<item name="android:textDirection">locale</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:lineHeight">20sp</item>
</style>
+ <!-- APP PERMISSION RATIONALE CONTAINER -->
+ <style name="AppPermissionRationaleContainer">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:orientation">vertical</item>
+ </style>
+
+ <style name="AppPermissionRationaleContent">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginTop">20dp</item>
+ <item name="android:layout_marginBottom">20dp</item>
+ <item name="android:orientation">horizontal</item>
+ </style>
+
+ <style name="AppPermissionRationaleTextContent">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginStart">24dp</item>
+ <item name="android:orientation">vertical</item>
+ <item name="android:layout_weight">1</item>
+ </style>
+
+ <style name="AppPermissionRationaleTitle">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textDirection">locale</item>
+ <item name="android:textSize">20sp</item>
+ <item name="android:lineHeight">24sp</item>
+ </style>
+
+ <style name="AppPermissionRationaleSubtitle">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:textDirection">locale</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:lineHeight">20sp</item>
+ </style>
+
+ <style name="AppPermissionRationaleIcon">
+ <item name="android:layout_width">24dp</item>
+ <item name="android:layout_height">24dp</item>
+ <item name="android:layout_gravity">start|center_vertical</item>
+ <item name="android:scaleType">centerInside</item>
+ <item name="android:tint">?android:attr/textColorPrimary</item>
+ </style>
+ <!-- END APP PERMISSION RATIONALE CONTAINER -->
+
<style name="AppPermissionRadioButton"
parent="@android:style/Widget.DeviceDefault.CompoundButton.RadioButton">
<item name="android:layout_width">match_parent</item>
@@ -420,7 +546,6 @@
<style name="AppPermissionLocationAccuracy">
<item name="android:layout_marginTop">24dp</item>
<item name="android:layout_marginBottom">8dp</item>
- <item name="android:paddingStart">8dp</item>
<item name="android:clickable">true</item>
<item name="android:focusable">true</item>
<item name="android:background">?android:attr/selectableItemBackground</item>
@@ -1084,10 +1209,8 @@
<!-- START PRIVACY DASHBOARD -->
- <style name="PrivacyDashboardGraphicLabel">
- <item name="android:layout_width">wrap_content</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
+ <style name="PrivacyDashboardGraphicLabel"
+ parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textSize">16sp</item>
</style>
@@ -1108,18 +1231,16 @@
<item name="android:paddingStart">?android:attr/listPreferredItemPaddingStart</item>
</style>
- <style name="WarningBannerCardView"
- xmlns:card_view="http://schemas.android.com/apk/res-auto"
- xmlns:app="http://schemas.android.com/apk/res-auto" >
+ <style name="WarningBannerCardView">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
- <item name="app:cardCornerRadius">20dp</item>
- <item name="app:cardBackgroundColor">@color/warning_surface</item>
- <item name="app:cardElevation">0dp</item>
- <item name="card_view:contentPaddingBottom">8dp</item>
- <item name="card_view:contentPaddingTop">20dp</item>
- <item name="card_view:contentPaddingLeft">20dp</item>
- <item name="card_view:contentPaddingRight">20dp</item>
+ <item name="cardCornerRadius">20dp</item>
+ <item name="cardBackgroundColor">@color/warning_surface</item>
+ <item name="cardElevation">0dp</item>
+ <item name="contentPaddingBottom">8dp</item>
+ <item name="contentPaddingTop">20dp</item>
+ <item name="contentPaddingLeft">20dp</item>
+ <item name="contentPaddingRight">20dp</item>
</style>
<style name="WarningBannerIcon">
diff --git a/PermissionController/res/values/themes.xml b/PermissionController/res/values/themes.xml
index 5882c595d..76196a050 100644
--- a/PermissionController/res/values/themes.xml
+++ b/PermissionController/res/values/themes.xml
@@ -105,7 +105,7 @@
<item name="android:background">@color/divider_color_primary</item>
</style>
- <style name="Theme.DeviceDefault.Dialog.Alert.DayNight" parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
+ <style name="Theme.DeviceDefault.Dialog.NoActionBar.DayNight" parent="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar" />
<!-- Do not allow OEMs to overlay these themes.
@@ -138,8 +138,4 @@
<item name="android:filterTouchesWhenObscured">true</item>
</style>
- <style name="SafetyCenter" parent="@android:style/Theme.DeviceDefault.NoActionBar">
- <item name="android:filterTouchesWhenObscured">true</item>
- </style>
-
</resources>
diff --git a/PermissionController/res/xml-v34/app_data_sharing_updates.xml b/PermissionController/res/xml-v34/app_data_sharing_updates.xml
new file mode 100644
index 000000000..fefd952b3
--- /dev/null
+++ b/PermissionController/res/xml-v34/app_data_sharing_updates.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.
+ -->
+<!-- TODO(b/261666772): Extract to styles where necessary and update to final spec. -->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+ <com.android.permissioncontroller.permission.ui.handheld.v34.AppDataSharingDetailsPreference
+ android:key="details"
+ android:selectable="false" />
+ <PreferenceCategory android:key="last_period_updates" />
+ <com.android.permissioncontroller.permission.ui.handheld.v34.AppDataSharingUpdatesFooterPreference
+ android:key="info_footer"
+ android:icon="@drawable/ic_info_outline"
+ android:selectable="false" />
+</PreferenceScreen> \ No newline at end of file
diff --git a/PermissionController/res/xml-v34/privacy_subpage.xml b/PermissionController/res/xml-v34/privacy_subpage.xml
new file mode 100644
index 000000000..0aec164ce
--- /dev/null
+++ b/PermissionController/res/xml-v34/privacy_subpage.xml
@@ -0,0 +1,67 @@
+<!--
+ ~ 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.
+ -->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <com.android.permissioncontroller.safetycenter.ui.SafetyBrandChipPreference
+ android:key="subpage_brand_chip"
+ app:selectable="false"/>
+
+ <com.android.permissioncontroller.safetycenter.ui.ComparablePreferenceCategory
+ android:key="subpage_issue_group"
+ android:layout="@layout/preference_category_no_label"
+ app:selectable="false" />
+
+ <com.android.permissioncontroller.safetycenter.ui.ComparablePreferenceCategory
+ android:key="subpage_generic_entry_group"
+ app:selectable="false" />
+
+ <com.android.permissioncontroller.safetycenter.ui.ComparablePreferenceCategory
+ android:key="subpage_controls_entry_group"
+ android:title="@string/privacy_subpage_controls_header"
+ app:selectable="false">
+ <com.android.permissioncontroller.safetycenter.ui.ClickableDisabledSwitchPreference
+ android:key="privacy_camera_toggle"
+ android:title="@string/camera_toggle_title"
+ android:summary="@string/perm_toggle_description" />
+
+ <com.android.permissioncontroller.safetycenter.ui.ClickableDisabledSwitchPreference
+ android:key="privacy_mic_toggle"
+ android:title="@string/mic_toggle_title"
+ android:summary="@string/mic_toggle_description"/>
+
+ <com.android.permissioncontroller.safetycenter.ui.ClickableDisabledSwitchPreference
+ android:key="show_clip_access_notification"
+ android:title="@string/show_clip_access_notification_title"
+ android:summary="@string/show_clip_access_notification_summary" />
+
+ <com.android.permissioncontroller.safetycenter.ui.ClickableDisabledSwitchPreference
+ android:key="show_password"
+ android:title="@string/show_password_title"
+ android:summary="@string/show_password_summary"/>
+
+ <Preference
+ android:key="privacy_location_access"
+ android:title="@string/location_settings"
+ android:summary="@string/location_settings_subtitle"/>
+
+ <com.android.permissioncontroller.safetycenter.ui.ComparablePreferenceCategory
+ android:key="subpage_controls_extra_entry_group"
+ android:layout="@layout/preference_category_no_label"
+ app:selectable="false" />
+ </com.android.permissioncontroller.safetycenter.ui.ComparablePreferenceCategory>
+</PreferenceScreen>
diff --git a/PermissionController/res/xml-v34/safety_center_subpage.xml b/PermissionController/res/xml-v34/safety_center_subpage.xml
new file mode 100644
index 000000000..81e246773
--- /dev/null
+++ b/PermissionController/res/xml-v34/safety_center_subpage.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <com.android.permissioncontroller.safetycenter.ui.SafetyBrandChipPreference
+ android:key="subpage_brand_chip"
+ app:selectable="false"/>
+
+ <com.android.permissioncontroller.safetycenter.ui.SafetyIllustrationPreference
+ android:key="subpage_illustration"
+ app:selectable="false"/>
+
+ <com.android.permissioncontroller.safetycenter.ui.ComparablePreferenceCategory
+ android:key="subpage_issue_group"
+ android:layout="@layout/preference_category_no_label"
+ app:selectable="false" />
+
+ <com.android.permissioncontroller.safetycenter.ui.ComparablePreferenceCategory
+ android:key="subpage_entry_group"
+ app:selectable="false" />
+
+ <com.android.settingslib.widget.FooterPreference
+ android:key="subpage_footer"
+ app:selectable="false"/>
+
+ <com.android.permissioncontroller.safetycenter.ui.SpacerPreference
+ android:key="subpage_spacer"
+ app:selectable="false"/>
+</PreferenceScreen>
diff --git a/PermissionController/res/xml/privacy_controls.xml b/PermissionController/res/xml/privacy_controls.xml
new file mode 100644
index 000000000..48dc8f180
--- /dev/null
+++ b/PermissionController/res/xml/privacy_controls.xml
@@ -0,0 +1,53 @@
+<!--
+ ~ 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.
+ -->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="privacy_controls_page"
+ android:title="@string/privacy_controls_title">
+
+ <!-- Camera toggle -->
+ <com.android.permissioncontroller.safetycenter.ui.ClickableDisabledSwitchPreference
+ android:key="privacy_camera_toggle"
+ android:title="@string/camera_toggle_title"
+ android:summary="@string/perm_toggle_description" />
+
+ <!-- Microphone toggle -->
+ <com.android.permissioncontroller.safetycenter.ui.ClickableDisabledSwitchPreference
+ android:key="privacy_mic_toggle"
+ android:title="@string/mic_toggle_title"
+ android:summary="@string/mic_toggle_description"/>
+
+ <!-- Clipboard access notifications toggle -->
+ <com.android.permissioncontroller.safetycenter.ui.ClickableDisabledSwitchPreference
+ android:key="show_clip_access_notification"
+ android:title="@string/show_clip_access_notification_title"
+ android:summary="@string/show_clip_access_notification_summary" />
+
+ <!-- Show password toggle-->
+ <com.android.permissioncontroller.safetycenter.ui.ClickableDisabledSwitchPreference
+ android:key="show_password"
+ android:title="@string/show_password_title"
+ android:summary="@string/show_password_summary"/>
+
+ <!-- Location link -->
+ <Preference
+ android:key="privacy_location_access"
+ android:title="@string/location_settings"
+ android:summary="@string/location_settings_subtitle"/>
+
+</PreferenceScreen>
diff --git a/PermissionController/res/xml/roles.xml b/PermissionController/res/xml/roles.xml
index 1a37f3538..2f8f5a291 100644
--- a/PermissionController/res/xml/roles.xml
+++ b/PermissionController/res/xml/roles.xml
@@ -84,6 +84,7 @@
<permission name="android.permission.BLUETOOTH_ADVERTISE" minSdkVersion="31" />
<permission name="android.permission.BLUETOOTH_CONNECT" minSdkVersion="31" />
<permission name="android.permission.BLUETOOTH_SCAN" minSdkVersion="31" />
+ <permission name="android.permission.NEARBY_WIFI_DEVICES" minSdkVersion="33" />
</permission-set>
<permission-set name="notifications">
@@ -101,7 +102,8 @@
label="@string/role_assistant_label"
overrideUserWhenGranting="true"
requestable="false"
- shortLabel="@string/role_assistant_short_label">
+ shortLabel="@string/role_assistant_short_label"
+ uiBehavior="AssistantRoleUiBehavior">
<required-components>
<!-- Qualified components are determined int AssistantRoleBehavior. This comment here is
ignored and represents just a rough description
@@ -136,6 +138,8 @@
minSdkVersion="33"/>
<permission name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE"
minSdkVersion="33" />
+ <permission name="android.permission.EXECUTE_APP_ACTION"
+ minSdkVersion="34" />
</permissions>
<app-op-permissions>
<app-op-permission name="android.permission.SYSTEM_ALERT_WINDOW" />
@@ -159,7 +163,8 @@
overrideUserWhenGranting="true"
requestDescription="@string/role_browser_request_description"
requestTitle="@string/role_browser_request_title"
- shortLabel="@string/role_browser_short_label">
+ shortLabel="@string/role_browser_short_label"
+ uiBehavior="BrowserRoleUiBehavior">
<!--
~ Required components matching is handled in BrowserRoleBehavior because it needs the
~ PackageManager.MATCH_ALL flag and other manual filtering, which cannot fit in our
@@ -180,6 +185,9 @@
~ Not need to set preferred activity because PackageManager handles browser intents
~ specially.
-->
+ <permissions>
+ <permission name="android.permission.PROVIDE_OWN_AUTOFILL_SUGGESTIONS" minSdkVersion="34" />
+ </permissions>
</role>
<!--
@@ -201,7 +209,8 @@
requestDescription="@string/role_dialer_request_description"
requestTitle="@string/role_dialer_request_title"
searchKeywords="@string/role_dialer_search_keywords"
- shortLabel="@string/role_dialer_short_label">
+ shortLabel="@string/role_dialer_short_label"
+ uiBehavior="DialerRoleUiBehavior">
<required-components>
<activity>
<intent-filter>
@@ -287,7 +296,8 @@
requestDescription="@string/role_sms_request_description"
requestTitle="@string/role_sms_request_title"
searchKeywords="@string/role_sms_search_keywords"
- shortLabel="@string/role_sms_short_label">
+ shortLabel="@string/role_sms_short_label"
+ uiBehavior="SmsRoleUiBehavior">
<required-components>
<receiver permission="android.permission.BROADCAST_SMS">
<intent-filter>
@@ -377,7 +387,8 @@
requestTitle="@string/role_emergency_request_title"
searchKeywords="@string/role_emergency_search_keywords"
shortLabel="@string/role_emergency_short_label"
- systemOnly="true">
+ systemOnly="true"
+ uiBehavior="EmergencyRoleUiBehavior">
<required-components>
<activity>
<intent-filter>
@@ -407,7 +418,8 @@
requestDescription="@string/role_home_request_description"
requestTitle="@string/role_home_request_title"
searchKeywords="@string/role_home_search_keywords"
- shortLabel="@string/role_home_short_label">
+ shortLabel="@string/role_home_short_label"
+ uiBehavior="HomeRoleUiBehavior">
<!-- Also used by HomeRoleBehavior.getFallbackHolder(). -->
<required-components>
<activity>
@@ -565,6 +577,8 @@
<permission name="android.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION" minSdkVersion="33" />
<permission name="android.permission.SEND_SMS" />
<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"/>
</permissions>
</role>
@@ -600,6 +614,59 @@
<permission name="android.permission.ADD_ALWAYS_UNLOCKED_DISPLAY" minSdkVersion="33" />
<permission name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE"
minSdkVersion="33" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_AIRPLANE_MODE"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_APP_EXEMPTIONS"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_APP_RESTRICTIONS"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_BLUETOOTH"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_CALLS" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_CAMERA"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_FACTORY_RESET"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_FUN" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_KEYGUARD"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_LOCK" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_LOCK_TASK"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_MOBILE_NETWORK"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_MODIFY_USERS"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_PACKAGE_STATE"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_RESET_PASSWORD"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_SAFE_BOOT"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_SMS" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_STATUS_BAR"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_TIME" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER"
+ minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_WINDOWS" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_WIPE_DATA"
+ minSdkVersion="34" />
+ <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" />
</permissions>
</role>
@@ -670,6 +737,9 @@
<permission name="android.permission.SUSPEND_APPS"/>
<permission name="android.permission.SYSTEM_APPLICATION_OVERLAY"/>
</permissions>
+ <app-op-permissions>
+ <app-op-permission name="android.permission.SCHEDULE_EXACT_ALARM" minSdkVersion="34"/>
+ </app-op-permissions>
</role>
<!---
@@ -1108,6 +1178,41 @@
</permissions>
</role>
+ <role
+ name="android.app.role.COMPANION_DEVICE_GLASSES"
+ behavior="CompanionDeviceGlassesRoleBehavior"
+ exclusive="false"
+ minSdkVersion="34"
+ systemOnly="false"
+ visible="false">
+ <permissions>
+ <permission-set name="contacts" />
+ <permission-set name="microphone" />
+ <permission-set name="nearby_devices" />
+ <permission-set name="notifications" />
+ <permission-set name="phone" />
+ <permission-set name="sms" />
+ </permissions>
+ <app-op-permissions>
+ <app-op-permission name="android.permission.MANAGE_ONGOING_CALLS" />
+ </app-op-permissions>
+ </role>
+
+ <role
+ name="android.app.role.COMPANION_DEVICE_NEARBY_DEVICE_STREAMING"
+ allowBypassingQualification="true"
+ exclusive="false"
+ minSdkVersion="34"
+ systemOnly="true"
+ visible="false">
+ <permissions>
+ <permission-set name="nearby_devices" />
+ <permission name="android.permission.CREATE_VIRTUAL_DEVICE" />
+ <permission name="android.permission.ADD_TRUSTED_DISPLAY" />
+ <permission name="android.permission.ADD_ALWAYS_UNLOCKED_DISPLAY" />
+ </permissions>
+ </role>
+
<role
name="android.app.role.SYSTEM_SUPERVISION"
defaultHolders="config_systemSupervision"
@@ -1118,6 +1223,8 @@
visible="false" >
<permissions>
<permission name="android.permission.ACCESS_INSTANT_APPS"/>
+ <permission name="android.permission.KILL_UID" minSdkVersion="34"/>
+ <permission name="android.permission.MANAGE_DEFAULT_APPLICATIONS" minSdkVersion="34"/>
<permission name="android.permission.SUSPEND_APPS"/>
<permission name="android.permission.SYSTEM_APPLICATION_OVERLAY"/>
</permissions>
@@ -1187,6 +1294,41 @@
<permission name="android.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES" />
<permission name="android.permission.QUERY_ADMIN_POLICY" />
<permission name="android.permission.TRIGGER_LOST_MODE" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_APP_EXEMPTIONS" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_AIRPLANE_MODE" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_CAMERA" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_CERTIFICATES" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_DEFAULT_SMS" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_FACTORY_RESET" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_INPUT_METHODS" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_KEYGUARD" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_LOCK" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_MOBILE_NETWORK" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_MTE" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_PACKAGE_STATE" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_PROFILES" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_SCREEN_CAPTURE" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_SECURITY_LOGGING" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_SUSPEND_PERSONAL_APPS" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_TIME" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_WIFI" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_WIPE_DATA" minSdkVersion="34" />
+ <permission name="android.permission.SET_TIME" minSdkVersion="34" />
+ <permission name="android.permission.SET_TIME_ZONE" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_MODIFY_USERS" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_SAFE_BOOT" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_MICROPHONE" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL" minSdkVersion="34" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS" minSdkVersion="34" />
</permissions>
</role>
@@ -1313,6 +1455,7 @@
visible="false">
<permissions>
<permission-set name="notifications" />
+ <permission name="android.permission.INTERACT_ACROSS_USERS_FULL" minSdkVersion="34" />
</permissions>
</role>
@@ -1340,4 +1483,131 @@
<permission name="android.permission.NET_TUNNELING" />
</permissions>
</role>
+
+ <!--
+ ~ A role assigned to the financing kiosk app
+ -->
+ <role
+ name="android.app.role.FINANCED_DEVICE_KIOSK"
+ exclusive="true"
+ minSdkVersion="34"
+ visible="false">
+ <permissions>
+ <permission-set name="notifications" />
+ <permission name="android.permission.MANAGE_DEVICE_LOCK_STATE" />
+ </permissions>
+ </role>
+
+ <!--
+ ~ A role assigned to the device lock controller
+ -->
+ <role
+ name="android.app.role.SYSTEM_FINANCED_DEVICE_CONTROLLER"
+ defaultHolders="config_systemFinancedDeviceController"
+ exclusive="true"
+ minSdkVersion="34"
+ static="true"
+ systemOnly="true"
+ visible="false">
+ <permissions>
+ <permission-set name="notifications" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_CALLS" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_LOCK_TASK" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_SAFE_BOOT" />
+ <permission name="android.permission.MANAGE_DEVICE_POLICY_TIME" />
+ <permission name="android.permission.MASTER_CLEAR" />
+ <permission name="android.permission.INTERACT_ACROSS_USERS" />
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
+ </permissions>
+ </role>
+
+ <!---
+ ~ A role for the wear health service that handles health/fitness tracking features.
+ -->
+ <role
+ name="android.app.role.SYSTEM_WEAR_HEALTH_SERVICE"
+ behavior="SystemWearHealthServiceRoleBehavior"
+ defaultHolders="config_systemWearHealthService"
+ exclusive="true"
+ minSdkVersion="33"
+ static="true"
+ systemOnly="true"
+ visible="false">
+ <permissions>
+ <permission-set name="sensors" />
+ <permission-set name="location" />
+ <permission name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+ <permission name="android.permission.ACTIVITY_RECOGNITION" />
+ </permissions>
+ </role>
+
+ <!---
+ ~ A role for the package that responds to system notes actions.
+ -->
+ <role
+ name="android.app.role.NOTES"
+ behavior="NotesRoleBehavior"
+ defaultHolders="config_defaultNotes"
+ description="@string/role_notes_description"
+ exclusive="true"
+ label="@string/role_notes_label"
+ minSdkVersion="34"
+ overrideUserWhenGranting="true"
+ requestable="false"
+ searchKeywords="@string/role_notes_search_keywords"
+ shortLabel="@string/role_notes_short_label"
+ showNone="true">
+ <required-components>
+ <!-- Flag value is FLAG_SHOW_WHEN_LOCKED | FLAG_TURN_SCREEN_ON -->
+ <activity flags="0x1800000">
+ <intent-filter>
+ <action name="android.intent.action.CREATE_NOTE" />
+ </intent-filter>
+ </activity>
+ </required-components>
+ <preferred-activities>
+ <preferred-activity>
+ <!-- Flag value is FLAG_SHOW_WHEN_LOCKED | FLAG_TURN_SCREEN_ON -->
+ <activity flags="0x1800000">
+ <intent-filter>
+ <action name="android.intent.action.CREATE_NOTE" />
+ </intent-filter>
+ </activity>
+ <intent-filter>
+ <action name="android.intent.action.CREATE_NOTE" />
+ </intent-filter>
+ </preferred-activity>
+ </preferred-activities>
+ <permissions>
+ <permission name="android.permission.LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE" minSdkVersion="34"/>
+ </permissions>
+ </role>
+
+ <!---
+ ~ A role for the package that streams calls to other devices.
+ -->
+ <role
+ name="android.app.role.SYSTEM_CALL_STREAMING"
+ allowBypassingQualification="true"
+ defaultHolders="config_systemCallStreaming"
+ exclusive="true"
+ minSdkVersion="34"
+ static="true"
+ systemOnly="true"
+ visible="false">
+ <permissions>
+ <permission name="android.permission.CALL_AUDIO_INTERCEPTION" />
+ <permission name="android.permission.RECORD_AUDIO" />
+ </permissions>
+ <required-components>
+ <service permission="android.permission.BIND_CALL_STREAMING_SERVICE">
+ <intent-filter>
+ <action name="android.telecom.CallStreamingService" />
+ </intent-filter>
+ </service>
+ </required-components>
+ </role>
</roles>
diff --git a/PermissionController/res/xml/safety_center_dashboard.xml b/PermissionController/res/xml/safety_center_dashboard.xml
index d72a8b9fb..216ef318e 100644
--- a/PermissionController/res/xml/safety_center_dashboard.xml
+++ b/PermissionController/res/xml/safety_center_dashboard.xml
@@ -24,22 +24,23 @@
android:order="-3"
app:selectable="false" />
- <!-- TODO(b/205996247): Add primary safety warning. -->
- <!-- TODO(b/205999071): Add link to more warnings page. -->
- <PreferenceCategory
+ <com.android.permissioncontroller.safetycenter.ui.ComparablePreferenceCategory
android:key="issues_group"
- app:title="Issues"
+ android:layout="@layout/preference_category_no_label"
app:selectable="false" />
- <!-- TODO(b/205971026): Add real layouts for safety entries. -->
- <PreferenceCategory
+ <com.android.permissioncontroller.safetycenter.ui.ComparablePreferenceCategory
android:key="entries_group"
- app:title="Entries"
+ android:title="@string/safety_center_entries_category_title"
app:selectable="false" />
- <PreferenceCategory
+ <com.android.permissioncontroller.safetycenter.ui.ComparablePreferenceCategory
android:key="static_entries_group"
- app:title="Static entries"
+ android:layout="@layout/spaced_preference_category_no_label"
+ app:selectable="false" />
+
+ <com.android.permissioncontroller.safetycenter.ui.SpacerPreference
+ android:key="spacer"
app:selectable="false" />
</PreferenceScreen>
diff --git a/PermissionController/res/xml/unused_app_categories.xml b/PermissionController/res/xml/unused_app_categories.xml
index 19d882348..69cbfd143 100644
--- a/PermissionController/res/xml/unused_app_categories.xml
+++ b/PermissionController/res/xml/unused_app_categories.xml
@@ -18,12 +18,6 @@
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
- android:key="three_months"/>
-
- <PreferenceCategory
- android:key="six_months"/>
-
- <PreferenceCategory
android:key="info_msg_category"/>
</PreferenceScreen>
diff --git a/PermissionController/role-controller/Android.bp b/PermissionController/role-controller/Android.bp
new file mode 100644
index 000000000..1a790b730
--- /dev/null
+++ b/PermissionController/role-controller/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"],
+}
+
+java_library {
+ name: "role-controller",
+ srcs: [
+ "java/**/*.java",
+ ],
+ libs: [
+ "androidx.annotation_annotation",
+ ],
+ static_libs: [
+ "modules-utils-build_system",
+ ],
+ apex_available: [
+ "com.android.permission",
+ "test_com.android.permission",
+ ],
+ installable: false,
+ min_sdk_version: "30",
+ sdk_version: "system_current",
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/AssistantRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/AssistantRoleBehavior.java
index c8286f9ca..12710cfd3 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/AssistantRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/AssistantRoleBehavior.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.behavior;
import android.app.ActivityManager;
import android.app.role.RoleManager;
@@ -27,7 +27,6 @@ import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.Process;
import android.os.UserHandle;
-import android.provider.Settings;
import android.service.voice.VoiceInteractionService;
import android.util.ArraySet;
import android.util.AttributeSet;
@@ -37,8 +36,9 @@ import android.util.Xml;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.permissioncontroller.R;
-import com.android.permissioncontroller.role.utils.UserUtils;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.RoleBehavior;
+import com.android.role.controller.util.UserUtils;
import org.xmlpull.v1.XmlPullParserException;
@@ -78,44 +78,6 @@ public class AssistantRoleBehavior implements RoleBehavior {
return !UserUtils.isProfile(user, context);
}
- @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,
- @NonNull Context context) {
-
- if (isAutomotive(context)){
- return null;
- }
-
- return new Intent(Settings.ACTION_VOICE_INPUT_SETTINGS);
- }
-
- @Nullable
- @Override
- public CharSequence getConfirmationMessage(@NonNull Role role, @NonNull String packageName,
- @NonNull Context context) {
-
- // see (b/216746393) for details
- if(isAutomotive(context)){
- boolean contextEnabled = Settings.Secure.getInt(context.getContentResolver(),
- "assist_structure_enabled", 1) != 0;
- boolean screenshotEnabled = Settings.Secure.getInt(context.getContentResolver(),
- "assist_screenshot_enabled", 1) != 0;
-
- if(!contextEnabled && !screenshotEnabled){
- return null;
- }
- }
-
- return context.getString(R.string.assistant_confirmation_message);
- }
-
@Nullable
@Override
public List<String> getQualifyingPackagesAsUser(@NonNull Role role, @NonNull UserHandle user,
@@ -197,14 +159,6 @@ public class AssistantRoleBehavior implements RoleBehavior {
public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
}
- /**
- * Returns true if the device is an Automotive device
- */
- private boolean isAutomotive(@NonNull Context context) {
- return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
- }
-
-
private boolean isAssistantVoiceInteractionService(@NonNull PackageManager pm,
@NonNull ServiceInfo si) {
if (!android.Manifest.permission.BIND_VOICE_INTERACTION.equals(si.permission)) {
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/AutomotiveRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/AutomotiveRoleBehavior.java
index 3596c7d91..6eedb8f4d 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/AutomotiveRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/AutomotiveRoleBehavior.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.behavior;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -22,6 +22,9 @@ import android.os.UserHandle;
import androidx.annotation.NonNull;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.RoleBehavior;
+
/**
* Class for behavior of the Automotive role.
*/
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/BrowserRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/BrowserRoleBehavior.java
index 9d4d9e08b..2cf6a0b14 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/BrowserRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/BrowserRoleBehavior.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.behavior;
import android.content.Context;
import android.content.Intent;
@@ -29,10 +29,12 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.modules.utils.build.SdkLevel;
-import com.android.permissioncontroller.R;
-import com.android.permissioncontroller.permission.utils.CollectionUtils;
-import com.android.permissioncontroller.role.utils.PackageUtils;
-import com.android.permissioncontroller.role.utils.UserUtils;
+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.util.CollectionUtils;
+import com.android.role.controller.util.PackageUtils;
+import com.android.role.controller.util.UserUtils;
import java.util.ArrayList;
import java.util.Arrays;
@@ -122,7 +124,7 @@ public class BrowserRoleBehavior implements RoleBehavior {
for (int i = 0; i < resolveInfosSize; i++) {
ResolveInfo resolveInfo = resolveInfos.get(i);
- if (!resolveInfo.handleAllWebDataURI) {
+ if (!resolveInfo.activityInfo.exported || !resolveInfo.handleAllWebDataURI) {
continue;
}
packageNames.add(resolveInfo.activityInfo.packageName);
@@ -136,8 +138,8 @@ public class BrowserRoleBehavior implements RoleBehavior {
// #grantDefaultPermissionsToDefaultBrowser(java.lang.String, int)
if (SdkLevel.isAtLeastS()) {
if (PackageUtils.isSystemPackage(packageName, context)) {
- Permissions.grant(packageName, SYSTEM_BROWSER_PERMISSIONS, false, false, false,
- true, false, context);
+ Permissions.grant(packageName, SYSTEM_BROWSER_PERMISSIONS, false, false, true,
+ false, false, context);
}
}
}
@@ -146,15 +148,9 @@ public class BrowserRoleBehavior implements RoleBehavior {
public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
if (SdkLevel.isAtLeastT()) {
if (PackageUtils.isSystemPackage(packageName, context)) {
- Permissions.revoke(packageName, SYSTEM_BROWSER_PERMISSIONS, false, true, false,
+ Permissions.revoke(packageName, SYSTEM_BROWSER_PERMISSIONS, true, false, false,
context);
}
}
}
-
- @Override
- public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
- @NonNull Context context) {
- return context.getResources().getBoolean(R.bool.config_showBrowserRole);
- }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/CompanionDeviceAppStreamingRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceAppStreamingRoleBehavior.java
index ca4af2355..131690fd7 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/CompanionDeviceAppStreamingRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceAppStreamingRoleBehavior.java
@@ -14,13 +14,15 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.behavior;
import android.content.Context;
import androidx.annotation.NonNull;
-import com.android.permissioncontroller.role.utils.NotificationUtils;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.RoleBehavior;
+import com.android.role.controller.util.NotificationUtils;
/**
* Class for behavior of the "App Streaming" Companion device profile role.
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/CompanionDeviceComputerRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceComputerRoleBehavior.java
index 1d9409f1f..c59d5e58d 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/CompanionDeviceComputerRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceComputerRoleBehavior.java
@@ -14,13 +14,15 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.behavior;
import android.content.Context;
import androidx.annotation.NonNull;
-import com.android.permissioncontroller.role.utils.NotificationUtils;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.RoleBehavior;
+import com.android.role.controller.util.NotificationUtils;
/**
* Class for behavior of the "Computer" Companion device profile role.
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
new file mode 100644
index 000000000..2e4691b9c
--- /dev/null
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceGlassesRoleBehavior.java
@@ -0,0 +1,41 @@
+/*
+ * 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.role.controller.behavior;
+
+import android.content.Context;
+
+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;
+
+/**
+ * Class for behavior of the "glasses" Companion device profile role.
+ */
+public class CompanionDeviceGlassesRoleBehavior implements RoleBehavior {
+
+ @Override
+ public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
+ NotificationUtils.grantNotificationAccessForPackage(context, packageName);
+ }
+
+ @Override
+ public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
+ NotificationUtils.revokeNotificationAccessForPackage(context, packageName);
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/CompanionDeviceWatchRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceWatchRoleBehavior.java
index 75675fb00..233c0d92e 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/CompanionDeviceWatchRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceWatchRoleBehavior.java
@@ -14,13 +14,15 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.behavior;
import android.content.Context;
import androidx.annotation.NonNull;
-import com.android.permissioncontroller.role.utils.NotificationUtils;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.RoleBehavior;
+import com.android.role.controller.util.NotificationUtils;
/**
* Class for behavior of the "watch" Companion device profile role.
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/DevicePolicyManagementRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/DevicePolicyManagementRoleBehavior.java
index 8232847e0..648b7d198 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/DevicePolicyManagementRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/DevicePolicyManagementRoleBehavior.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.behavior;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
@@ -23,6 +23,9 @@ import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.RoleBehavior;
+
/**
* Class for behavior of the device policy management role.
*/
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/DialerRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/DialerRoleBehavior.java
index 36be7e88a..79c139cee 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/DialerRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/DialerRoleBehavior.java
@@ -14,25 +14,22 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.behavior;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
import android.os.UserHandle;
-import android.telecom.TelecomManager;
import android.telephony.TelephonyManager;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.preference.Preference;
import com.android.modules.utils.build.SdkLevel;
-import com.android.permissioncontroller.R;
-import com.android.permissioncontroller.role.utils.PackageUtils;
+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.util.PackageUtils;
import java.util.Arrays;
import java.util.List;
-import java.util.Objects;
/**
* Class for behavior of the dialer role.
@@ -58,33 +55,6 @@ public class DialerRoleBehavior implements RoleBehavior {
}
@Override
- public void prepareApplicationPreferenceAsUser(@NonNull Role role,
- @NonNull Preference preference, @NonNull ApplicationInfo applicationInfo,
- @NonNull UserHandle user, @NonNull Context context) {
- TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
- String systemPackageName = telecomManager.getSystemDialerPackage();
- if (Objects.equals(applicationInfo.packageName, systemPackageName)) {
- preference.setSummary(R.string.default_app_system_default);
- } else {
- preference.setSummary(null);
- }
- }
-
- @Nullable
- @Override
- public CharSequence getConfirmationMessage(@NonNull Role role, @NonNull String packageName,
- @NonNull Context context) {
- return EncryptionUnawareConfirmationMixin.getConfirmationMessage(role, packageName,
- context);
- }
-
- @Override
- public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
- @NonNull Context context) {
- return context.getResources().getBoolean(R.bool.config_showDialerRole);
- }
-
- @Override
public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
if (SdkLevel.isAtLeastS()) {
if (PackageUtils.isSystemPackage(packageName, context)) {
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/DocumentManagerRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/DocumentManagerRoleBehavior.java
index ce307fd82..ee7984274 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/DocumentManagerRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/DocumentManagerRoleBehavior.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.behavior;
import android.content.Context;
import android.os.Process;
@@ -22,6 +22,9 @@ import android.util.Log;
import androidx.annotation.NonNull;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.RoleBehavior;
+
import java.util.Collections;
import java.util.List;
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/EmergencyRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/EmergencyRoleBehavior.java
index d0b2bf42a..a54006bb5 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/EmergencyRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/EmergencyRoleBehavior.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.behavior;
import android.content.Context;
import android.content.pm.PackageInfo;
@@ -25,7 +25,9 @@ import android.telephony.TelephonyManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.permissioncontroller.role.utils.PackageUtils;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.RoleBehavior;
+import com.android.role.controller.util.PackageUtils;
import java.util.List;
@@ -66,18 +68,4 @@ 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", context);
- }
-
- @Nullable
- @Override
- public CharSequence getConfirmationMessage(@NonNull Role role, @NonNull String packageName,
- @NonNull Context context) {
- return EncryptionUnawareConfirmationMixin.getConfirmationMessage(role, packageName,
- context);
- }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/HomeRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/HomeRoleBehavior.java
index af6acfeec..3254bc6e4 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/HomeRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/HomeRoleBehavior.java
@@ -14,31 +14,24 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.behavior;
-import android.app.admin.DevicePolicyResources.Strings.DefaultAppSettings;
-import android.app.role.RoleManager;
-import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
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 android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-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.ui.TwoTargetPreference;
-import com.android.permissioncontroller.role.utils.UserUtils;
+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.util.UserUtils;
import java.util.Arrays;
import java.util.List;
@@ -53,8 +46,6 @@ import java.util.Objects;
*/
public class HomeRoleBehavior implements RoleBehavior {
- private static final String LOG_TAG = HomeRoleBehavior.class.getSimpleName();
-
private static final List<String> AUTOMOTIVE_PERMISSIONS = Arrays.asList(
android.Manifest.permission.READ_CALL_LOG,
android.Manifest.permission.WRITE_CALL_LOG,
@@ -100,71 +91,10 @@ public class HomeRoleBehavior implements RoleBehavior {
return packageName;
}
- @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) {
- TwoTargetPreference.OnSecondTargetClickListener listener = null;
- RoleManager roleManager = context.getSystemService(RoleManager.class);
- String packageName = CollectionUtils.firstOrNull(roleManager.getRoleHoldersAsUser(
- role.getName(), user));
- if (packageName != null) {
- Intent intent = new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
- .setPackage(packageName)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- PackageManager userPackageManager = UserUtils.getUserContext(context, user)
- .getPackageManager();
- ResolveInfo resolveInfo = userPackageManager.resolveActivity(intent, 0);
- if (resolveInfo != null && resolveInfo.activityInfo != null
- && resolveInfo.activityInfo.exported) {
- listener = preference2 -> {
- try {
- context.startActivity(intent);
- } catch (ActivityNotFoundException e) {
- Log.e(LOG_TAG, "Cannot start activity for home app preferences", e);
- }
- };
- }
- }
- preference.setOnSecondTargetClickListener(listener);
- }
-
- @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 !isSettingsApplication(applicationInfo, context);
- }
-
- @Override
- public void prepareApplicationPreferenceAsUser(@NonNull Role role,
- @NonNull Preference preference, @NonNull ApplicationInfo applicationInfo,
- @NonNull UserHandle user, @NonNull Context context) {
- boolean missingWorkProfileSupport = isMissingWorkProfileSupport(applicationInfo, context);
- preference.setEnabled(!missingWorkProfileSupport);
- preference.setSummary(missingWorkProfileSupport ? Utils.getEnterpriseString(context,
- DefaultAppSettings.HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE,
- R.string.home_missing_work_profile_support) : null);
- }
-
- private boolean isMissingWorkProfileSupport(@NonNull ApplicationInfo applicationInfo,
- @NonNull Context context) {
- boolean hasWorkProfile = UserUtils.getWorkProfile(context) != null;
- if (!hasWorkProfile) {
- return false;
- }
- boolean isWorkProfileSupported = applicationInfo.targetSdkVersion
- >= Build.VERSION_CODES.LOLLIPOP;
- return !isWorkProfileSupported;
- }
-
- private boolean isSettingsApplication(@NonNull ApplicationInfo applicationInfo,
+ /**
+ * 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(
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/NotesRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/NotesRoleBehavior.java
new file mode 100644
index 000000000..14c189a0f
--- /dev/null
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/NotesRoleBehavior.java
@@ -0,0 +1,58 @@
+/*
+ * 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.role.controller.behavior;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Build;
+import android.os.UserHandle;
+
+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 Notes role.
+ */
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+public class NotesRoleBehavior implements RoleBehavior {
+
+ @Override
+ public boolean isAvailableAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ // Role should be enabled by OEMs.
+ Resources resources = context.getResources();
+ if (!resources.getBoolean(android.R.bool.config_enableDefaultNotes)) {
+ return false;
+ }
+
+ // Cloned profile shouldn't have a separate role.
+ if (UserUtils.isCloneProfile(user, context)) {
+ return false;
+ }
+
+ if (UserUtils.isManagedProfile(user, context)) {
+ // The role holder for work profile is separately controlled via config.
+ return resources.getBoolean(android.R.bool.config_enableDefaultNotesForWorkProfile);
+ }
+
+ return true;
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/SmsRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/SmsRoleBehavior.java
index 1515945c1..c1186a930 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/SmsRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/SmsRoleBehavior.java
@@ -14,8 +14,10 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+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;
@@ -26,10 +28,12 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.modules.utils.build.SdkLevel;
-import com.android.permissioncontroller.R;
-import com.android.permissioncontroller.permission.utils.CollectionUtils;
-import com.android.permissioncontroller.role.utils.PackageUtils;
-import com.android.permissioncontroller.role.utils.UserUtils;
+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.util.CollectionUtils;
+import com.android.role.controller.util.PackageUtils;
+import com.android.role.controller.util.UserUtils;
import java.util.Arrays;
import java.util.List;
@@ -54,9 +58,31 @@ public class SmsRoleBehavior implements RoleBehavior {
@Override
public boolean isAvailableAsUser(@NonNull Role role, @NonNull UserHandle user,
@NonNull Context context) {
- if (UserUtils.isProfile(user, context)) {
- return false;
+ if (SdkLevel.isAtLeastU()) {
+ if (UserUtils.isCloneProfile(user, context)) {
+ return false;
+ }
+
+ // If work profile telephony is not enabled, there is no reason for sms role to be
+ // available in work profile. Given that you can't send or receive work message without
+ // work profile telephony being enabled.
+ // Also when work profile telephony gets enabled, dialer/sms app gets installed in to
+ // work profile, which would trigger this function and hence sms role getting
+ // enabled at the right point of time.
+ if (UserUtils.isManagedProfile(user, context)) {
+ DevicePolicyManager devicePolicyManager = context.getSystemService(
+ DevicePolicyManager.class);
+ if (devicePolicyManager.getManagedSubscriptionsPolicy().getPolicyType()
+ != ManagedSubscriptionsPolicy.TYPE_ALL_MANAGED_SUBSCRIPTIONS) {
+ return false;
+ }
+ }
+ } else {
+ if (UserUtils.isProfile(user, context)) {
+ return false;
+ }
}
+
UserManager userManager = context.getSystemService(UserManager.class);
if (userManager.isRestrictedProfile(user)) {
return false;
@@ -86,20 +112,6 @@ public class SmsRoleBehavior implements RoleBehavior {
return CollectionUtils.firstOrNull(qualifyingPackageNames);
}
- @Nullable
- @Override
- public CharSequence getConfirmationMessage(@NonNull Role role, @NonNull String packageName,
- @NonNull Context context) {
- return EncryptionUnawareConfirmationMixin.getConfirmationMessage(role, packageName,
- context);
- }
-
- @Override
- public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
- @NonNull Context context) {
- return context.getResources().getBoolean(R.bool.config_showSmsRole);
- }
-
@Override
public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {
if (SdkLevel.isAtLeastS() && PackageUtils.isSystemPackage(packageName, context)) {
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/SystemShellRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemShellRoleBehavior.java
index 9476e2bae..c0cbe9c25 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/SystemShellRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemShellRoleBehavior.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.behavior;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -24,6 +24,9 @@ import android.os.UserHandle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.RoleBehavior;
+
/**
* Class for behavior of the system shell role.
*/
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/SystemUiRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemUiRoleBehavior.java
index c08232931..210c2313f 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/SystemUiRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemUiRoleBehavior.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.behavior;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -22,6 +22,9 @@ 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;
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemWearHealthServiceRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemWearHealthServiceRoleBehavior.java
new file mode 100644
index 000000000..d9f34291d
--- /dev/null
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemWearHealthServiceRoleBehavior.java
@@ -0,0 +1,36 @@
+/*
+ * 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.role.controller.behavior;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+
+import androidx.annotation.NonNull;
+
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.RoleBehavior;
+
+/** The role behavior for System Wear Health Service. */
+public class SystemWearHealthServiceRoleBehavior implements RoleBehavior {
+ @Override
+ public boolean isAvailableAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ // Role is only available on Watches.
+ return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/TelevisionRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/TelevisionRoleBehavior.java
index b854e3e35..88021e62d 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/TelevisionRoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/TelevisionRoleBehavior.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.behavior;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -22,6 +22,9 @@ import android.os.UserHandle;
import androidx.annotation.NonNull;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.RoleBehavior;
+
/**
* The base behaviour class for the roles available only on TV.
*/
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/AppOp.java b/PermissionController/role-controller/java/com/android/role/controller/model/AppOp.java
index 700cf7fe7..3efa68bc9 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/AppOp.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/AppOp.java
@@ -14,15 +14,16 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.model;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.os.Process;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.permissioncontroller.role.utils.PackageUtils;
+import com.android.role.controller.util.PackageUtils;
import java.util.Objects;
@@ -103,7 +104,8 @@ public class AppOp {
if (mMaxTargetSdkVersion == null) {
return true;
}
- ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(packageName, context);
+ ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName,
+ Process.myUserHandle(), context);
if (applicationInfo == null) {
return false;
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/AppOpPermissions.java b/PermissionController/role-controller/java/com/android/role/controller/model/AppOpPermissions.java
index 25d8dc942..f3f9b321e 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/AppOpPermissions.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/AppOpPermissions.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.model;
import android.app.AppOpsManager;
import android.content.Context;
@@ -24,8 +24,8 @@ import android.os.Build;
import androidx.annotation.NonNull;
-import com.android.permissioncontroller.permission.utils.ArrayUtils;
-import com.android.permissioncontroller.role.utils.PackageUtils;
+import com.android.role.controller.util.ArrayUtils;
+import com.android.role.controller.util.PackageUtils;
/**
* App op permissions to be granted or revoke by a {@link Role}.
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/IntentFilterData.java b/PermissionController/role-controller/java/com/android/role/controller/model/IntentFilterData.java
index 0bf1ce585..90deebfc6 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/IntentFilterData.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/IntentFilterData.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.model;
import android.content.Intent;
import android.content.IntentFilter;
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/Permission.java b/PermissionController/role-controller/java/com/android/role/controller/model/Permission.java
index ae1b6d0e9..0c4a14574 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/Permission.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/Permission.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.model;
import android.os.Build;
@@ -60,9 +60,9 @@ public class Permission {
* @return whether this permission is available
*/
public boolean isAvailable() {
- // Workaround to match the value 33+ for T+ in roles.xml before SDK finalization.
- if (mMinSdkVersion >= 33) {
- return SdkLevel.isAtLeastT();
+ // Workaround to match the value 34+ for U+ in roles.xml before SDK finalization.
+ if (mMinSdkVersion >= 34) {
+ return SdkLevel.isAtLeastU();
} else {
return Build.VERSION.SDK_INT >= mMinSdkVersion;
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/PermissionSet.java b/PermissionController/role-controller/java/com/android/role/controller/model/PermissionSet.java
index 1568c5c74..72f127e1c 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/PermissionSet.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/PermissionSet.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.model;
import androidx.annotation.NonNull;
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/Permissions.java b/PermissionController/role-controller/java/com/android/role/controller/model/Permissions.java
index 4bacdcf28..f55a84c07 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/Permissions.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/Permissions.java
@@ -14,9 +14,8 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.model;
-import android.Manifest;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -35,10 +34,9 @@ import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.permissioncontroller.permission.utils.ArrayUtils;
-import com.android.permissioncontroller.permission.utils.CollectionUtils;
-import com.android.permissioncontroller.permission.utils.Utils;
-import com.android.permissioncontroller.role.utils.PackageUtils;
+import com.android.role.controller.util.ArrayUtils;
+import com.android.role.controller.util.CollectionUtils;
+import com.android.role.controller.util.PackageUtils;
import java.util.ArrayList;
import java.util.List;
@@ -57,6 +55,8 @@ public class Permissions {
private static ArrayMap<String, List<String>> sBackgroundToForegroundPermissions;
private static final Object sForegroundBackgroundPermissionMappingsLock = new Object();
+ private static final ArrayMap<String, Boolean> sRestrictedPermissions = new ArrayMap<>();
+
/**
* Filter a list of permissions based on their SDK versions.
*
@@ -180,16 +180,12 @@ public class Permissions {
Set<String> whitelistedRestrictedPermissions = new ArraySet<>(
packageManager.getWhitelistedRestrictedPermissions(packageName,
PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM));
- List<String> smsPermissions = Utils.getPlatformPermissionNamesOfGroup(
- Manifest.permission_group.SMS);
- List<String> callLogPermissions = Utils.getPlatformPermissionNamesOfGroup(
- Manifest.permission_group.CALL_LOG);
int sortedPermissionsToGrantLength = sortedPermissionsToGrant.length;
for (int i = 0; i < sortedPermissionsToGrantLength; i++) {
String permission = sortedPermissionsToGrant[i];
- if ((smsPermissions.contains(permission) || callLogPermissions.contains(permission))
+ if (isRestrictedPermission(permission, context)
&& whitelistedRestrictedPermissions.add(permission)) {
packageManager.addWhitelistedRestrictedPermission(packageName, permission,
PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM);
@@ -432,7 +428,9 @@ public class Permissions {
PackageManager packageManager = context.getPackageManager();
Set<String> whitelistedRestrictedPermissions =
packageManager.getWhitelistedRestrictedPermissions(packageName,
- Utils.FLAGS_PERMISSION_WHITELIST_ALL);
+ PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+ | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+ | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
boolean permissionOrAppOpChanged = false;
@@ -583,7 +581,8 @@ public class Permissions {
static boolean isRuntimePermissionsSupported(@NonNull String packageName,
@NonNull Context context) {
- ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(packageName, context);
+ ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName,
+ Process.myUserHandle(), context);
if (applicationInfo == null) {
return false;
}
@@ -712,6 +711,34 @@ public class Permissions {
}
}
+ private static boolean isRestrictedPermission(@NonNull String permission,
+ @NonNull Context context) {
+ synchronized (sRestrictedPermissions) {
+ if (sRestrictedPermissions.containsKey(permission)) {
+ return sRestrictedPermissions.get(permission);
+ }
+ }
+
+ PackageManager packageManager = context.getPackageManager();
+ PermissionInfo permissionInfo = null;
+ try {
+ permissionInfo = packageManager.getPermissionInfo(permission, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(LOG_TAG, "Cannot get PermissionInfo for permission: " + permission);
+ }
+
+ // Don't expect that to be a transient error, so we can still cache the failed information.
+ boolean isRestrictedPermission = permissionInfo != null
+ && (permissionInfo.flags & (PermissionInfo.FLAG_SOFT_RESTRICTED
+ | PermissionInfo.FLAG_HARD_RESTRICTED)) != 0;
+
+ synchronized (sRestrictedPermissions) {
+ sRestrictedPermissions.put(permission, isRestrictedPermission);
+ }
+
+ return isRestrictedPermission;
+ }
+
private static void createForegroundBackgroundPermissionMappings(@NonNull Context context) {
List<String> permissions = new ArrayList<>();
sBackgroundToForegroundPermissions = new ArrayMap<>();
@@ -727,8 +754,8 @@ public class Permissions {
List<PermissionInfo> permissionInfos;
try {
- permissionInfos = Utils.getPermissionInfosForGroup(packageManager,
- permissionGroupInfo.name);
+ permissionInfos = packageManager.queryPermissionsByGroup(
+ permissionGroupInfo.name, 0);
} catch (PackageManager.NameNotFoundException e) {
Log.e(LOG_TAG, "Cannot get permissions for group: " + permissionGroupInfo.name);
continue;
@@ -791,7 +818,8 @@ public class Permissions {
@Nullable
static Integer getAppOpMode(@NonNull String packageName, @NonNull String appOp,
@NonNull Context context) {
- ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(packageName, context);
+ ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName,
+ Process.myUserHandle(), context);
if (applicationInfo == null) {
return null;
}
@@ -819,7 +847,8 @@ public class Permissions {
if (currentMode != null && currentMode == mode) {
return false;
}
- ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(packageName, context);
+ ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName,
+ Process.myUserHandle(), context);
if (applicationInfo == null) {
Log.e(LOG_TAG, "Cannot get ApplicationInfo for package to set app op mode: "
+ packageName);
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/PreferredActivity.java b/PermissionController/role-controller/java/com/android/role/controller/model/PreferredActivity.java
index f03527b36..5b9c22b67 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/PreferredActivity.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/PreferredActivity.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.model;
import android.content.ComponentName;
import android.content.Context;
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/RequiredActivity.java b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredActivity.java
index def0a6dbf..58c878e56 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/RequiredActivity.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredActivity.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.model;
import android.content.ComponentName;
import android.content.Context;
@@ -27,7 +27,7 @@ import android.os.UserHandle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.permissioncontroller.role.utils.UserUtils;
+import com.android.role.controller.util.UserUtils;
import java.util.List;
@@ -37,8 +37,9 @@ import java.util.List;
public class RequiredActivity extends RequiredComponent {
public RequiredActivity(@NonNull IntentFilterData intentFilterData, int minTargetSdkVersion,
- @Nullable String permission, int queryFlags, @NonNull List<RequiredMetaData> metaData) {
- super(intentFilterData, minTargetSdkVersion, permission, queryFlags, metaData);
+ int flags, @Nullable String permission, int queryFlags,
+ @NonNull List<RequiredMetaData> metaData) {
+ super(intentFilterData, minTargetSdkVersion, flags, permission, queryFlags, metaData);
}
@NonNull
@@ -58,6 +59,11 @@ public class RequiredActivity extends RequiredComponent {
resolveInfo.activityInfo.name);
}
+ @Override
+ protected int getComponentFlags(@NonNull ResolveInfo resolveInfo) {
+ return resolveInfo.activityInfo.flags;
+ }
+
@Nullable
@Override
protected String getComponentPermission(@NonNull ResolveInfo resolveInfo) {
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/RequiredBroadcastReceiver.java b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredBroadcastReceiver.java
index 1f756f618..945fda3c3 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/RequiredBroadcastReceiver.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredBroadcastReceiver.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.model;
import android.content.ComponentName;
import android.content.Context;
@@ -27,7 +27,7 @@ import android.os.UserHandle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.permissioncontroller.role.utils.UserUtils;
+import com.android.role.controller.util.UserUtils;
import java.util.List;
@@ -37,9 +37,9 @@ import java.util.List;
public class RequiredBroadcastReceiver extends RequiredComponent {
public RequiredBroadcastReceiver(@NonNull IntentFilterData intentFilterData,
- int minTargetSdkVersion, @Nullable String permission, int queryFlags,
+ int minTargetSdkVersion, int flags, @Nullable String permission, int queryFlags,
@NonNull List<RequiredMetaData> metaData) {
- super(intentFilterData, minTargetSdkVersion, permission, queryFlags, metaData);
+ super(intentFilterData, minTargetSdkVersion, flags, permission, queryFlags, metaData);
}
@NonNull
@@ -58,6 +58,11 @@ public class RequiredBroadcastReceiver extends RequiredComponent {
resolveInfo.activityInfo.name);
}
+ @Override
+ protected int getComponentFlags(@NonNull ResolveInfo resolveInfo) {
+ return resolveInfo.activityInfo.flags;
+ }
+
@Nullable
@Override
protected String getComponentPermission(@NonNull ResolveInfo resolveInfo) {
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/RequiredComponent.java b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredComponent.java
index 361727d59..ae6156e7f 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/RequiredComponent.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredComponent.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.model;
import android.content.ComponentName;
import android.content.Context;
@@ -56,6 +56,11 @@ public abstract class RequiredComponent {
private final int mMinTargetSdkVersion;
/**
+ * Optional flags required to be set on a component for match to succeed.
+ */
+ private final int mFlags;
+
+ /**
* Optional permission required on a component for match to succeed.
*
* @see android.content.pm.ActivityInfo#permission
@@ -78,9 +83,11 @@ public abstract class RequiredComponent {
private final List<RequiredMetaData> mMetaData;
public RequiredComponent(@NonNull IntentFilterData intentFilterData, int minTargetSdkVersion,
- @Nullable String permission, int queryFlags, @NonNull List<RequiredMetaData> metaData) {
+ int flags, @Nullable String permission, int queryFlags,
+ @NonNull List<RequiredMetaData> metaData) {
mIntentFilterData = intentFilterData;
mMinTargetSdkVersion = minTargetSdkVersion;
+ mFlags = flags;
mPermission = permission;
mQueryFlags = queryFlags;
mMetaData = metaData;
@@ -101,9 +108,9 @@ public abstract class RequiredComponent {
* @return whether this required component is available
*/
public boolean isAvailable() {
- // Workaround to match the value 33+ for T+ in roles.xml before SDK finalization.
- if (mMinTargetSdkVersion >= 33) {
- return SdkLevel.isAtLeastT();
+ // Workaround to match the value 34+ for U+ in roles.xml before SDK finalization.
+ if (mMinTargetSdkVersion >= 34) {
+ return SdkLevel.isAtLeastU();
} else {
return Build.VERSION.SDK_INT >= mMinTargetSdkVersion;
}
@@ -119,6 +126,10 @@ public abstract class RequiredComponent {
return isAvailable() && applicationInfo.targetSdkVersion >= mMinTargetSdkVersion;
}
+ public int getFlags() {
+ return mFlags;
+ }
+
@Nullable
public String getPermission() {
return mPermission;
@@ -169,13 +180,14 @@ public abstract class RequiredComponent {
if (packageName != null) {
intent.setPackage(packageName);
}
- int flags = mQueryFlags | PackageManager.MATCH_DIRECT_BOOT_AWARE
+ int queryFlags = mQueryFlags | PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
boolean hasMetaData = !mMetaData.isEmpty();
if (hasMetaData) {
- flags |= PackageManager.GET_META_DATA;
+ queryFlags |= PackageManager.GET_META_DATA;
}
- List<ResolveInfo> resolveInfos = queryIntentComponentsAsUser(intent, flags, user, context);
+ List<ResolveInfo> resolveInfos = queryIntentComponentsAsUser(intent, queryFlags, user,
+ context);
ArraySet<String> componentPackageNames = new ArraySet<>();
List<ComponentName> componentNames = new ArrayList<>();
@@ -183,6 +195,13 @@ public abstract class RequiredComponent {
for (int resolveInfosIndex = 0; resolveInfosIndex < resolveInfosSize; resolveInfosIndex++) {
ResolveInfo resolveInfo = resolveInfos.get(resolveInfosIndex);
+ if (mFlags != 0) {
+ int componentFlags = getComponentFlags(resolveInfo);
+ if ((componentFlags & mFlags) != mFlags) {
+ continue;
+ }
+ }
+
if (mPermission != null) {
String componentPermission = getComponentPermission(resolveInfo);
if (!Objects.equals(componentPermission, mPermission)) {
@@ -248,6 +267,15 @@ public abstract class RequiredComponent {
protected abstract ComponentName getComponentComponentName(@NonNull ResolveInfo resolveInfo);
/**
+ * Get the flags that have been set on a component.
+ *
+ * @param resolveInfo the {@code ResolveInfo} of the component
+ *
+ * @return the flags that have been set on a component
+ */
+ protected abstract int getComponentFlags(@NonNull ResolveInfo resolveInfo);
+
+ /**
* Get the permission required to access a component.
*
* @param resolveInfo the {@code ResolveInfo} of the component
@@ -272,6 +300,7 @@ public abstract class RequiredComponent {
return "RequiredComponent{"
+ "mIntentFilterData=" + mIntentFilterData
+ ", mMinTargetSdkVersion=" + mMinTargetSdkVersion
+ + ", mFlags='" + mFlags + '\''
+ ", mPermission='" + mPermission + '\''
+ ", mQueryFlags=" + mQueryFlags
+ ", mMetaData=" + mMetaData
@@ -289,6 +318,7 @@ public abstract class RequiredComponent {
RequiredComponent that = (RequiredComponent) object;
return Objects.equals(mIntentFilterData, that.mIntentFilterData)
&& Objects.equals(mMinTargetSdkVersion, that.mMinTargetSdkVersion)
+ && mFlags == that.mFlags
&& Objects.equals(mPermission, that.mPermission)
&& mQueryFlags == that.mQueryFlags
&& Objects.equals(mMetaData, that.mMetaData);
@@ -296,7 +326,7 @@ public abstract class RequiredComponent {
@Override
public int hashCode() {
- return Objects.hash(mIntentFilterData, mMinTargetSdkVersion, mPermission, mQueryFlags,
- mMetaData);
+ return Objects.hash(mIntentFilterData, mMinTargetSdkVersion, mFlags, mPermission,
+ mQueryFlags, mMetaData);
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/RequiredContentProvider.java b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredContentProvider.java
index 76c82faf6..7b53a25bb 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/RequiredContentProvider.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredContentProvider.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.model;
import android.content.ComponentName;
import android.content.Context;
@@ -27,7 +27,7 @@ import android.os.UserHandle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.permissioncontroller.role.utils.UserUtils;
+import com.android.role.controller.util.UserUtils;
import java.util.List;
@@ -37,9 +37,9 @@ import java.util.List;
public class RequiredContentProvider extends RequiredComponent {
public RequiredContentProvider(@NonNull IntentFilterData intentFilterData,
- int minTargetSdkVersion, @Nullable String permission, int queryFlags,
+ int minTargetSdkVersion, int flags, @Nullable String permission, int queryFlags,
@NonNull List<RequiredMetaData> metaData) {
- super(intentFilterData, minTargetSdkVersion, permission, queryFlags, metaData);
+ super(intentFilterData, minTargetSdkVersion, flags, permission, queryFlags, metaData);
}
@NonNull
@@ -58,6 +58,11 @@ public class RequiredContentProvider extends RequiredComponent {
resolveInfo.providerInfo.name);
}
+ @Override
+ protected int getComponentFlags(@NonNull ResolveInfo resolveInfo) {
+ return resolveInfo.providerInfo.flags;
+ }
+
@Nullable
@Override
protected String getComponentPermission(@NonNull ResolveInfo resolveInfo) {
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/RequiredMetaData.java b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredMetaData.java
index f7f701fc3..07b1a294d 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/RequiredMetaData.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredMetaData.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.model;
import android.os.Bundle;
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/RequiredService.java b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredService.java
index 72d1439c9..f27aae013 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/RequiredService.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.model;
import android.content.ComponentName;
import android.content.Context;
@@ -27,7 +27,7 @@ import android.os.UserHandle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.permissioncontroller.role.utils.UserUtils;
+import com.android.role.controller.util.UserUtils;
import java.util.List;
@@ -37,8 +37,9 @@ import java.util.List;
public class RequiredService extends RequiredComponent {
public RequiredService(@NonNull IntentFilterData intentFilterData, int minTargetSdkVersion,
- @Nullable String permission, int queryFlags, @NonNull List<RequiredMetaData> metaData) {
- super(intentFilterData, minTargetSdkVersion, permission, queryFlags, metaData);
+ int flags, @Nullable String permission, int queryFlags,
+ @NonNull List<RequiredMetaData> metaData) {
+ super(intentFilterData, minTargetSdkVersion, flags, permission, queryFlags, metaData);
}
@NonNull
@@ -56,6 +57,11 @@ public class RequiredService extends RequiredComponent {
return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
}
+ @Override
+ protected int getComponentFlags(@NonNull ResolveInfo resolveInfo) {
+ return resolveInfo.serviceInfo.flags;
+ }
+
@Nullable
@Override
protected String getComponentPermission(@NonNull ResolveInfo resolveInfo) {
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/Role.java b/PermissionController/role-controller/java/com/android/role/controller/model/Role.java
index de6112e5e..aa6cba169 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/Role.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/Role.java
@@ -14,13 +14,12 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.model;
import android.app.ActivityManager;
import android.app.role.RoleManager;
import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.SharedLibraryInfo;
@@ -37,16 +36,12 @@ import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
-import androidx.preference.Preference;
import com.android.modules.utils.build.SdkLevel;
-import com.android.permissioncontroller.Constants;
-import com.android.permissioncontroller.permission.utils.CollectionUtils;
-import com.android.permissioncontroller.permission.utils.Utils;
-import com.android.permissioncontroller.role.ui.TwoTargetPreference;
-import com.android.permissioncontroller.role.utils.PackageUtils;
-import com.android.permissioncontroller.role.utils.RoleManagerCompat;
-import com.android.permissioncontroller.role.utils.UserUtils;
+import com.android.role.controller.util.CollectionUtils;
+import com.android.role.controller.util.PackageUtils;
+import com.android.role.controller.util.RoleManagerCompat;
+import com.android.role.controller.util.UserUtils;
import java.util.ArrayList;
import java.util.Collections;
@@ -124,6 +119,11 @@ public class Role {
private final int mLabelResource;
/**
+ * The maximum SDK version for this role to be available.
+ */
+ private final int mMaxSdkVersion;
+
+ /**
* The minimum SDK version for this role to be available.
*/
private final int mMinSdkVersion;
@@ -204,7 +204,7 @@ public class Role {
* The app op permissions to be granted by this role.
*/
@NonNull
- private final List<String> mAppOpPermissions;
+ private final List<Permission> mAppOpPermissions;
/**
* The app ops to be set to allowed by this role.
@@ -218,16 +218,21 @@ public class Role {
@NonNull
private final List<PreferredActivity> mPreferredActivities;
+ @Nullable
+ private final String mUiBehaviorName;
+
public Role(@NonNull String name, boolean allowBypassingQualification,
@Nullable RoleBehavior behavior, @Nullable String defaultHoldersResourceName,
@StringRes int descriptionResource, boolean exclusive, boolean fallBackToDefaultHolder,
- @StringRes int labelResource, 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,
- @NonNull List<Permission> permissions, @NonNull List<String> appOpPermissions,
- @NonNull List<AppOp> appOps, @NonNull List<PreferredActivity> preferredActivities) {
+ @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,
+ @NonNull List<Permission> permissions, @NonNull List<Permission> appOpPermissions,
+ @NonNull List<AppOp> appOps, @NonNull List<PreferredActivity> preferredActivities,
+ @Nullable String uiBehaviorName) {
mName = name;
mAllowBypassingQualification = allowBypassingQualification;
mBehavior = behavior;
@@ -236,6 +241,7 @@ public class Role {
mExclusive = exclusive;
mFallBackToDefaultHolder = fallBackToDefaultHolder;
mLabelResource = labelResource;
+ mMaxSdkVersion = maxSdkVersion;
mMinSdkVersion = minSdkVersion;
mOverrideUserWhenGranting = overrideUserWhenGranting;
mRequestDescriptionResource = requestDescriptionResource;
@@ -252,6 +258,7 @@ public class Role {
mAppOpPermissions = appOpPermissions;
mAppOps = appOps;
mPreferredActivities = preferredActivities;
+ mUiBehaviorName = uiBehaviorName;
}
@NonNull
@@ -331,7 +338,7 @@ public class Role {
}
@NonNull
- public List<String> getAppOpPermissions() {
+ public List<Permission> getAppOpPermissions() {
return mAppOpPermissions;
}
@@ -345,6 +352,11 @@ public class Role {
return mPreferredActivities;
}
+ @Nullable
+ public String getUiBehaviorName() {
+ return mUiBehaviorName;
+ }
+
/**
* Callback when this role is added to the system for the first time.
*
@@ -380,11 +392,12 @@ public class Role {
* @return whether this role is available based on SDK version
*/
boolean isAvailableBySdkVersion() {
- // Workaround to match the value 33+ for T+ in roles.xml before SDK finalization.
- if (mMinSdkVersion >= 33) {
- return SdkLevel.isAtLeastT();
+ // Workaround to match the value 34+ for U+ in roles.xml before SDK finalization.
+ if (mMinSdkVersion >= 34) {
+ return SdkLevel.isAtLeastU();
} else {
- return Build.VERSION.SDK_INT >= mMinSdkVersion;
+ return Build.VERSION.SDK_INT >= mMinSdkVersion
+ && Build.VERSION.SDK_INT <= mMaxSdkVersion;
}
}
@@ -487,7 +500,8 @@ public class Role {
return null;
}
} else {
- ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(packageName, context);
+ ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName,
+ Process.myUserHandle(), context);
if (applicationInfo == null) {
Log.w(LOG_TAG, "Cannot get ApplicationInfo for default holder: " + packageName);
return null;
@@ -513,7 +527,7 @@ public class Role {
*/
@Nullable
public String getFallbackHolder(@NonNull Context context) {
- if (isNoneHolderSelected(context)) {
+ if (!RoleManagerCompat.isRoleFallbackEnabledAsUser(this, Process.myUserHandle(), context)) {
return null;
}
if (mFallBackToDefaultHolder) {
@@ -526,110 +540,6 @@ public class Role {
}
/**
- * Check whether this role should be visible to user.
- *
- * @param user the user to check for
- * @param context the {@code Context} to retrieve system services
- *
- * @return whether this role should be visible to user
- */
- public boolean isVisibleAsUser(@NonNull UserHandle user, @NonNull Context context) {
- return mVisible && (mBehavior == null || mBehavior.isVisibleAsUser(this, user, context));
- }
-
- /**
- * Check whether this role should be visible to user, for current user.
- *
- * @param context the {@code Context} to retrieve system services
- *
- * @return whether this role should be visible to user.
- */
- public boolean isVisible(@NonNull Context context) {
- return isVisibleAsUser(Process.myUserHandle(), context);
- }
-
- /**
- * Get the {@link Intent} to manage this role, or {@code null} to use the default UI.
- *
- * @param user the user to manage this role for
- * @param context the {@code Context} to retrieve system services
- *
- * @return the {@link Intent} to manage this role, or {@code null} to use the default UI.
- */
- @Nullable
- public Intent getManageIntentAsUser(@NonNull UserHandle user, @NonNull Context context) {
- if (mBehavior != null) {
- return mBehavior.getManageIntentAsUser(this, user, context);
- }
- return null;
- }
-
- /**
- * Prepare a {@link Preference} for this role.
- *
- * @param preference the {@link Preference} for this role
- * @param user the user for this role
- * @param context the {@code Context} to retrieve system services
- */
- public void preparePreferenceAsUser(@NonNull TwoTargetPreference preference,
- @NonNull UserHandle user, @NonNull Context context) {
- if (mBehavior != null) {
- mBehavior.preparePreferenceAsUser(this, preference, 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) {
- if (mBehavior != null) {
- return mBehavior.isApplicationVisibleAsUser(this, applicationInfo, user, context);
- }
- return true;
- }
-
- /**
- * Prepare a {@link Preference} for an application.
- *
- * @param preference the {@link Preference} for the application
- * @param applicationInfo the {@link ApplicationInfo} for the application
- * @param user the user for the application
- * @param context the {@code Context} to retrieve system services
- */
- public void prepareApplicationPreferenceAsUser(@NonNull Preference preference,
- @NonNull ApplicationInfo applicationInfo, @NonNull UserHandle user,
- @NonNull Context context) {
- if (mBehavior != null) {
- mBehavior.prepareApplicationPreferenceAsUser(this, preference, applicationInfo, user,
- context);
- }
- }
-
- /**
- * Get the confirmation message for adding an application as a holder of this role.
- *
- * @param packageName the package name of the application to get confirmation message for
- * @param context the {@code Context} to retrieve system services
- *
- * @return the confirmation message, or {@code null} if no confirmation is needed
- */
- @Nullable
- public CharSequence getConfirmationMessage(@NonNull String packageName,
- @NonNull Context context) {
- if (mBehavior != null) {
- return mBehavior.getConfirmationMessage(this, packageName, context);
- }
- return null;
- }
-
- /**
* Check whether this role is allowed to bypass qualification, if enabled globally.
*
* @param context the {@code Context} to retrieve system services
@@ -663,7 +573,8 @@ public class Role {
return true;
}
- ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(packageName, context);
+ ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName,
+ Process.myUserHandle(), context);
if (applicationInfo == null) {
Log.w(LOG_TAG, "Cannot get ApplicationInfo for package: " + packageName);
return false;
@@ -876,9 +787,10 @@ public class Role {
SdkLevel.isAtLeastS() ? !mSystemOnly : true, overrideUser, true, false, false,
context);
- int appOpPermissionsSize = mAppOpPermissions.size();
+ List<String> appOpPermissionsToGrant = Permissions.filterBySdkVersion(mAppOpPermissions);
+ int appOpPermissionsSize = appOpPermissionsToGrant.size();
for (int i = 0; i < appOpPermissionsSize; i++) {
- String appOpPermission = mAppOpPermissions.get(i);
+ String appOpPermission = appOpPermissionsToGrant.get(i);
AppOpPermissions.grant(packageName, appOpPermission, overrideUser, context);
}
@@ -930,11 +842,12 @@ public class Role {
boolean permissionOrAppOpChanged = Permissions.revoke(packageName, permissionsToRevoke,
true, false, overrideSystemFixedPermissions, context);
- List<String> appOpPermissionsToRevoke = new ArrayList<>(mAppOpPermissions);
+ List<String> appOpPermissionsToRevoke = Permissions.filterBySdkVersion(mAppOpPermissions);
for (int i = 0; i < otherRoleNamesSize; i++) {
String roleName = otherRoleNames.get(i);
Role role = roles.get(roleName);
- appOpPermissionsToRevoke.removeAll(role.mAppOpPermissions);
+ appOpPermissionsToRevoke.removeAll(
+ Permissions.filterBySdkVersion(role.mAppOpPermissions));
}
int appOpPermissionsSize = appOpPermissionsToRevoke.size();
for (int i = 0; i < appOpPermissionsSize; i++) {
@@ -974,7 +887,8 @@ public class Role {
+ Thread.currentThread().getStackTrace()[3].getMethodName()
+ "(" + mName + ")");
}
- ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(packageName, context);
+ ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName,
+ Process.myUserHandle(), context);
if (applicationInfo == null) {
Log.w(LOG_TAG, "Cannot get ApplicationInfo for package: " + packageName);
return;
@@ -984,18 +898,6 @@ public class Role {
}
/**
- * Check whether the "none" role holder is selected.
- *
- * @param context the {@code Context} to retrieve system services
- *
- * @return whether the "none" role holder is selected
- */
- private boolean isNoneHolderSelected(@NonNull Context context) {
- return Utils.getDeviceProtectedSharedPreferences(context).getBoolean(
- Constants.IS_NONE_ROLE_HOLDER_SELECTED_KEY + mName, false);
- }
-
- /**
* Callback when a role holder (other than "none") was added.
*
* @param packageName the package name of the role holder
@@ -1004,9 +906,7 @@ public class Role {
*/
public void onHolderAddedAsUser(@NonNull String packageName, @NonNull UserHandle user,
@NonNull Context context) {
- Utils.getDeviceProtectedSharedPreferences(UserUtils.getUserContext(context, user)).edit()
- .remove(Constants.IS_NONE_ROLE_HOLDER_SELECTED_KEY + mName)
- .apply();
+ RoleManagerCompat.setRoleFallbackEnabledAsUser(this, true, user, context);
}
/**
@@ -1044,9 +944,7 @@ public class Role {
* @param context the {@code Context} to retrieve system services
*/
public void onNoneHolderSelectedAsUser(@NonNull UserHandle user, @NonNull Context context) {
- Utils.getDeviceProtectedSharedPreferences(UserUtils.getUserContext(context, user)).edit()
- .putBoolean(Constants.IS_NONE_ROLE_HOLDER_SELECTED_KEY + mName, true)
- .apply();
+ RoleManagerCompat.setRoleFallbackEnabledAsUser(this, false, user, context);
}
@Override
@@ -1060,6 +958,7 @@ public class Role {
+ ", mExclusive=" + mExclusive
+ ", mFallBackToDefaultHolder=" + mFallBackToDefaultHolder
+ ", mLabelResource=" + mLabelResource
+ + ", mMaxSdkVersion=" + mMaxSdkVersion
+ ", mMinSdkVersion=" + mMinSdkVersion
+ ", mOverrideUserWhenGranting=" + mOverrideUserWhenGranting
+ ", mRequestDescriptionResource=" + mRequestDescriptionResource
@@ -1076,6 +975,7 @@ public class Role {
+ ", mAppOpPermissions=" + mAppOpPermissions
+ ", mAppOps=" + mAppOps
+ ", mPreferredActivities=" + mPreferredActivities
+ + ", mUiBehaviorName=" + mUiBehaviorName
+ '}';
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/RoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/model/RoleBehavior.java
index e5402c2ed..f0c4fc018 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/RoleBehavior.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/RoleBehavior.java
@@ -14,18 +14,13 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.model;
import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
import android.os.UserHandle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.preference.Preference;
-
-import com.android.permissioncontroller.role.ui.TwoTargetPreference;
import java.util.Collections;
import java.util.List;
@@ -65,56 +60,6 @@ public interface RoleBehavior {
}
/**
- * @see Role#isVisibleAsUser(UserHandle, Context)
- */
- default boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user,
- @NonNull Context context) {
- return true;
- }
-
- /**
- * @see Role#getManageIntentAsUser(UserHandle, Context)
- */
- @Nullable
- default Intent getManageIntentAsUser(@NonNull Role role, @NonNull UserHandle user,
- @NonNull Context context) {
- return null;
- }
-
- /**
- * @see Role#preparePreferenceAsUser(TwoTargetPreference, UserHandle, Context)
- */
- default void preparePreferenceAsUser(@NonNull Role role,
- @NonNull TwoTargetPreference preference, @NonNull UserHandle user,
- @NonNull Context context) {}
-
- /**
- * @see Role#isApplicationVisibleAsUser(ApplicationInfo, UserHandle, Context)
- */
- default boolean isApplicationVisibleAsUser(@NonNull Role role,
- @NonNull ApplicationInfo applicationInfo, @NonNull UserHandle user,
- @NonNull Context context) {
- return true;
- }
-
- /**
- * @see Role#prepareApplicationPreferenceAsUser(Preference, ApplicationInfo, UserHandle,
- * Context)
- */
- default void prepareApplicationPreferenceAsUser(@NonNull Role role,
- @NonNull Preference preference, @NonNull ApplicationInfo applicationInfo,
- @NonNull UserHandle user, @NonNull Context context) {}
-
- /**
- * @see Role#getConfirmationMessage(String, Context)
- */
- @Nullable
- default CharSequence getConfirmationMessage(@NonNull Role role, @NonNull String packageName,
- @NonNull Context context) {
- return null;
- }
-
- /**
* @see Role#shouldAllowBypassingQualification(Context)
*/
@Nullable
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/RoleParser.java b/PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java
index 3d5e2e89c..23299419e 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/RoleParser.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.model;
+package com.android.role.controller.model;
import android.app.AppOpsManager;
import android.content.Context;
@@ -31,7 +31,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import com.android.permissioncontroller.R;
+import com.android.role.controller.behavior.BrowserRoleBehavior;
import org.xmlpull.v1.XmlPullParserException;
@@ -41,6 +41,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.function.Function;
/**
* Parser for {@link Role} definitions.
@@ -48,6 +49,11 @@ import java.util.Objects;
@VisibleForTesting
public class RoleParser {
+ /**
+ * Function to retrieve the roles.xml resource from a context
+ */
+ public static volatile Function<Context, XmlResourceParser> sGetRolesXml;
+
private static final String LOG_TAG = RoleParser.class.getSimpleName();
private static final String TAG_ROLES = "roles";
@@ -80,6 +86,7 @@ public class RoleParser {
private static final String ATTRIBUTE_EXCLUSIVE = "exclusive";
private static final String ATTRIBUTE_FALL_BACK_TO_DEFAULT_HOLDER = "fallBackToDefaultHolder";
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_OVERRIDE_USER_WHEN_GRANTING = "overrideUserWhenGranting";
private static final String ATTRIBUTE_QUERY_FLAGS = "queryFlags";
@@ -91,7 +98,9 @@ public class RoleParser {
private static final String ATTRIBUTE_SHOW_NONE = "showNone";
private static final String ATTRIBUTE_STATIC = "static";
private static final String ATTRIBUTE_SYSTEM_ONLY = "systemOnly";
+ private static final String ATTRIBUTE_UI_BEHAVIOR = "uiBehavior";
private static final String ATTRIBUTE_VISIBLE = "visible";
+ private static final String ATTRIBUTE_FLAGS = "flags";
private static final String ATTRIBUTE_MIN_TARGET_SDK_VERSION = "minTargetSdkVersion";
private static final String ATTRIBUTE_PERMISSION = "permission";
private static final String ATTRIBUTE_PROHIBITED = "prohibited";
@@ -101,6 +110,9 @@ public class RoleParser {
private static final String ATTRIBUTE_MAX_TARGET_SDK_VERSION = "maxTargetSdkVersion";
private static final String ATTRIBUTE_MODE = "mode";
+ private static final String BEHAVIOR_PACKAGE_NAME = BrowserRoleBehavior.class.getPackage()
+ .getName();
+
private static final String MODE_NAME_ALLOWED = "allowed";
private static final String MODE_NAME_IGNORED = "ignored";
private static final String MODE_NAME_ERRORED = "errored";
@@ -137,7 +149,7 @@ public class RoleParser {
*/
@NonNull
public ArrayMap<String, Role> parse() {
- try (XmlResourceParser parser = mContext.getResources().getXml(R.xml.roles)) {
+ try (XmlResourceParser parser = sGetRolesXml.apply(mContext)) {
Pair<ArrayMap<String, PermissionSet>, ArrayMap<String, Role>> xml = parseXml(parser);
if (xml == null) {
return new ArrayMap<>();
@@ -253,7 +265,7 @@ public class RoleParser {
}
if (parser.getName().equals(TAG_PERMISSION)) {
- Permission permission = parsePermission(parser);
+ Permission permission = parsePermission(parser, TAG_PERMISSION);
if (permission == null) {
continue;
}
@@ -269,9 +281,9 @@ public class RoleParser {
}
@Nullable
- private Permission parsePermission(@NonNull XmlResourceParser parser) throws IOException,
- XmlPullParserException {
- String name = requireAttributeValue(parser, ATTRIBUTE_NAME, TAG_PERMISSION);
+ private Permission parsePermission(@NonNull XmlResourceParser parser,
+ @NonNull String tagName) throws IOException, XmlPullParserException {
+ String name = requireAttributeValue(parser, ATTRIBUTE_NAME, tagName);
if (name == null) {
skipCurrentTag(parser);
return null;
@@ -297,8 +309,7 @@ public class RoleParser {
String behaviorClassSimpleName = getAttributeValue(parser, ATTRIBUTE_BEHAVIOR);
RoleBehavior behavior;
if (behaviorClassSimpleName != null) {
- String behaviorClassName = RoleParser.class.getPackage().getName() + '.'
- + behaviorClassSimpleName;
+ String behaviorClassName = BEHAVIOR_PACKAGE_NAME + '.' + behaviorClassSimpleName;
try {
behavior = (RoleBehavior) Class.forName(behaviorClassName).newInstance();
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
@@ -350,8 +361,17 @@ public class RoleParser {
boolean fallBackToDefaultHolder = getAttributeBooleanValue(parser,
ATTRIBUTE_FALL_BACK_TO_DEFAULT_HOLDER, false);
+ int maxSdkVersion = getAttributeIntValue(parser, ATTRIBUTE_MAX_SDK_VERSION,
+ Build.VERSION_CODES.CUR_DEVELOPMENT);
int minSdkVersion = getAttributeIntValue(parser, ATTRIBUTE_MIN_SDK_VERSION,
Build.VERSION_CODES.BASE);
+ if (minSdkVersion > maxSdkVersion) {
+ throwOrLogMessage("minSdkVersion " + minSdkVersion
+ + " cannot be greater than maxSdkVersion " + maxSdkVersion + " for role: "
+ + name);
+ skipCurrentTag(parser);
+ return null;
+ }
boolean overrideUserWhenGranting = getAttributeBooleanValue(parser,
ATTRIBUTE_OVERRIDE_USER_WHEN_GRANTING, false);
@@ -398,9 +418,11 @@ public class RoleParser {
boolean systemOnly = getAttributeBooleanValue(parser, ATTRIBUTE_SYSTEM_ONLY, false);
+ String uiBehaviorName = getAttributeValue(parser, ATTRIBUTE_UI_BEHAVIOR);
+
List<RequiredComponent> requiredComponents = null;
List<Permission> permissions = null;
- List<String> appOpPermissions = null;
+ List<Permission> appOpPermissions = null;
List<AppOp> appOps = null;
List<PreferredActivity> preferredActivities = null;
@@ -478,10 +500,10 @@ public class RoleParser {
}
return new Role(name, allowBypassingQualification, behavior, defaultHoldersResourceName,
descriptionResource, exclusive, fallBackToDefaultHolder, labelResource,
- minSdkVersion, overrideUserWhenGranting, requestDescriptionResource,
+ maxSdkVersion, minSdkVersion, overrideUserWhenGranting, requestDescriptionResource,
requestTitleResource, requestable, searchKeywordsResource, shortLabelResource,
showNone, statik, systemOnly, visible, requiredComponents, permissions,
- appOpPermissions, appOps, preferredActivities);
+ appOpPermissions, appOps, preferredActivities, uiBehaviorName);
}
@NonNull
@@ -528,6 +550,7 @@ public class RoleParser {
@NonNull String name) throws IOException, XmlPullParserException {
int minTargetSdkVersion = getAttributeIntValue(parser, ATTRIBUTE_MIN_TARGET_SDK_VERSION,
Build.VERSION_CODES.BASE);
+ int flags = getAttributeIntValue(parser, ATTRIBUTE_FLAGS, 0);
String permission = getAttributeValue(parser, ATTRIBUTE_PERMISSION);
int queryFlags = getAttributeIntValue(parser, ATTRIBUTE_QUERY_FLAGS, 0);
IntentFilterData intentFilterData = null;
@@ -592,16 +615,16 @@ public class RoleParser {
}
switch (name) {
case TAG_ACTIVITY:
- return new RequiredActivity(intentFilterData, minTargetSdkVersion, permission,
- queryFlags, metaData);
+ return new RequiredActivity(intentFilterData, minTargetSdkVersion, flags,
+ permission, queryFlags, metaData);
case TAG_PROVIDER:
- return new RequiredContentProvider(intentFilterData, minTargetSdkVersion,
+ return new RequiredContentProvider(intentFilterData, minTargetSdkVersion, flags,
permission, queryFlags, metaData);
case TAG_RECEIVER:
- return new RequiredBroadcastReceiver(intentFilterData, minTargetSdkVersion,
+ return new RequiredBroadcastReceiver(intentFilterData, minTargetSdkVersion, flags,
permission, queryFlags, metaData);
case TAG_SERVICE:
- return new RequiredService(intentFilterData, minTargetSdkVersion, permission,
+ return new RequiredService(intentFilterData, minTargetSdkVersion, flags, permission,
queryFlags, metaData);
default:
throwOrLogMessage("Unknown tag <" + name + ">");
@@ -725,7 +748,7 @@ public class RoleParser {
break;
}
case TAG_PERMISSION: {
- Permission permission = parsePermission(parser);
+ Permission permission = parsePermission(parser, TAG_PERMISSION);
if (permission == null) {
continue;
}
@@ -743,9 +766,9 @@ public class RoleParser {
}
@NonNull
- private List<String> parseAppOpPermissions(@NonNull XmlResourceParser parser)
+ private List<Permission> parseAppOpPermissions(@NonNull XmlResourceParser parser)
throws IOException, XmlPullParserException {
- List<String> appOpPermissions = new ArrayList<>();
+ List<Permission> appOpPermissions = new ArrayList<>();
int type;
int depth;
@@ -758,8 +781,7 @@ public class RoleParser {
}
if (parser.getName().equals(TAG_APP_OP_PERMISSION)) {
- String appOpPermission = requireAttributeValue(parser, ATTRIBUTE_NAME,
- TAG_APP_OP_PERMISSION);
+ Permission appOpPermission = parsePermission(parser, TAG_APP_OP_PERMISSION);
if (appOpPermission == null) {
continue;
}
@@ -1064,12 +1086,10 @@ public class RoleParser {
validateAppOp(appOp);
}
- List<String> appOpPermissions = role.getAppOpPermissions();
+ List<Permission> appOpPermissions = role.getAppOpPermissions();
int appOpPermissionsSize = appOpPermissions.size();
for (int i = 0; i < appOpPermissionsSize; i++) {
- String appOpPermission = appOpPermissions.get(i);
-
- validateAppOpPermission(appOpPermission);
+ validateAppOpPermission(appOpPermissions.get(i));
}
List<PreferredActivity> preferredActivities = role.getPreferredActivities();
@@ -1125,6 +1145,13 @@ public class RoleParser {
}
}
+ private void validateAppOpPermission(@NonNull Permission appOpPermission) {
+ if (!appOpPermission.isAvailable()) {
+ return;
+ }
+ validateAppOpPermission(appOpPermission.getName());
+ }
+
private void validateAppOpPermission(@NonNull String appOpPermission) {
PackageManager packageManager = mContext.getPackageManager();
PermissionInfo permissionInfo;
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/Roles.java b/PermissionController/role-controller/java/com/android/role/controller/model/Roles.java
index 6312b170e..5914ffbae 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/Roles.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/model/Roles.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.util.ArrayMap;
diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/ArrayUtils.java b/PermissionController/role-controller/java/com/android/role/controller/util/ArrayUtils.java
new file mode 100644
index 000000000..5ef531e9e
--- /dev/null
+++ b/PermissionController/role-controller/java/com/android/role/controller/util/ArrayUtils.java
@@ -0,0 +1,61 @@
+/*
+ * 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 com.android.role.controller.util;
+
+import androidx.annotation.Nullable;
+
+import java.util.Objects;
+
+/**
+ * Array utilities.
+ */
+public final class ArrayUtils {
+ private ArrayUtils() { /* cannot be instantiated */ }
+
+ /**
+ * Checks if an array is null or has no elements.
+ *
+ * @param array the array to check for
+ *
+ * @return whether the array is null or has no elements.
+ */
+ public static <T> boolean isEmpty(@Nullable T[] array) {
+ return array == null || array.length == 0;
+ }
+
+ /**
+ * Checks that value is present as at least one of the elements of the array.
+ * @param array the array to check in
+ * @param value the value to check for
+ * @return true if the value is present in the array
+ */
+ public static <T> boolean contains(T[] array, T value) {
+ return indexOf(array, value) != -1;
+ }
+
+ /**
+ * Return first index of {@code value} in {@code array}, or {@code -1} if
+ * not found.
+ */
+ public static <T> int indexOf(T[] array, T value) {
+ if (array == null) return -1;
+ for (int i = 0; i < array.length; i++) {
+ if (Objects.equals(array[i], value)) return i;
+ }
+ return -1;
+ }
+}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/CollectionUtils.java b/PermissionController/role-controller/java/com/android/role/controller/util/CollectionUtils.java
new file mode 100644
index 000000000..35d8e26ff
--- /dev/null
+++ b/PermissionController/role-controller/java/com/android/role/controller/util/CollectionUtils.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.role.controller.util;
+
+import android.util.ArraySet;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Utility methods for dealing with {@link java.util.Collection}s.
+ */
+public final class CollectionUtils {
+
+ private CollectionUtils() {}
+
+ /**
+ * Return the first element of a list, or {@code null} if the list is {@code null} or empty.
+ *
+ * @param <T> the class of the elements of the list
+ * @param list the list to get the first element
+ *
+ * @return the first element of the list, or {@code null} if the list is {@code null} or empty
+ */
+ @Nullable
+ public static <T> T firstOrNull(@Nullable List<T> list) {
+ if (list == null || list.isEmpty()) {
+ return null;
+ }
+ return list.get(0);
+ }
+
+ /**
+ * Remove all values in the array set that do <b>not</b> exist in the given collection.
+ *
+ * @param <T> the class of the elements to retain and of the {@code ArraySet}
+ * @param arraySet the {@code ArraySet} whose elements are to be removed or retained
+ * @param valuesToRetain the values to be used to determine which elements to retain
+ *
+ * @return {@code true} if any values were removed from the array set, {@code false} otherwise.
+ *
+ * @see ArraySet#retainAll(java.util.Collection)
+ */
+ @SafeVarargs
+ public static <T> boolean retainAll(ArraySet<T> arraySet, T... valuesToRetain) {
+ boolean removed = false;
+ List<T> valuesToRetainList = Arrays.asList(valuesToRetain);
+ for (int i = arraySet.size() - 1; i >= 0; i--) {
+ if (!valuesToRetainList.contains(arraySet.valueAt(i))) {
+ arraySet.removeAt(i);
+ removed = true;
+ }
+ }
+ return removed;
+ }
+
+ /**
+ * Return a singleton list containing the element, or an empty list if the element is
+ * {@code null}.
+ *
+ * @param <T> the class of the element
+ * @param element the element to be put into the list
+ *
+ * @return a singleton list containing the element, or an empty list if the element is
+ * {@code null}.
+ */
+ @NonNull
+ public static <T> List<T> singletonOrEmpty(@Nullable T element) {
+ return element != null ? Collections.singletonList(element) : Collections.emptyList();
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/utils/NotificationUtils.java b/PermissionController/role-controller/java/com/android/role/controller/util/NotificationUtils.java
index 08607594c..3b11d7d92 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/utils/NotificationUtils.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/util/NotificationUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.role.utils;
+package com.android.role.controller.util;
import android.app.NotificationManager;
import android.content.ComponentName;
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
new file mode 100644
index 000000000..4b127ad10
--- /dev/null
+++ b/PermissionController/role-controller/java/com/android/role/controller/util/PackageUtils.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.role.controller.util;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * Utility methods about application packages.
+ */
+public final class PackageUtils {
+
+ private 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
+ *
+ * @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();
+ try {
+ return packageManager.getPackageInfo(packageName, PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | extraFlags);
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Retrieve if a package is a system package.
+ *
+ * @param packageName the name 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;
+ }
+
+ /**
+ * Retrieve the {@link ApplicationInfo} of 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 the {@link ApplicationInfo} of the application, or {@code null} if not found
+ */
+ @Nullable
+ public static ApplicationInfo getApplicationInfoAsUser(@NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ PackageManager userPackageManager = userContext.getPackageManager();
+ try {
+ return userPackageManager.getApplicationInfo(packageName,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
+ }
+ }
+}
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
new file mode 100644
index 000000000..8a6fd579c
--- /dev/null
+++ b/PermissionController/role-controller/java/com/android/role/controller/util/RoleManagerCompat.java
@@ -0,0 +1,102 @@
+/*
+ * 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.util;
+
+import android.app.role.RoleManager;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.UserHandle;
+
+import androidx.annotation.NonNull;
+
+import com.android.modules.utils.build.SdkLevel;
+import com.android.role.controller.model.Role;
+
+/**
+ * Helper for accessing features in {@link RoleManager}.
+ */
+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() {}
+
+ /**
+ * @see RoleManager#isBypassingRoleQualification()
+ */
+ public static boolean isBypassingRoleQualification(@NonNull RoleManager roleManager) {
+ if (SdkLevel.isAtLeastS()) {
+ return roleManager.isBypassingRoleQualification();
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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();
+ } else {
+ getDeviceProtectedSharedPreferences(userContext).edit()
+ .putBoolean(IS_NONE_ROLE_HOLDER_SELECTED_KEY + role.getName(), true)
+ .apply();
+ }
+ }
+}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/UserUtils.java b/PermissionController/role-controller/java/com/android/role/controller/util/UserUtils.java
new file mode 100644
index 000000000..ac3b681a8
--- /dev/null
+++ b/PermissionController/role-controller/java/com/android/role/controller/util/UserUtils.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.role.controller.util;
+
+import android.content.Context;
+import android.os.Build;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import androidx.annotation.NonNull;
+
+/** Utility class to deal with Android users. */
+public final class UserUtils {
+
+ private UserUtils() {}
+
+ /**
+ * Check whether a user is a profile.
+ *
+ * @param user the user to check
+ * @param context the {@code Context} to retrieve system services
+ * @return whether the user is a profile
+ */
+ public static boolean isProfile(@NonNull UserHandle user, @NonNull Context context) {
+ return isManagedProfile(user, context) || isCloneProfile(user, context);
+ }
+
+ /**
+ * Check whether a user is a managed profile.
+ *
+ * @param user the user to check
+ * @param context the {@code Context} to retrieve system services
+ * @return whether the user is a managed profile
+ */
+ public static boolean isManagedProfile(@NonNull UserHandle user, @NonNull Context context) {
+ Context userContext = getUserContext(context, user);
+ UserManager userUserManager = userContext.getSystemService(UserManager.class);
+ return userUserManager.isManagedProfile(user.getIdentifier());
+ }
+
+ /**
+ * Check whether a user is a clone profile.
+ *
+ * @param user the user to check
+ * @param context the {@code Context} to retrieve system services
+ * @return whether the user is a clone profile
+ */
+ public static boolean isCloneProfile(@NonNull UserHandle user, @NonNull Context context) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
+ return false;
+ }
+ Context userContext = getUserContext(context, user);
+ UserManager userUserManager = userContext.getSystemService(UserManager.class);
+ return userUserManager.isCloneProfile();
+ }
+
+ /**
+ * Create a context for a user.
+ *
+ * @param context The context to clone
+ * @param user The user the new context should be for
+ *
+ * @return The context for the new user
+ */
+ @NonNull
+ public static Context getUserContext(@NonNull Context context, @NonNull UserHandle user) {
+ if (Process.myUserHandle().equals(user)) {
+ return context;
+ } else {
+ return context.createContextAsUser(user, 0);
+ }
+ }
+}
diff --git a/PermissionController/role-controller/lint-baseline.xml b/PermissionController/role-controller/lint-baseline.xml
new file mode 100644
index 000000000..e7c119f3b
--- /dev/null
+++ b/PermissionController/role-controller/lint-baseline.xml
@@ -0,0 +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">
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.app.NotificationManager#setNotificationListenerAccessGranted`"
+ errorLine1=" notificationManager.setNotificationListenerAccessGranted("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/PermissionController/role-controller/java/com/android/role/controller/util/NotificationUtils.java"
+ line="74"
+ column="33"/>
+ </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 505c84933..58b62dc54 100644
--- a/PermissionController/src/com/android/permissioncontroller/Constants.java
+++ b/PermissionController/src/com/android/permissioncontroller/Constants.java
@@ -21,7 +21,8 @@ import android.os.Build;
import androidx.annotation.RequiresApi;
import com.android.permissioncontroller.hibernation.HibernationJobService;
-import com.android.permissioncontroller.permission.service.v33.PermissionEventCleanupJobService;
+import com.android.permissioncontroller.permission.service.PermissionEventCleanupJobService;
+import com.android.permissioncontroller.permission.service.v34.SafetyLabelChangesJobService;
/**
* App-global constants
@@ -65,20 +66,37 @@ public class Constants {
public static final int NOTIFICATION_LISTENER_CHECK_JOB_ID = 5;
/**
- * Name of file to containing the packages we already showed a notification for.
- *
- * @see com.android.permissioncontroller.permission.service.LocationAccessCheck
+ * ID for the periodic job in
+ * {@link com.android.permissioncontroller.privacysources.AccessibilitySourceService}.
*/
- public static final String LOCATION_ACCESS_CHECK_ALREADY_NOTIFIED_FILE =
- "packages_already_notified_location_access";
+ public static final int PERIODIC_ACCESSIBILITY_CHECK_JOB_ID = 6;
+
+ /**
+ * ID for Safety Centers periodic background refresh job, scheduled after boot and after Safety
+ * Center is enabled, in {@link
+ * com.android.permissioncontroller.safetycenter.service.SafetyCenterBackgroundRefreshJobService
+ * }.
+ */
+ public static final int SAFETY_CENTER_BACKGROUND_REFRESH_JOB_ID = 7;
+
+
+ /**
+ * ID for the detect updates job in {@link SafetyLabelChangesJobService}.
+ */
+ public static final int SAFETY_LABEL_CHANGES_DETECT_UPDATES_JOB_ID = 8;
+
+ /**
+ * ID for the periodic notification job in {@link SafetyLabelChangesJobService}.
+ */
+ public static final int SAFETY_LABEL_CHANGES_PERIODIC_NOTIFICATION_JOB_ID = 9;
/**
* Name of file to containing the packages we already showed a notification for.
*
- * @see com.android.permissioncontroller.privacysources.NotificationListenerCheck
+ * @see com.android.permissioncontroller.permission.service.LocationAccessCheck
*/
- public static final String NOTIFICATION_LISTENER_CHECK_ALREADY_NOTIFIED_FILE =
- "packages_already_notified_notification_listener";
+ public static final String LOCATION_ACCESS_CHECK_ALREADY_NOTIFIED_FILE =
+ "packages_already_notified_location_access";
/**
* ID for notification shown by
@@ -105,6 +123,35 @@ public class Constants {
public static final int NOTIFICATION_LISTENER_CHECK_NOTIFICATION_ID = 3;
/**
+ * ID for notification shown by
+ * {@link com.android.permissioncontroller.privacysources.AccessibilitySourceService}.
+ */
+ public static final int ACCESSIBILITY_CHECK_NOTIFICATION_ID = 4;
+
+ /**
+ * ID for notification shown by
+ * {@link SafetyLabelChangesJobService}.
+ */
+ public static final int SAFETY_LABEL_CHANGES_NOTIFICATION_ID = 5;
+
+ /**
+ * ID for notification of auto-granted permissions shown by
+ * {@link com.android.permissioncontroller.permission.ui.AutoGrantPermissionsNotifier}.
+ */
+ public static final int PERMISSION_GRANTED_BY_ADMIN_NOTIFICATION_ID = 6;
+
+ /**
+ * Summary notification ID for the group of admin auto-granted permission notifications
+ */
+ public static final int ADMIN_AUTO_GRANTED_PERMISSIONS_NOTIFICATION_SUMMARY_ID = 7;
+
+ /**
+ * Group ID for all admin auto-granted permission notifications
+ */
+ public static final String ADMIN_AUTO_GRANTED_PERMISSIONS_NOTIFICATION_GROUP_ID =
+ "auto granted permission group id";
+
+ /**
* String action for navigating to the auto revoke screen.
*/
public static final String ACTION_MANAGE_AUTO_REVOKE = "manageAutoRevoke";
@@ -128,8 +175,9 @@ public class Constants {
* Channel of the notifications shown by
* {@link com.android.permissioncontroller.permission.service.LocationAccessCheck},
* {@link com.android.permissioncontroller.privacysources.NotificationListenerCheck},
- * {@link com.android.permissioncontroller.hibernation.HibernationPolicyKt}, and
- * {@link com.android.permissioncontroller.auto.DrivingDecisionReminderService}
+ * {@link com.android.permissioncontroller.hibernation.HibernationPolicyKt},
+ * {@link com.android.permissioncontroller.auto.DrivingDecisionReminderService}, and
+ * {@link SafetyLabelChangesJobService}
*/
public static final String PERMISSION_REMINDER_CHANNEL_ID = "permission reminders";
@@ -228,6 +276,12 @@ public class Constants {
"com.android.permissioncontroller.extra.SESSION_ID";
/**
+ * Intent extra used to pass privacy source details to safety center.
+ */
+ public static final String EXTRA_PRIVACY_SOURCE =
+ "com.android.permissioncontroller.extra.PRIVACY_SOURCE";
+
+ /**
* Invalid session id.
*/
public static final long INVALID_SESSION_ID = 0;
@@ -245,19 +299,44 @@ public class Constants {
*/
public static final String ADMIN_AUTO_GRANTED_PERMISSIONS_ALERTING_NOTIFICATION_CHANNEL_ID =
"alerting auto granted permissions";
- /**
- * ID for notification of auto-granted permissions shown by
- * {@link com.android.permissioncontroller.permission.ui.AutoGrantPermissionsNotifier}.
- */
- public static final int PERMISSION_GRANTED_BY_ADMIN_NOTIFICATION_ID = 1;
/**
* Package name of the Android platform.
*/
public static final String OS_PACKAGE_NAME = "android";
+ /**
+ * Source id for safety center source for unused apps.
+ */
+ public static final String UNUSED_APPS_SAFETY_CENTER_SOURCE_ID = "AndroidPermissionAutoRevoke";
+
+ /**
+ * Issue id for safety center issue for unused apps.
+ */
+ public static final String UNUSED_APPS_SAFETY_CENTER_ISSUE_ID = "unused_apps_issue";
+
+ /**
+ * Action id for safety center "See unused apps" action.
+ */
+ public static final String UNUSED_APPS_SAFETY_CENTER_SEE_UNUSED_APPS_ID = "see_unused_apps";
+
// TODO(b/231624295) add to API
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public static final String OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO =
"android:receive_ambient_trigger_audio";
+
+ /**
+ * Extra used by Settings to indicate an Intent should be treated as if opened directly by
+ * Settings app itself.
+ */
+ public static final String EXTRA_FROM_SETTINGS = "is_from_settings_homepage";
+
+ /**
+ * Extra used by Settings to indicate an Intent should be treated as if opened by a slice
+ * within Settings.
+ *
+ * <p>Slices are opened within settings by firing a PendingIntent, so we can use this extra to
+ * allow the same UX path to be taken as for slices.
+ */
+ public static final String EXTRA_IS_FROM_SLICE = "is_from_slice";
}
diff --git a/PermissionController/src/com/android/permissioncontroller/DeviceUtils.java b/PermissionController/src/com/android/permissioncontroller/DeviceUtils.java
index 60caf888c..ec3642d1d 100644
--- a/PermissionController/src/com/android/permissioncontroller/DeviceUtils.java
+++ b/PermissionController/src/com/android/permissioncontroller/DeviceUtils.java
@@ -18,12 +18,10 @@ package com.android.permissioncontroller;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.content.res.Configuration;
public class DeviceUtils {
public static boolean isTelevision(Context context) {
- int uiMode = context.getResources().getConfiguration().uiMode;
- return (uiMode & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION;
+ return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
}
public static boolean isWear(final Context context) {
diff --git a/PermissionController/src/com/android/permissioncontroller/PermissionController.proto b/PermissionController/src/com/android/permissioncontroller/PermissionController.proto
index 429909b71..02e51ce2d 100644
--- a/PermissionController/src/com/android/permissioncontroller/PermissionController.proto
+++ b/PermissionController/src/com/android/permissioncontroller/PermissionController.proto
@@ -17,7 +17,7 @@ syntax = "proto2";
package com.android.permissioncontroller;
option java_outer_classname = "PermissionControllerProto";
-import "packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/AutoRevokePermissions.proto";
+import "permission/service/AutoRevokePermissions.proto";
message PermissionControllerDumpProto {
optional permission.service.AutoRevokePermissionsDumpProto autoRevoke = 1;
diff --git a/PermissionController/src/com/android/permissioncontroller/PermissionControllerApplication.java b/PermissionController/src/com/android/permissioncontroller/PermissionControllerApplication.java
index d99c3e2ce..68495ce1e 100644
--- a/PermissionController/src/com/android/permissioncontroller/PermissionControllerApplication.java
+++ b/PermissionController/src/com/android/permissioncontroller/PermissionControllerApplication.java
@@ -20,11 +20,21 @@ import android.app.Application;
import android.content.ComponentName;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
+import android.os.Build;
import android.util.ArrayMap;
+import android.view.accessibility.AccessibilityManager;
-import com.android.permissioncontroller.role.model.Role;
-import com.android.permissioncontroller.role.model.Roles;
+import androidx.annotation.RequiresApi;
+
+import com.android.modules.utils.build.SdkLevel;
+import com.android.permissioncontroller.permission.utils.KotlinUtils;
+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;
public final class PermissionControllerApplication extends Application {
@@ -37,7 +47,14 @@ public final class PermissionControllerApplication extends Application {
sInstance = this;
PackageItemInfo.forceSafeLabels();
+ RoleParserInitializer.initialize();
updateSpecialAppAccessListActivityEnabledState();
+ if (SdkLevel.isAtLeastT()) {
+ addAccessibilityListener();
+ }
+ if (Utils.isHealthPermissionUiEnabled()) {
+ KotlinUtils.INSTANCE.addHealthPermissions(this);
+ }
}
/**
@@ -54,7 +71,7 @@ public final class PermissionControllerApplication extends Application {
for (int i = 0; i < rolesSize; i++) {
Role role = roles.valueAt(i);
- if (!role.isAvailable(this) || !role.isVisible(this)) {
+ if (!role.isAvailable(this) || !RoleUiBehaviorUtils.isVisible(role, this)) {
continue;
}
if (!role.isExclusive()) {
@@ -71,4 +88,13 @@ public final class PermissionControllerApplication extends Application {
packageManager.setComponentEnabledSetting(componentName, enabledState,
PackageManager.DONT_KILL_APP);
}
+
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private void addAccessibilityListener() {
+ AccessibilityManager a11yManager = Utils.getSystemServiceSafe(
+ this, AccessibilityManager.class);
+ a11yManager.addAccessibilityServicesStateChangeListener(
+ new SafetyCenterAccessibilityListener(this));
+ }
+
}
diff --git a/PermissionController/src/com/android/permissioncontroller/hibernation/HibernationPolicy.kt b/PermissionController/src/com/android/permissioncontroller/hibernation/HibernationPolicy.kt
index 64481862f..1f6b5272a 100644
--- a/PermissionController/src/com/android/permissioncontroller/hibernation/HibernationPolicy.kt
+++ b/PermissionController/src/com/android/permissioncontroller/hibernation/HibernationPolicy.kt
@@ -27,6 +27,9 @@ import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
+import android.app.PendingIntent.FLAG_IMMUTABLE
+import android.app.PendingIntent.FLAG_ONE_SHOT
+import android.app.PendingIntent.FLAG_UPDATE_CURRENT
import android.app.admin.DeviceAdminReceiver
import android.app.admin.DevicePolicyManager
import android.app.job.JobInfo
@@ -41,17 +44,26 @@ import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
+import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
+import android.content.Intent.FLAG_RECEIVER_FOREGROUND
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.content.pm.PackageManager.PERMISSION_GRANTED
+import android.os.Build
import android.os.Bundle
import android.os.Process
+import android.os.SystemClock
import android.os.UserHandle
import android.os.UserManager
import android.printservice.PrintService
import android.provider.DeviceConfig
import android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION
import android.provider.Settings
+import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetyEvent
+import android.safetycenter.SafetySourceData
+import android.safetycenter.SafetySourceIssue
+import android.safetycenter.SafetySourceIssue.Action
import android.service.autofill.AutofillService
import android.service.dreams.DreamService
import android.service.notification.NotificationListenerService
@@ -61,7 +73,9 @@ import android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
import android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS
import android.util.Log
import android.view.inputmethod.InputMethod
+import androidx.annotation.ChecksSdkIntAtLeast
import androidx.annotation.MainThread
+import androidx.annotation.RequiresApi
import androidx.lifecycle.MutableLiveData
import androidx.preference.PreferenceManager
import com.android.modules.utils.build.SdkLevel
@@ -85,16 +99,17 @@ 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.KotlinUtils
import com.android.permissioncontroller.permission.utils.StringUtils
import com.android.permissioncontroller.permission.utils.Utils
import com.android.permissioncontroller.permission.utils.forEachInParallel
+import java.util.Date
+import java.util.Random
+import java.util.concurrent.TimeUnit
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
-import java.util.Date
-import java.util.Random
-import java.util.concurrent.TimeUnit
private const val LOG_TAG = "HibernationPolicy"
const val DEBUG_OVERRIDE_THRESHOLDS = false
@@ -119,7 +134,18 @@ private fun getCheckFrequencyMs() = DeviceConfig.getLong(
Utils.PROPERTY_HIBERNATION_CHECK_FREQUENCY_MILLIS,
DEFAULT_CHECK_FREQUENCY_MS)
-private val PREF_KEY_FIRST_BOOT_TIME = "first_boot_time"
+// 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
+const val PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING = "first_boot_time"
+const val PREF_KEY_BOOT_TIME_SNAPSHOT = "ah_boot_time_snapshot"
+const val PREF_KEY_ELAPSED_REALTIME_SNAPSHOT = "ah_elapsed_realtime_snapshot"
+
+private const val PREFS_FILE_NAME = "unused_apps_prefs"
+private const val PREF_KEY_UNUSED_APPS_REVIEW = "unused_apps_need_review"
+const val SNAPSHOT_UNINITIALIZED = -1L
+private const val ACTION_SET_UP_HIBERNATION =
+ "com.android.permissioncontroller.action.SET_UP_HIBERNATION"
+val ONE_DAY_MS = TimeUnit.DAYS.toMillis(1)
fun isHibernationEnabled(): Boolean {
return SdkLevel.isAtLeastS() &&
@@ -137,50 +163,143 @@ fun hibernationTargetsPreSApps(): Boolean {
false /* defaultValue */)
}
+@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codename = "UpsideDownCake")
+fun isSystemExemptFromHibernationEnabled(): Boolean {
+ return SdkLevel.isAtLeastU() && DeviceConfig.getBoolean(NAMESPACE_APP_HIBERNATION,
+ Utils.PROPERTY_SYSTEM_EXEMPT_HIBERNATION_ENABLED,
+ true /* defaultValue */)
+}
+
/**
- * Receiver of the onBoot event.
+ * Remove the unused apps notification.
*/
-class HibernationOnBootReceiver : BroadcastReceiver() {
+fun cancelUnusedAppsNotification(context: Context) {
+ context.getSystemService(NotificationManager::class.java)!!.cancel(
+ HibernationJobService::class.java.simpleName,
+ Constants.UNUSED_APPS_NOTIFICATION_ID)
+}
- override fun onReceive(context: Context, intent: Intent?) {
- if (DEBUG_HIBERNATION_POLICY) {
- DumpableLog.i(LOG_TAG, "scheduleHibernationJob " +
- "with frequency ${getCheckFrequencyMs()}ms " +
- "and threshold ${getUnusedThresholdMs()}ms")
- }
+/**
+ * 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)
+fun rescanAndPushDataToSafetyCenter(
+ context: Context,
+ sessionId: Long,
+ safetyEvent: SafetyEvent,
+) {
+ 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()
+
+ safetyCenterManager.setSafetySourceData(
+ Constants.UNUSED_APPS_SAFETY_CENTER_SOURCE_ID,
+ safetySourceData,
+ safetyEvent)
+ } else {
+ safetyCenterManager.setSafetySourceData(
+ Constants.UNUSED_APPS_SAFETY_CENTER_SOURCE_ID,
+ /* safetySourceData= */ null,
+ safetyEvent)
+ }
+}
- // Write first boot time if first boot
- context.firstBootTime
+/**
+ * Set whether we show the safety center card to the user to review their auto-revoked permissions.
+ */
+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) {
+ return
+ }
+ sharedPreferences.edit().putBoolean(PREF_KEY_UNUSED_APPS_REVIEW, needsReview).apply()
+}
- // If this user is a profile, then its hibernation/auto-revoke will be handled by the
- // primary user
- if (isProfile(context)) {
+private fun getUnusedAppsReviewNeeded(context: Context): Boolean {
+ return context.sharedPreferences.getBoolean(PREF_KEY_UNUSED_APPS_REVIEW, false)
+}
+
+/**
+ * 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}
+ * </ul>
+ */
+class HibernationBroadcastReceiver : BroadcastReceiver() {
+
+ override fun onReceive(context: Context, intent: Intent) {
+ val action = intent.action
+ if (action == Intent.ACTION_BOOT_COMPLETED || action == ACTION_SET_UP_HIBERNATION) {
if (DEBUG_HIBERNATION_POLICY) {
- DumpableLog.i(LOG_TAG, "user ${Process.myUserHandle().identifier} is a profile." +
- " Not running hibernation job.")
+ DumpableLog.i(LOG_TAG, "scheduleHibernationJob " +
+ "with frequency ${getCheckFrequencyMs()}ms " +
+ "and threshold ${getUnusedThresholdMs()}ms")
}
- return
- } else if (DEBUG_HIBERNATION_POLICY) {
- 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)
- if (status != JobScheduler.RESULT_SUCCESS) {
- DumpableLog.e(LOG_TAG,
- "Could not schedule ${HibernationJobService::class.java.simpleName}: $status")
+ initStartTimeOfUnusedAppTracking(context.sharedPreferences)
+
+ // If this user is a profile, then its hibernation/auto-revoke will be handled by the
+ // primary user
+ if (isProfile(context)) {
+ if (DEBUG_HIBERNATION_POLICY) {
+ 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.")
+ }
+
+ 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)
+ if (status != JobScheduler.RESULT_SUCCESS) {
+ DumpableLog.e(LOG_TAG, "Could not schedule " +
+ "${HibernationJobService::class.java.simpleName}: $status")
+ }
}
}
+ if (action == Intent.ACTION_TIME_CHANGED || action == Intent.ACTION_TIMEZONE_CHANGED) {
+ adjustStartTimeOfUnusedAppTracking(context.sharedPreferences)
+ }
}
// UserManager#isProfile was already a systemAPI, linter started complaining after it
@@ -225,10 +344,10 @@ class HibernationOnBootReceiver : BroadcastReceiver() {
*/
@MainThread
private suspend fun getAppsToHibernate(
- context: Context
+ context: Context,
): Map<UserHandle, List<LightPackageInfo>> {
val now = System.currentTimeMillis()
- val firstBootTime = context.firstBootTime
+ val startTimeOfUnusedAppTracking = getStartTimeOfUnusedAppTracking(context.sharedPreferences)
val allPackagesByUser = AllPackageInfosLiveData.getInitializedValue(forceUpdate = true)
val allPackagesByUserByUid = allPackagesByUser.mapValues { (_, pkgs) ->
@@ -273,7 +392,7 @@ private suspend fun getAppsToHibernate(
lastTimePkgUsed = Math.max(lastTimePkgUsed, packageInfo.firstInstallTime)
// Limit by first boot time
- lastTimePkgUsed = Math.max(lastTimePkgUsed, firstBootTime)
+ lastTimePkgUsed = Math.max(lastTimePkgUsed, startTimeOfUnusedAppTracking)
// Handle cross-profile apps
if (context.isPackageCrossProfile(pkgName)) {
@@ -372,7 +491,7 @@ private fun List<UsageStats>.lastTimePackageUsed(pkgName: String): Long {
*/
suspend fun isPackageHibernationExemptBySystem(
pkg: LightPackageInfo,
- user: UserHandle
+ user: UserHandle,
): Boolean {
if (!LauncherPackagesLiveData.getInitializedValue().contains(pkg.packageName)) {
if (DEBUG_HIBERNATION_POLICY) {
@@ -393,6 +512,14 @@ suspend fun isPackageHibernationExemptBySystem(
return true
}
+ if (pkg.uid == Process.SYSTEM_UID){
+ if (DEBUG_HIBERNATION_POLICY) {
+ DumpableLog.i(LOG_TAG,
+ "Exempted ${pkg.packageName} - Package shares system uid")
+ }
+ return true
+ }
+
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.
@@ -432,6 +559,15 @@ suspend fun isPackageHibernationExemptBySystem(
return true
}
+ val emergencyRoleHolders = context.getSystemService(android.app.role.RoleManager::class.java)!!
+ .getRoleHolders(RoleManager.ROLE_EMERGENCY)
+ if (emergencyRoleHolders.contains(pkg.packageName)) {
+ if (DEBUG_HIBERNATION_POLICY) {
+ DumpableLog.i(LOG_TAG, "Exempted ${pkg.packageName} - emergency app")
+ }
+ return true
+ }
+
if (SdkLevel.isAtLeastS()) {
val hasInstallOrUpdatePermissions =
context.checkPermission(
@@ -477,6 +613,18 @@ suspend fun isPackageHibernationExemptBySystem(
}
}
+ 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,
+ "Exempted ${pkg.packageName} - has OP_SYSTEM_EXEMPT_FROM_HIBERNATION"
+ )
+ }
+ return true
+ }
+
return false
}
@@ -486,7 +634,7 @@ suspend fun isPackageHibernationExemptBySystem(
*/
suspend fun isPackageHibernationExemptByUser(
context: Context,
- pkg: LightPackageInfo
+ pkg: LightPackageInfo,
): Boolean {
val packageName = pkg.packageName
val packageUid = pkg.uid
@@ -535,15 +683,120 @@ val Context.sharedPreferences: SharedPreferences
return PreferenceManager.getDefaultSharedPreferences(this)
}
-private val Context.firstBootTime: Long get() {
- var time = sharedPreferences.getLong(PREF_KEY_FIRST_BOOT_TIME, -1L)
- if (time > 0) {
- return time
+internal class SystemTime {
+ var actualSystemTime: Long = SNAPSHOT_UNINITIALIZED
+ var actualRealtime: Long = SNAPSHOT_UNINITIALIZED
+ var diffSystemTime: Long = SNAPSHOT_UNINITIALIZED
+}
+
+private fun getSystemTime(sharedPreferences: SharedPreferences): SystemTime {
+ val systemTime = SystemTime()
+ 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)
+ if (realtimeSnapshot == SNAPSHOT_UNINITIALIZED) {
+ DumpableLog.e(LOG_TAG, "PREF_KEY_ELAPSED_REALTIME_SNAPSHOT is not initialized")
+ return systemTime
+ }
+ systemTime.actualSystemTime = System.currentTimeMillis()
+ systemTime.actualRealtime = SystemClock.elapsedRealtime()
+ val expectedSystemTime = systemTime.actualRealtime - realtimeSnapshot + systemTimeSnapshot
+ systemTime.diffSystemTime = systemTime.actualSystemTime - expectedSystemTime
+ return systemTime
+}
+
+fun getStartTimeOfUnusedAppTracking(sharedPreferences: SharedPreferences): Long {
+ 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()
+ return actualSystemTime
+ }
+
+ val diffSystemTime = getSystemTime(sharedPreferences).diffSystemTime
+ // If the value stored is older than a day adjust start time.
+ if (diffSystemTime > ONE_DAY_MS) {
+ adjustStartTimeOfUnusedAppTracking(sharedPreferences)
+ }
+ 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()
+ }
+ val realtimeSnapshot = SystemClock.elapsedRealtime()
+ sharedPreferences.edit()
+ .putLong(PREF_KEY_BOOT_TIME_SNAPSHOT, systemTimeSnapshot)
+ .putLong(PREF_KEY_ELAPSED_REALTIME_SNAPSHOT, realtimeSnapshot)
+ .apply()
+}
+
+private fun adjustStartTimeOfUnusedAppTracking(sharedPreferences: SharedPreferences) {
+ val systemTime = getSystemTime(sharedPreferences)
+ val startTimeOfUnusedAppTracking =
+ 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()
+ .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.
+ */
+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)
+ return pendingIntent
+}
+
+/**
+ * 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)
+}
+
+/**
+ * Broadcast receiver class for when safety center card is dismissed.
+ */
+class DismissHandler : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ setUnusedAppsReviewNeeded(context!!, false)
}
- // This is the first boot
- time = System.currentTimeMillis()
- sharedPreferences.edit().putLong(PREF_KEY_FIRST_BOOT_TIME, time).apply()
- return time
}
/**
@@ -589,6 +842,16 @@ class HibernationJobService : JobService() {
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,
+ sessionId,
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED)
+ .build())
+ }
}
} catch (e: Exception) {
DumpableLog.e(LOG_TAG, "Failed to auto-revoke permissions", e)
@@ -606,14 +869,6 @@ class HibernationJobService : JobService() {
NotificationManager.IMPORTANCE_LOW)
notificationManager.createNotificationChannel(permissionReminderChannel)
- val clickIntent = Intent(Intent.ACTION_MANAGE_UNUSED_APPS).apply {
- putExtra(Constants.EXTRA_SESSION_ID, sessionId)
- 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)
-
var notifTitle: String
var notifContent: String
if (isHibernationEnabled()) {
@@ -630,15 +885,26 @@ class HibernationJobService : JobService() {
.setContentTitle(notifTitle)
.setContentText(notifContent)
.setStyle(Notification.BigTextStyle().bigText(notifContent))
- .setSmallIcon(R.drawable.ic_settings_24dp)
.setColor(getColor(android.R.color.system_notification_accent_color))
.setAutoCancel(true)
- .setContentIntent(pendingIntent)
- Utils.getSettingsLabelForNotifications(applicationContext.packageManager)?.let {
- settingsLabel ->
- val extras = Bundle()
- extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, settingsLabel.toString())
- b.addExtras(extras)
+ .setContentIntent(makeUnusedAppsIntent(this, sessionId))
+ val extras = Bundle()
+ if (SdkLevel.isAtLeastT() &&
+ getSystemService(SafetyCenterManager::class.java)!!.isSafetyCenterEnabled) {
+ val notificationResources = KotlinUtils.getSafetyCenterNotificationResources(this)
+
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, notificationResources.appLabel)
+ b.setSmallIcon(notificationResources.smallIcon)
+ .setColor(notificationResources.color)
+ .addExtras(extras)
+ } else {
+ // Use standard Settings branding
+ Utils.getSettingsLabelForNotifications(applicationContext.packageManager)?.let {
+ settingsLabel ->
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, settingsLabel.toString())
+ b.setSmallIcon(R.drawable.ic_settings_24dp)
+ .addExtras(extras)
+ }
}
notificationManager.notify(HibernationJobService::class.java.simpleName,
@@ -658,8 +924,8 @@ class HibernationJobService : JobService() {
* Packages using exempt services for the current user (package-name -> list<service-interfaces>
* implemented by the package)
*/
-class ExemptServicesLiveData(private val user: UserHandle)
- : SmartUpdateMediatorLiveData<Map<String, List<String>>>() {
+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,
@@ -736,8 +1002,8 @@ class ExemptServicesLiveData(private val user: UserHandle)
/**
* Live data for whether the hibernation feature is enabled or not.
*/
-object HibernationEnabledLiveData
- : MutableLiveData<Boolean>() {
+object HibernationEnabledLiveData :
+ MutableLiveData<Boolean>() {
init {
postValue(SdkLevel.isAtLeastS() &&
DeviceConfig.getBoolean(NAMESPACE_APP_HIBERNATION,
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/TEST_MAPPING b/PermissionController/src/com/android/permissioncontroller/permission/TEST_MAPPING
index e9b30d20a..b65eb6710 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/TEST_MAPPING
+++ b/PermissionController/src/com/android/permissioncontroller/permission/TEST_MAPPING
@@ -5,6 +5,24 @@
"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"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
}
]
},
@@ -12,16 +30,46 @@
"name": "CtsHibernationTestCases",
"options": [
{
- "include-filter": "android.hibernation.cts.AutoRevokeTest"
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
}
]
}
],
- "presubmit-large": [
+ "mainline-presubmit": [
{
- "name": "CtsPermission3TestCases",
+ "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"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.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": "android.platform.test.annotations.FlakyTest"
}
]
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompat.java b/PermissionController/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompat.java
new file mode 100644
index 000000000..637eb5fc4
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompat.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.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/AppPermGroupUiInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/AppPermGroupUiInfoLiveData.kt
index f3addd112..b9d2d237a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/AppPermGroupUiInfoLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/AppPermGroupUiInfoLiveData.kt
@@ -17,6 +17,7 @@
package com.android.permissioncontroller.permission.data
import android.Manifest
+import android.Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
import android.Manifest.permission_group.STORAGE
import android.app.AppOpsManager
import android.app.Application
@@ -31,9 +32,9 @@ 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.Utils
-import com.android.permissioncontroller.permission.utils.Utils.isModernPermissionGroup
import kotlinx.coroutines.Job
/**
@@ -132,9 +133,10 @@ class AppPermGroupUiInfoLiveData private constructor(
val isUserSet = isUserSet(permissionState)
- val isGranted = getGrantedIncludingBackground(permissionState, allPermInfos, packageInfo)
+ val permGrantState =
+ getGrantedIncludingBackground(permissionState, allPermInfos, packageInfo)
- return AppPermGroupUiInfo(shouldShow, isGranted, isSystemApp, isUserSet)
+ return AppPermGroupUiInfo(shouldShow, permGrantState, isSystemApp, isUserSet)
}
/**
@@ -155,7 +157,7 @@ class AppPermGroupUiInfoLiveData private constructor(
permissionInfos: Collection<LightPermInfo>
): Boolean {
if (groupInfo.packageName == Utils.OS_PKG &&
- !isModernPermissionGroup(groupInfo.name)) {
+ !isPlatformPermissionGroup(groupInfo.name)) {
return false
}
@@ -193,7 +195,7 @@ class AppPermGroupUiInfoLiveData private constructor(
* permission group
*/
private fun isUserSensitive(permissionState: Map<String, PermState>): Boolean {
- if (!isModernPermissionGroup(permGroupName)) {
+ if (!isPlatformPermissionGroup(permGroupName)) {
return true
}
@@ -282,6 +284,12 @@ class AppPermGroupUiInfoLiveData private constructor(
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)
+ }
if (anyAllowed && (hasPermWithBackground || shouldShowAsForegroundGroup())) {
return if (isOneTime) {
PermGrantState.PERMS_ASK
@@ -289,7 +297,7 @@ class AppPermGroupUiInfoLiveData private constructor(
PermGrantState.PERMS_ALLOWED_FOREGROUND_ONLY
}
} else if (anyAllowed) {
- return if (isOneTime) {
+ return if (isOneTime || onlySelectedPhotosGranted) {
PermGrantState.PERMS_ASK
} else {
PermGrantState.PERMS_ALLOWED
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/AutoRevokedPackagesLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/AutoRevokedPackagesLiveData.kt
index eb5dee214..70f857afb 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.Utils
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
@@ -64,7 +64,8 @@ object AutoRevokedPackagesLiveData
val pkgGroups = mutableSetOf<Triple<String, String, UserHandle>>()
for ((idx, requestedPerm) in pkg.requestedPermissions.withIndex()) {
- val group = Utils.getGroupOfPlatformPermission(requestedPerm) ?: continue
+ val group =
+ PermissionMapping.getGroupOfPlatformPermission(requestedPerm) ?: continue
val granted = (pkg.requestedPermissionsFlags[idx] and
PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0
if (pkg.targetSdkVersion < Build.VERSION_CODES.M || !granted) {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/CustomPermGroupNamesLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/CustomPermGroupNamesLiveData.kt
index b2b645b41..cb44c0a27 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/CustomPermGroupNamesLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/CustomPermGroupNamesLiveData.kt
@@ -19,7 +19,7 @@ package com.android.permissioncontroller.permission.data
import android.app.Application
import android.content.pm.PermissionInfo
import com.android.permissioncontroller.PermissionControllerApplication
-import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.permission.utils.PermissionMapping
/**
* A class which tracks the names of all custom permission groups in the system, including
@@ -38,7 +38,7 @@ object CustomPermGroupNamesLiveData : SmartUpdateMediatorLiveData<List<String>>(
}
override fun onUpdate() {
- val platformGroupNames = Utils.getPlatformPermissionGroups()
+ val platformGroupNames = PermissionMapping.getPlatformPermissionGroups()
val groupNames = mutableListOf<String>()
val allPackages = packagesLiveData.value ?: return
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/ForegroundPermNamesLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/ForegroundPermNamesLiveData.kt
index 8ed2429ad..1471ed15f 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/ForegroundPermNamesLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/ForegroundPermNamesLiveData.kt
@@ -18,6 +18,7 @@ package com.android.permissioncontroller.permission.data
import android.content.pm.PackageManager
import com.android.permissioncontroller.PermissionControllerApplication
+import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.utils.Utils
import kotlinx.coroutines.Job
@@ -35,7 +36,7 @@ object ForegroundPermNamesLiveData : SmartAsyncMediatorLiveData<Map<String, List
}
override suspend fun loadDataAndPostValue(job: Job) {
- val systemGroups = Utils.getPlatformPermissionGroups()
+ val systemGroups = PermissionMapping.getPlatformPermissionGroups()
val permMap = mutableMapOf<String, MutableList<String>>()
for (groupName in systemGroups) {
val permInfos = try {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/LightPackageInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/LightPackageInfoLiveData.kt
index 82d614d93..27681cd90 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/LightPackageInfoLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/LightPackageInfoLiveData.kt
@@ -20,9 +20,11 @@ package com.android.permissioncontroller.permission.data
import android.app.Application
import android.content.pm.PackageManager
import android.os.UserHandle
+import android.os.UserManager
import android.util.Log
import androidx.annotation.MainThread
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.Utils
@@ -46,7 +48,6 @@ class LightPackageInfoLiveData private constructor(
private val LOG_TAG = LightPackageInfoLiveData::class.java.simpleName
private val userPackagesLiveData = UserPackageInfosLiveData[user]
- private var context = Utils.getUserContext(app, user)
private var uid: Int? = null
/**
* The currently registered UID on which this LiveData is listening for permission changes.
@@ -95,10 +96,21 @@ class LightPackageInfoLiveData private constructor(
return
}
postValue(try {
- LightPackageInfo(context.packageManager.getPackageInfo(packageName,
- PackageManager.GET_PERMISSIONS))
- } catch (e: PackageManager.NameNotFoundException) {
- Log.w(LOG_TAG, "Package \"$packageName\" not found")
+ var flags = PackageManager.GET_PERMISSIONS
+ if (SdkLevel.isAtLeastS()) {
+ flags = flags or PackageManager.GET_ATTRIBUTIONS
+ }
+
+ 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)
+ }
invalidateSingle(packageName to user)
null
})
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/LightPermInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/LightPermInfoLiveData.kt
index 9d45d35ad..6f33cb199 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/LightPermInfoLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/LightPermInfoLiveData.kt
@@ -20,9 +20,9 @@ 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.Utils.OS_PKG
-import com.android.permissioncontroller.permission.utils.Utils.isRuntimePlatformPermission
import kotlinx.coroutines.Job
/**
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/PackageBroadcastReceiver.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PackageBroadcastReceiver.kt
index 9dc16e306..b2e0236fa 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/PackageBroadcastReceiver.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PackageBroadcastReceiver.kt
@@ -21,7 +21,10 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import com.android.modules.utils.build.SdkLevel
import com.android.permissioncontroller.PermissionControllerApplication
+import com.android.permissioncontroller.permission.data.v34.LightInstallSourceInfoLiveData
+import com.android.permissioncontroller.permission.data.v34.SafetyLabelInfoLiveData
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
@@ -161,6 +164,10 @@ object PackageBroadcastReceiver : BroadcastReceiver() {
HibernationSettingStateLiveData.invalidateAllForPackage(packageName)
LightAppPermGroupLiveData.invalidateAllForPackage(packageName)
AppPermGroupUiInfoLiveData.invalidateAllForPackage(packageName)
+ if (SdkLevel.isAtLeastU()) {
+ SafetyLabelInfoLiveData.invalidateAllForPackage(packageName)
+ LightInstallSourceInfoLiveData.invalidateAllForPackage(packageName)
+ }
}
}
@@ -176,4 +183,4 @@ object PackageBroadcastReceiver : BroadcastReceiver() {
*/
fun onPackageUpdate(packageName: String)
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/PackagePermissionsLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PackagePermissionsLiveData.kt
index f83d69885..49be1fbd0 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/PackagePermissionsLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PackagePermissionsLiveData.kt
@@ -22,7 +22,7 @@ import android.content.pm.PermissionInfo
import android.os.Build
import android.os.UserHandle
import com.android.permissioncontroller.PermissionControllerApplication
-import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.permission.utils.PermissionMapping
import kotlinx.coroutines.Job
/**
@@ -58,7 +58,7 @@ class PackagePermissionsLiveData private constructor(
val packageInfo = packageInfoLiveData.value ?: return
val permissionMap = mutableMapOf<String, MutableList<String>>()
for (permName in packageInfo.requestedPermissions) {
- var groupName = Utils.getGroupOfPlatformPermission(permName)
+ var groupName = PermissionMapping.getGroupOfPlatformPermission(permName)
if (groupName == null) {
val permInfo = try {
app.packageManager.getPermissionInfo(permName, 0)
@@ -93,7 +93,7 @@ class PackagePermissionsLiveData private constructor(
continue
}
- groupName = Utils.getGroupOfPermission(permInfo) ?: permName
+ groupName = PermissionMapping.getGroupOfPermission(permInfo) ?: permName
}
permissionMap.getOrPut(groupName) { mutableListOf() }.add(permName)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupUsageLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupUsageLiveData.kt
index 7b3905030..08f9bbfb4 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupUsageLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupUsageLiveData.kt
@@ -19,7 +19,7 @@ package com.android.permissioncontroller.permission.data
import android.app.AppOpsManager.permissionToOp
import android.app.Application
import com.android.permissioncontroller.PermissionControllerApplication
-import com.android.permissioncontroller.permission.utils.Utils.getPlatformPermissionNamesOfGroup
+import com.android.permissioncontroller.permission.utils.PermissionMapping.getPlatformPermissionNamesOfGroup
import kotlin.collections.set
/**
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesLiveData.kt
index c44c2b473..e4fa75bd6 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesLiveData.kt
@@ -43,7 +43,7 @@ class PermGroupsPackagesLiveData private constructor(
init {
addSource(groupNamesLiveData) {
- groupNames = it ?: emptyList()
+ groupNames = it
val getLiveData = { groupName: String -> PermGroupLiveData[groupName] }
setSourcesToDifference(groupNames, permGroupLiveDatas, getLiveData) {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesUiInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesUiInfoLiveData.kt
index 0318144e4..37967840b 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesUiInfoLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PermGroupsPackagesUiInfoLiveData.kt
@@ -18,6 +18,8 @@ package com.android.permissioncontroller.permission.data
import android.app.Application
import android.app.role.RoleManager
+import android.os.Handler
+import android.os.Looper
import android.os.UserHandle
import androidx.lifecycle.LiveData
import com.android.permissioncontroller.PermissionControllerApplication
@@ -34,11 +36,24 @@ import com.android.permissioncontroller.permission.utils.Utils
*/
class PermGroupsPackagesUiInfoLiveData(
private val app: Application,
- groupNamesLiveData: LiveData<List<String>>
+ private val groupNamesLiveData: LiveData<List<String>>
) : SmartUpdateMediatorLiveData<
@kotlin.jvm.JvmSuppressWildcards Map<String, PermGroupPackagesUiInfo?>>() {
private val SYSTEM_SHELL = "android.app.role.SYSTEM_SHELL"
+ private val STAGGER_LOAD_TIME_MS = 50L
+
+ // Optimization: This LiveData relies on a large number of other ones. Enough that they can
+ // cause loading issues when they all become active at once. If this value is true, then it will
+ // slowly load data from all source LiveDatas, spacing loads them STAGGER_LOAD_TIME_MS apart
+ var loadStaggered: Boolean = false
+
+ // If we are returning from a particular permission group page, then that particular group is
+ // the one most likely to change. If so, then it will be prioritized in the load order.
+ var firstLoadGroup: String? = null
+
+ private val handler: Handler = Handler(Looper.getMainLooper())
+
/**
* Map<permission group name, PermGroupUiLiveDatas>
*/
@@ -50,7 +65,7 @@ class PermGroupsPackagesUiInfoLiveData(
init {
addSource(groupNamesLiveData) {
- groupNames = it ?: emptyList()
+ groupNames = it
update()
getPermGroupPackageLiveDatas()
}
@@ -139,4 +154,39 @@ class PermGroupsPackagesUiInfoLiveData(
}
value = allPackageData.toMap()
}
+
+ // Schedule a staggered loading of individual permission group livedatas
+ private fun scheduleStaggeredGroupLoad() {
+ if (groupNamesLiveData.value != null) {
+ if (firstLoadGroup in groupNames) {
+ addLiveDataDelayed(firstLoadGroup!!, 0)
+ }
+ for ((idx, groupName) in groupNames.withIndex()) {
+ if (groupName != firstLoadGroup) {
+ addLiveDataDelayed(groupName, idx * STAGGER_LOAD_TIME_MS)
+ }
+ }
+ }
+ }
+
+ private fun addLiveDataDelayed(groupName: String, delayTimeMs: Long) {
+ val liveData = SinglePermGroupPackagesUiInfoLiveData[groupName]
+ permGroupPackagesLiveDatas[groupName] = liveData
+ handler.postDelayed( { addSource(liveData) { update() } }, delayTimeMs)
+ }
+
+ override fun onActive() {
+ super.onActive()
+ if (loadStaggered && permGroupPackagesLiveDatas.isEmpty()) {
+ scheduleStaggeredGroupLoad()
+ }
+ }
+
+ override fun onInactive() {
+ super.onInactive()
+ if (loadStaggered) {
+ permGroupPackagesLiveDatas.forEach { (_, liveData) -> removeSource(liveData) }
+ permGroupPackagesLiveDatas.clear()
+ }
+ }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/v33/PermissionChange.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PermissionChange.kt
index fb553d487..29789b0f7 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/v33/PermissionChange.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PermissionChange.kt
@@ -14,10 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.data.v33
-
-import android.os.Build
-import androidx.annotation.RequiresApi
+package com.android.permissioncontroller.permission.data
/**
* A record of the user changing permissions for the app but not including any information on what
@@ -25,7 +22,6 @@ import androidx.annotation.RequiresApi
* persist the data for longer periods of time than we'd be able to otherwise
* (e.g. [PermissionDecision]).
*/
-@RequiresApi(Build.VERSION_CODES.TIRAMISU)
data class PermissionChange(
override val packageName: String,
override val eventTime: Long
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/v33/PermissionEvent.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/PermissionEvent.kt
index e292ab1a2..ad759795b 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/v33/PermissionEvent.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/PermissionEvent.kt
@@ -14,10 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.data.v33
-
-import android.os.Build
-import androidx.annotation.RequiresApi
+package com.android.permissioncontroller.permission.data
/**
* A record of a permission event caused by the user.
@@ -26,7 +23,6 @@ import androidx.annotation.RequiresApi
* @param eventTime the time of the event, in epoch time. Should be rounded to day-level
* precision for user privacy.
*/
-@RequiresApi(Build.VERSION_CODES.TIRAMISU)
abstract class PermissionEvent(
open val packageName: String,
open val eventTime: Long
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/ServiceLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/ServiceLiveData.kt
index 4d5de4cd2..6d59fd585 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/ServiceLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/ServiceLiveData.kt
@@ -193,13 +193,13 @@ class ServiceLiveData(
}
return when (intentAction) {
AccessibilityService.SERVICE_INTERFACE -> {
- pkg in enabledAccessibilityServicesLiveData.value!!
+ pkg in (enabledAccessibilityServicesLiveData.value ?: emptyList<String>())
}
InputMethod.SERVICE_INTERFACE -> {
- pkg in enabledInputMethodsLiveData.value!!
+ pkg in (enabledInputMethodsLiveData.value ?: emptyList<String>())
}
NotificationListenerService.SERVICE_INTERFACE -> {
- pkg in enabledNotificationListenersLiveData.value!!
+ pkg in (enabledNotificationListenersLiveData.value ?: emptyList<String>())
}
WallpaperService.SERVICE_INTERFACE -> {
pkg == selectedWallpaperServiceLiveData.value
@@ -211,13 +211,13 @@ class ServiceLiveData(
pkg == selectedAutofillServiceLiveData.value
}
DreamService.SERVICE_INTERFACE -> {
- pkg in enabledDreamServicesLiveData.value!!
+ pkg in (enabledDreamServicesLiveData.value ?: emptyList<String>())
}
PrintService.SERVICE_INTERFACE -> {
- pkg !in disabledPrintServicesLiveData.value!!
+ pkg !in (disabledPrintServicesLiveData.value ?: emptyList<String>())
}
DevicePolicyManager.ACTION_DEVICE_ADMIN_SERVICE -> {
- pkg in enabledDeviceAdminsLiveDataLiveData.value!!
+ pkg in (enabledDeviceAdminsLiveDataLiveData.value ?: emptyList<String>())
}
else -> true
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/SinglePermGroupPackagesUiInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/SinglePermGroupPackagesUiInfoLiveData.kt
index bf49b48ec..a46882c04 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.Utils
/**
* LiveData for the UI info for all packages in a single permission group. Tracks which packages
@@ -36,7 +36,8 @@ class SinglePermGroupPackagesUiInfoLiveData private constructor(
) : SmartUpdateMediatorLiveData<Map<Pair<String, UserHandle>, AppPermGroupUiInfo>>() {
private val permGroupLiveData = PermGroupLiveData[permGroupName]
- private val isCustomGroup = !Utils.getPlatformPermissionGroups().contains(permGroupName)
+ private val isCustomGroup =
+ !PermissionMapping.getPlatformPermissionGroups().contains(permGroupName)
private val permGroupPackagesLiveData = PermGroupsPackagesLiveData.get(
customGroups = isCustomGroup)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/SmartUpdateMediatorLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/SmartUpdateMediatorLiveData.kt
index 639539ebd..7c3ebe0b3 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/SmartUpdateMediatorLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/SmartUpdateMediatorLiveData.kt
@@ -36,8 +36,8 @@ import kotlinx.coroutines.launch
*
* @param isStaticVal Whether or not this LiveData value is expected to change
*/
-abstract class SmartUpdateMediatorLiveData<T>(private val isStaticVal: Boolean = false)
- : MediatorLiveData<T>(), DataRepository.InactiveTimekeeper {
+abstract class SmartUpdateMediatorLiveData<T>(private val isStaticVal: Boolean = false) :
+ MediatorLiveData<T>(), DataRepository.InactiveTimekeeper {
companion object {
const val DEBUG_UPDATES = false
@@ -45,14 +45,6 @@ abstract class SmartUpdateMediatorLiveData<T>(private val isStaticVal: Boolean =
}
/**
- * Boolean, whether or not the value of this uiDataLiveData has been explicitly set yet.
- * Differentiates between "null value because liveData is new" and "null value because
- * liveData is invalid"
- */
- var isInitialized = false
- private set
-
- /**
* Boolean, whether or not this liveData has a stale value or not. Every time the liveData goes
* inactive, its data becomes stale, until it goes active again, and is explicitly set.
*/
@@ -66,7 +58,6 @@ abstract class SmartUpdateMediatorLiveData<T>(private val isStaticVal: Boolean =
ensureMainThread()
if (!isInitialized) {
- isInitialized = true
// If we have received an invalid value, and this is the first time we are set,
// notify observers.
if (newValue == null) {
@@ -176,7 +167,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) {
@@ -201,7 +192,7 @@ 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> {
+ val observer = Observer<Any?> {
if (onUpdateFun != null) {
onUpdateFun(key)
} else {
@@ -247,6 +238,6 @@ abstract class SmartUpdateMediatorLiveData<T>(private val isStaticVal: Boolean =
update()
}
},
- isInitialized = { 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 0719a44de..3b3b76171 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/StandardPermGroupNamesLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/StandardPermGroupNamesLiveData.kt
@@ -17,7 +17,7 @@
package com.android.permissioncontroller.permission.data
import androidx.lifecycle.LiveData
-import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.permission.utils.PermissionMapping
/**
* A LiveData which tracks Platform Permission Group names.
@@ -25,6 +25,6 @@ import com.android.permissioncontroller.permission.utils.Utils
object StandardPermGroupNamesLiveData : LiveData<List<String>>() {
init {
- postValue(Utils.getPlatformPermissionGroups())
+ postValue(PermissionMapping.getPlatformPermissionGroups())
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/UserPackageInfosLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/UserPackageInfosLiveData.kt
index 36586e7cc..02285809c 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/UserPackageInfosLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/UserPackageInfosLiveData.kt
@@ -18,9 +18,13 @@
package com.android.permissioncontroller.permission.data
import android.app.Application
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.GET_ATTRIBUTIONS
+import android.content.pm.PackageManager.GET_ATTRIBUTIONS_LONG
import android.content.pm.PackageManager.GET_PERMISSIONS
import android.content.pm.PackageManager.MATCH_ALL
import android.os.UserHandle
+import com.android.modules.utils.build.SdkLevel
import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
import kotlinx.coroutines.Job
@@ -31,16 +35,13 @@ import kotlinx.coroutines.Job
* @param app The current application
* @param user The user whose packages are desired
*/
-class UserPackageInfosLiveData private constructor(
- private val app: Application,
- private val user: UserHandle
-) : SmartAsyncMediatorLiveData<@kotlin.jvm.JvmSuppressWildcards List<LightPackageInfo>>(),
+class UserPackageInfosLiveData
+private constructor(private val app: Application, private val user: UserHandle) :
+ SmartAsyncMediatorLiveData<@JvmSuppressWildcards List<LightPackageInfo>>(),
PackageBroadcastReceiver.PackageBroadcastListener,
PermissionListenerMultiplexer.PermissionChangeCallback {
- /**
- * Whether or not the permissions in this liveData are out of date
- */
+ /** Whether or not the permissions in this liveData are out of date */
var permChangeStale = false
override fun onPackageUpdate(packageName: String) {
@@ -68,15 +69,29 @@ class UserPackageInfosLiveData private constructor(
permChangeStale = false
}
- /**
- * Get all of the packages in the system, organized by user.
- */
+ /** Get all of the packages in the system, organized by user. */
override suspend fun loadDataAndPostValue(job: Job) {
if (job.isCancelled) {
return
}
- val packageInfos = app.applicationContext.packageManager
- .getInstalledPackagesAsUser(GET_PERMISSIONS or MATCH_ALL, user.identifier)
+
+ val packageInfos =
+ if (SdkLevel.isAtLeastU()) {
+ app.applicationContext.packageManager.getInstalledPackagesAsUser(
+ PackageManager.PackageInfoFlags.of(
+ GET_PERMISSIONS.toLong() or GET_ATTRIBUTIONS_LONG or MATCH_ALL.toLong()
+ ),
+ user.identifier
+ )
+ } else if (SdkLevel.isAtLeastS()) {
+ app.applicationContext.packageManager.getInstalledPackagesAsUser(
+ GET_PERMISSIONS or GET_ATTRIBUTIONS or MATCH_ALL, user.identifier
+ )
+ } else {
+ app.applicationContext.packageManager.getInstalledPackagesAsUser(
+ GET_PERMISSIONS or MATCH_ALL, user.identifier
+ )
+ }
postValue(packageInfos.map { packageInfo -> LightPackageInfo(packageInfo) })
}
@@ -103,6 +118,7 @@ class UserPackageInfosLiveData private constructor(
/**
* Repository for UserPackageInfosLiveDatas.
+ *
* <p> Key value is a UserHandle, value is its corresponding LiveData.
*/
companion object : DataRepository<UserHandle, UserPackageInfosLiveData>() {
@@ -110,4 +126,4 @@ class UserPackageInfosLiveData private constructor(
return UserPackageInfosLiveData(PermissionControllerApplication.get(), key)
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/UserSensitivityLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/UserSensitivityLiveData.kt
index 28b6e2176..c138dc36d 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/UserSensitivityLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/UserSensitivityLiveData.kt
@@ -25,6 +25,7 @@ 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.Utils
@@ -100,7 +101,7 @@ class UserSensitivityLiveData private constructor(
val sensitiveStatePerUid = mutableMapOf<Int, UidSensitivityState>()
// TODO ntmyren: Figure out how to get custom runtime permissions in a less costly manner
- val runtimePerms = Utils.getRuntimePlatformPermissionNames()
+ val runtimePerms = PermissionMapping.getRuntimePlatformPermissionNames()
for (pkg in pkgs) {
// sensitivityState for one uid
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/UsersLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/UsersLiveData.kt
index abdd59f11..0e78ec5f6 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/UsersLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/UsersLiveData.kt
@@ -25,6 +25,7 @@ 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.
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightHistoricalPackageOpsLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightHistoricalPackageOpsLiveData.kt
new file mode 100644
index 000000000..a3fc40232
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightHistoricalPackageOpsLiveData.kt
@@ -0,0 +1,147 @@
+/*
+ * 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.permissioncontroller.permission.data.v31
+
+import android.app.AppOpsManager
+import android.app.AppOpsManager.HISTORY_FLAG_DISCRETE
+import android.app.AppOpsManager.HISTORY_FLAG_GET_ATTRIBUTION_CHAINS
+import android.app.AppOpsManager.HistoricalOps
+import android.app.AppOpsManager.HistoricalOpsRequest
+import android.app.AppOpsManager.OP_FLAG_SELF
+import android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED
+import android.app.Application
+import android.os.UserHandle
+import android.os.UserManager
+import com.android.modules.utils.build.SdkLevel
+import com.android.permissioncontroller.permission.data.SmartAsyncMediatorLiveData
+import com.android.permissioncontroller.permission.model.livedatatypes.v31.LightHistoricalPackageOps
+import java.util.concurrent.TimeUnit
+import kotlin.coroutines.suspendCoroutine
+import kotlinx.coroutines.Job
+
+/**
+ * LiveData class tracking [LightHistoricalPackageOps] for all packages on the device and for the
+ * provided app ops.
+ *
+ * App ops data is retrieved from [AppOpsManager] and is updated whenever app ops data changes are
+ * heard.
+ */
+class AllLightHistoricalPackageOpsLiveData(app: Application, val opNames: Set<String>) :
+ SmartAsyncMediatorLiveData<Map<Pair<String, UserHandle>, LightHistoricalPackageOps>>(),
+ AppOpsManager.OnOpActiveChangedListener,
+ AppOpsManager.OnOpNotedListener,
+ AppOpsManager.OnOpChangedListener {
+
+ private val appOpsManager = app.getSystemService(AppOpsManager::class.java)!!
+ private val userManager = app.getSystemService(UserManager::class.java)!!
+
+ override fun onActive() {
+ super.onActive()
+
+ opNames.forEach { opName ->
+ // TODO(b/262035952): We watch each active op individually as startWatchingActive only
+ // registers the callback if all ops are valid. Fix this behavior so if one op is
+ // invalid it doesn't affect the other ops.
+ try {
+ appOpsManager.startWatchingActive(arrayOf(opName), { it.run() }, this)
+ } catch (ignored: IllegalArgumentException) {
+ // Older builds may not support all requested app ops.
+ }
+
+ try {
+ appOpsManager.startWatchingMode(opName, /* all packages */ null, this)
+ } catch (ignored: IllegalArgumentException) {
+ // Older builds may not support all requested app ops.
+ }
+
+ if (SdkLevel.isAtLeastU()) {
+ try {
+ appOpsManager.startWatchingNoted(arrayOf(opName), this)
+ } catch (ignored: IllegalArgumentException) {
+ // Older builds may not support all requested app ops.
+ }
+ }
+ }
+ }
+
+ override fun onInactive() {
+ super.onInactive()
+
+ appOpsManager.stopWatchingActive(this)
+ appOpsManager.stopWatchingMode(this)
+ }
+
+ override suspend fun loadDataAndPostValue(job: Job) {
+ if (job.isCancelled) {
+ return
+ }
+
+ val allLightHistoricalPackageOps =
+ mutableMapOf<Pair<String, UserHandle>, LightHistoricalPackageOps>()
+
+ val endTimeMillis = System.currentTimeMillis()
+ val beginTimeMillis = endTimeMillis - TimeUnit.DAYS.toMillis(7)
+
+ val allProfilesInCurrentUser = userManager.userProfiles
+
+ val request =
+ HistoricalOpsRequest.Builder(beginTimeMillis, endTimeMillis)
+ .setFlags(OP_FLAG_SELF or OP_FLAG_TRUSTED_PROXIED)
+ .setHistoryFlags(HISTORY_FLAG_DISCRETE or HISTORY_FLAG_GET_ATTRIBUTION_CHAINS)
+ .build()
+
+ val historicalOps = suspendCoroutine {
+ appOpsManager.getHistoricalOps(request, { it.run() }) { ops: HistoricalOps ->
+ it.resumeWith(Result.success(ops))
+ }
+ }
+
+ for (i in 0 until historicalOps.uidCount) {
+ val historicalUidOps = historicalOps.getUidOpsAt(i)
+ val userHandle = UserHandle.getUserHandleForUid(historicalUidOps.uid)
+ if (userHandle !in allProfilesInCurrentUser) {
+ continue
+ }
+ for (j in 0 until historicalUidOps.packageCount) {
+ val historicalPackageOps = historicalUidOps.getPackageOpsAt(j)
+ allLightHistoricalPackageOps[Pair(historicalPackageOps.packageName, userHandle)] =
+ LightHistoricalPackageOps(historicalPackageOps, userHandle, opNames)
+ }
+ }
+
+ postValue(allLightHistoricalPackageOps)
+ }
+
+ override fun onOpChanged(op: String?, packageName: String?) {
+ update()
+ }
+
+ override fun onOpActiveChanged(op: String, uid: Int, packageName: String, active: Boolean) {
+ update()
+ }
+
+ override fun onOpNoted(
+ code: String,
+ uid: Int,
+ packageName: String,
+ attributionTag: String?,
+ flags: Int,
+ result: Int
+ ) {
+ update()
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightPackageOpsLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightPackageOpsLiveData.kt
new file mode 100644
index 000000000..6483c9f9c
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightPackageOpsLiveData.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 com.android.permissioncontroller.permission.data.v31
+
+import android.app.AppOpsManager
+import android.app.AppOpsManager.OPSTR_PHONE_CALL_CAMERA
+import android.app.AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE
+import android.app.AppOpsManager.OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO
+import android.app.Application
+import android.os.UserHandle
+import android.os.UserManager
+import com.android.modules.utils.build.SdkLevel
+import com.android.permissioncontroller.permission.data.SmartAsyncMediatorLiveData
+import com.android.permissioncontroller.permission.data.StandardPermGroupNamesLiveData
+import com.android.permissioncontroller.permission.model.livedatatypes.v31.LightPackageOps
+import com.android.permissioncontroller.permission.utils.PermissionMapping
+import kotlinx.coroutines.Job
+
+/**
+ * LiveData class tracking [LightPackageOps] for all packages on the device and for all system
+ * permission groups' ops.
+ *
+ * App ops data is retrieved from [AppOpsManager] and is updated whenever app ops data changes are
+ * heard.
+ */
+class AllLightPackageOpsLiveData(app: Application) :
+ SmartAsyncMediatorLiveData<Map<Pair<String, UserHandle>, LightPackageOps>>(),
+ AppOpsManager.OnOpActiveChangedListener,
+ AppOpsManager.OnOpNotedListener,
+ AppOpsManager.OnOpChangedListener {
+
+ private val appOpsManager = app.getSystemService(AppOpsManager::class.java)!!
+ private val userManager = app.getSystemService(UserManager::class.java)!!
+ private var opNames: MutableSet<String> =
+ getOpNames(StandardPermGroupNamesLiveData.value).toMutableSet()
+
+ init {
+ addSource(StandardPermGroupNamesLiveData) {
+ opNames = getOpNames(it).toMutableSet()
+ opNames.add(OPSTR_PHONE_CALL_MICROPHONE)
+ opNames.add(OPSTR_PHONE_CALL_CAMERA)
+ if (SdkLevel.isAtLeastT()) {
+ opNames.add(OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO)
+ }
+
+ update()
+ }
+ }
+
+ override fun onActive() {
+ super.onActive()
+
+ opNames.forEach { opName ->
+ // TODO(b/262035952): We watch each active op individually as startWatchingActive only
+ // registers the callback if all ops are valid. Fix this behavior so if one op is
+ // invalid it doesn't affect the other ops.
+ try {
+ appOpsManager.startWatchingActive(arrayOf(opName), { it.run() }, this)
+ } catch (ignored: IllegalArgumentException) {
+ // Older builds may not support all requested app ops.
+ }
+
+ try {
+ appOpsManager.startWatchingMode(opName, /* all packages */ null, this)
+ } catch (ignored: IllegalArgumentException) {
+ // Older builds may not support all requested app ops.
+ }
+
+ if (SdkLevel.isAtLeastU()) {
+ try {
+ appOpsManager.startWatchingNoted(arrayOf(opName), this)
+ } catch (ignored: IllegalArgumentException) {
+ // Older builds may not support all requested app ops.
+ }
+ }
+ }
+ }
+
+ override fun onInactive() {
+ super.onInactive()
+
+ appOpsManager.stopWatchingActive(this)
+ appOpsManager.stopWatchingMode(this)
+ }
+
+ override suspend fun loadDataAndPostValue(job: Job) {
+ if (opNames.isEmpty()) {
+ return
+ }
+
+ val packageOpsList =
+ try {
+ appOpsManager.getPackagesForOps(opNames.toTypedArray())
+ } catch (e: NullPointerException) {
+ // Older builds may not support all requested app ops.
+ emptyList<AppOpsManager.PackageOps>()
+ }
+
+ val allProfilesInCurrentUser = userManager.userProfiles
+
+ postValue(
+ packageOpsList
+ .filter { UserHandle.getUserHandleForUid(it.uid) in allProfilesInCurrentUser }
+ .associateBy(
+ { Pair(it.packageName, UserHandle.getUserHandleForUid(it.uid)) },
+ { LightPackageOps(opNames, it) }))
+ }
+
+ override fun onOpChanged(op: String?, packageName: String?) {
+ update()
+ }
+
+ override fun onOpActiveChanged(op: String, uid: Int, packageName: String, active: Boolean) {
+ update()
+ }
+
+ override fun onOpNoted(
+ code: String,
+ uid: Int,
+ packageName: String,
+ attributionTag: String?,
+ flags: Int,
+ result: Int
+ ) {
+ update()
+ }
+
+ /** Returns all op names for all permissions in a list of permission groups. */
+ private fun getOpNames(permissionGroupNames: List<String>?) =
+ permissionGroupNames
+ ?.flatMap { group -> PermissionMapping.getPlatformPermissionNamesOfGroup(group) }
+ ?.mapNotNull { permName -> AppOpsManager.permissionToOp(permName) }
+ ?.toSet()
+ ?: setOf()
+}
diff --git a/service/java/com/android/access/AccessCheckingService.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/v31/package-info.java
index e61a245fd..139b60364 100644
--- a/service/java/com/android/access/AccessCheckingService.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/v31/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 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,11 +14,5 @@
* limitations under the License.
*/
-package com.android.access
-
-import androidx.annotation.Keep
-
-@Keep
-class AccessCheckingService {
- var list = mutableListOf<Any>()
-}
+@androidx.annotation.RequiresApi(android.os.Build.VERSION_CODES.S)
+package com.android.permissioncontroller.permission.data.v31;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/v33/PermissionDecision.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/v33/PermissionDecision.kt
index e452f0d2b..646a15c12 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/v33/PermissionDecision.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/v33/PermissionDecision.kt
@@ -18,6 +18,7 @@ package com.android.permissioncontroller.permission.data.v33
import android.os.Build
import androidx.annotation.RequiresApi
+import com.android.permissioncontroller.permission.data.PermissionEvent
/**
* A record of a user's permission decision for an app.
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 6361477f2..4c18d6987 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/v33/RecentPermissionDecisionsLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/v33/RecentPermissionDecisionsLiveData.kt
@@ -21,7 +21,7 @@ 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.v33.PermissionEventStorage
+import com.android.permissioncontroller.permission.service.PermissionEventStorage
import kotlinx.coroutines.Job
/** Gets all recent permission decisions made by the user. */
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/v34/AppDataSharingUpdatesLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/v34/AppDataSharingUpdatesLiveData.kt
new file mode 100644
index 000000000..d5fd59242
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/v34/AppDataSharingUpdatesLiveData.kt
@@ -0,0 +1,77 @@
+/*
+ * 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.permissioncontroller.permission.data.v34
+
+import android.app.Application
+import android.os.Build
+import android.provider.DeviceConfig
+import androidx.annotation.RequiresApi
+import com.android.permissioncontroller.permission.data.SmartAsyncMediatorLiveData
+import com.android.permissioncontroller.permission.model.v34.AppDataSharingUpdate
+import com.android.permissioncontroller.permission.model.v34.AppDataSharingUpdate.Companion.buildUpdateIfSignificantChange
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistoryPersistence
+import java.time.Duration
+import java.time.Instant
+import java.time.ZoneId
+import kotlinx.coroutines.Job
+
+/** LiveData for [AppDataSharingUpdate]s. */
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+class AppDataSharingUpdatesLiveData(val app: Application) :
+ SmartAsyncMediatorLiveData<List<AppDataSharingUpdate>>(),
+ AppsSafetyLabelHistoryPersistence.ChangeListener {
+
+ override suspend fun loadDataAndPostValue(job: Job) {
+ val updatePeriod =
+ DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_DATA_SHARING_UPDATE_PERIOD_MILLIS,
+ 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)
+ val updatesFromPersistence =
+ appSafetyLabelDiffsFromPersistence.mapNotNull { it.buildUpdateIfSignificantChange() }
+
+ postValue(updatesFromPersistence)
+ }
+
+ override fun onActive() {
+ super.onActive()
+ AppsSafetyLabelHistoryPersistence.addListener(this)
+ }
+
+ override fun onInactive() {
+ super.onInactive()
+ AppsSafetyLabelHistoryPersistence.removeListener(this)
+ }
+
+ override fun onSafetyLabelHistoryChanged() {
+ update()
+ }
+
+ /** Companion object for [AppDataSharingUpdatesLiveData]. */
+ companion object {
+ private const val PROPERTY_DATA_SHARING_UPDATE_PERIOD_MILLIS =
+ "data_sharing_update_period_millis"
+ private const val DEFAULT_DATA_SHARING_UPDATE_PERIOD_DAYS: Long = 30
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/v34/LightInstallSourceInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/v34/LightInstallSourceInfoLiveData.kt
new file mode 100644
index 000000000..bbc62dfc9
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/v34/LightInstallSourceInfoLiveData.kt
@@ -0,0 +1,107 @@
+/*
+ * 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.permissioncontroller.permission.data.v34
+
+import android.app.Application
+import android.content.pm.InstallSourceInfo
+import android.content.pm.PackageManager
+import android.os.Process
+import android.os.UserHandle
+import android.util.Log
+import com.android.permissioncontroller.PermissionControllerApplication
+import com.android.permissioncontroller.permission.data.DataRepositoryForPackage
+import com.android.permissioncontroller.permission.data.PackageBroadcastReceiver
+import com.android.permissioncontroller.permission.data.SmartAsyncMediatorLiveData
+import com.android.permissioncontroller.permission.model.livedatatypes.v34.LightInstallSourceInfo
+import com.android.permissioncontroller.permission.model.livedatatypes.v34.LightInstallSourceInfo.Companion.INSTALL_SOURCE_UNAVAILABLE
+import kotlinx.coroutines.Job
+
+/**
+ * [LightInstallSourceInfo] [LiveData] for the specified package
+ *
+ * @param app current Application
+ * @param packageName name of the package to get InstallSourceInfo for
+ * @param user The user of the package
+ */
+class LightInstallSourceInfoLiveData
+private constructor(
+ private val app: Application,
+ private val packageName: String,
+ private val user: UserHandle
+) :
+ SmartAsyncMediatorLiveData<LightInstallSourceInfo>(),
+ PackageBroadcastReceiver.PackageBroadcastListener {
+
+ override fun onActive() {
+ super.onActive()
+ PackageBroadcastReceiver.addChangeCallback(packageName, this)
+ }
+
+ override fun onInactive() {
+ super.onInactive()
+ PackageBroadcastReceiver.removeChangeCallback(packageName, this)
+ }
+
+ /**
+ * Callback from the PackageBroadcastReceiver
+ *
+ * @param packageName the name of the package which was updated.
+ */
+ override fun onPackageUpdate(packageName: String) {
+ update()
+ }
+
+ override suspend fun loadDataAndPostValue(job: Job) {
+ if (job.isCancelled) {
+ return
+ }
+
+ val lightInstallSourceInfo: LightInstallSourceInfo =
+ try {
+ val installSourceInfo = getInstallSourceInfo(packageName)
+ LightInstallSourceInfo(
+ installSourceInfo.packageSource, installSourceInfo.initiatingPackageName)
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(LOG_TAG, "InstallSourceInfo for $packageName not found")
+ invalidateSingle(packageName to user)
+ INSTALL_SOURCE_UNAVAILABLE
+ }
+ postValue(lightInstallSourceInfo)
+ }
+
+ /** Returns the [InstallSourceInfo] for the given package. */
+ @Throws(PackageManager.NameNotFoundException::class)
+ private fun getInstallSourceInfo(packageName: String): InstallSourceInfo {
+ val userContext =
+ if (user == Process.myUserHandle()) {
+ app
+ } else {
+ app.createContextAsUser(user, /* flags= */ 0)
+ }
+ return userContext.packageManager.getInstallSourceInfo(packageName)
+ }
+
+ companion object :
+ DataRepositoryForPackage<Pair<String, UserHandle>, LightInstallSourceInfoLiveData>() {
+ private val LOG_TAG = LightInstallSourceInfoLiveData::class.java.simpleName
+
+ override fun newValue(key: Pair<String, UserHandle>): LightInstallSourceInfoLiveData {
+ return LightInstallSourceInfoLiveData(
+ 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
new file mode 100644
index 000000000..6229218d4
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/v34/SafetyLabelInfoLiveData.kt
@@ -0,0 +1,130 @@
+/*
+ * 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.permissioncontroller.permission.data.v34
+
+import android.app.Application
+import android.content.pm.PackageManager
+import android.os.Process
+import android.os.UserHandle
+import android.util.Log
+import com.android.permission.safetylabel.SafetyLabel
+import com.android.permissioncontroller.PermissionControllerApplication
+import com.android.permissioncontroller.permission.data.DataRepositoryForPackage
+import com.android.permissioncontroller.permission.data.PackageBroadcastReceiver
+import com.android.permissioncontroller.permission.data.SmartAsyncMediatorLiveData
+import com.android.permissioncontroller.permission.data.get
+import com.android.permissioncontroller.permission.model.livedatatypes.v34.SafetyLabelInfo
+import kotlinx.coroutines.Job
+
+/**
+ * [SafetyLabelInfo] [LiveData] for the specified package
+ *
+ * @param app current Application
+ * @param packageName name of the package to get SafetyLabel information for
+ * @param user The user of the package
+ */
+class SafetyLabelInfoLiveData
+private constructor(
+ private val app: Application,
+ private val packageName: String,
+ private val user: UserHandle
+) :
+ SmartAsyncMediatorLiveData<SafetyLabelInfo>(),
+ PackageBroadcastReceiver.PackageBroadcastListener {
+
+ private val lightInstallSourceInfoLiveData = LightInstallSourceInfoLiveData[packageName, user]
+
+ init {
+ addSource(lightInstallSourceInfoLiveData) { update() }
+
+ update()
+ }
+
+ override fun onActive() {
+ super.onActive()
+ PackageBroadcastReceiver.addChangeCallback(packageName, this)
+ }
+
+ override fun onInactive() {
+ super.onInactive()
+ PackageBroadcastReceiver.removeChangeCallback(packageName, this)
+ }
+
+ /**
+ * Callback from the PackageBroadcastReceiver
+ *
+ * @param packageName the name of the package which was updated.
+ */
+ override fun onPackageUpdate(packageName: String) {
+ update()
+ }
+
+ override suspend fun loadDataAndPostValue(job: Job) {
+ if (job.isCancelled) {
+ return
+ }
+
+ if (lightInstallSourceInfoLiveData.isStale) {
+ return
+ }
+
+ val lightInstallSourceInfo = lightInstallSourceInfoLiveData.value
+ if (lightInstallSourceInfo?.supportsSafetyLabel != true) {
+ postValue(SafetyLabelInfo.UNAVAILABLE)
+ return
+ }
+
+ val safetyLabelInfo: SafetyLabelInfo =
+ try {
+ val safetyLabel: SafetyLabel? = getSafetyLabel(packageName, user)
+ if (safetyLabel != null) {
+ SafetyLabelInfo(safetyLabel, lightInstallSourceInfo)
+ } else {
+ SafetyLabelInfo.UNAVAILABLE
+ }
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(LOG_TAG, "SafetyLabel for $packageName not found")
+ invalidateSingle(packageName to user)
+ SafetyLabelInfo.UNAVAILABLE
+ }
+ postValue(safetyLabelInfo)
+ }
+
+ /** Returns the [SafetyLabel] for the given package and user. */
+ @Throws(PackageManager.NameNotFoundException::class)
+ private fun getSafetyLabel(packageName: String, user: UserHandle): SafetyLabel? {
+ val userContext =
+ if (user == Process.myUserHandle()) {
+ app
+ } else {
+ app.createContextAsUser(user, /* flags= */ 0)
+ }
+
+ return SafetyLabel.getSafetyLabelFromMetadata(
+ userContext.packageManager.getAppMetadata(packageName))
+ }
+
+ companion object :
+ DataRepositoryForPackage<Pair<String, UserHandle>, SafetyLabelInfoLiveData>() {
+ private val LOG_TAG = SafetyLabelInfoLiveData::class.java.simpleName
+
+ override fun newValue(key: Pair<String, UserHandle>): SafetyLabelInfoLiveData {
+ return SafetyLabelInfoLiveData(
+ PermissionControllerApplication.get(), key.first, key.second)
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/v34/package-info.java b/PermissionController/src/com/android/permissioncontroller/permission/data/v34/package-info.java
new file mode 100644
index 000000000..8e1e624e2
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/v34/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+@androidx.annotation.RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+package com.android.permissioncontroller.permission.data.v34;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/AppPermissionGroup.java b/PermissionController/src/com/android/permissioncontroller/permission/model/AppPermissionGroup.java
index c03aef013..e096a1a7e 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/AppPermissionGroup.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/AppPermissionGroup.java
@@ -24,6 +24,9 @@ import static android.app.AppOpsManager.MODE_FOREGROUND;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OPSTR_LEGACY_STORAGE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP;
+
+import static com.android.permissioncontroller.permission.utils.Utils.isHealthPermissionUiEnabled;
import android.Manifest;
import android.app.ActivityManager;
@@ -55,6 +58,7 @@ import com.android.permissioncontroller.permission.service.LocationAccessCheck;
import com.android.permissioncontroller.permission.utils.ArrayUtils;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.LocationUtils;
+import com.android.permissioncontroller.permission.utils.PermissionMapping;
import com.android.permissioncontroller.permission.utils.SoftRestrictedPermissionPolicy;
import com.android.permissioncontroller.permission.utils.Utils;
@@ -147,6 +151,12 @@ public final class AppPermissionGroup implements Comparable<AppPermissionGroup>
*/
private boolean mTriggerLocationAccessCheckOnPersist;
+ /**
+ * Set if {@link LocationAccessCheck#cancelBackgroundAccessWarningNotification()} should be
+ * triggered to cancel the warning once the changes are persisted.
+ */
+ private boolean mCancelLocationAccessWarningOnRevoke;
+
private boolean mIsSelfRevoked;
/**
@@ -175,7 +185,7 @@ public final class AppPermissionGroup implements Comparable<AppPermissionGroup>
return null;
}
- String group = Utils.getGroupOfPermission(permissionInfo);
+ String group = PermissionMapping.getGroupOfPermission(permissionInfo);
PackageItemInfo groupInfo = permissionInfo;
if (group != null) {
try {
@@ -330,6 +340,8 @@ public final class AppPermissionGroup implements Comparable<AppPermissionGroup>
& PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
final String appOp = PLATFORM_PACKAGE_NAME.equals(requestedPermissionInfo.packageName)
+ || (isHealthPermissionUiEnabled() && HEALTH_PERMISSION_GROUP.equals(
+ requestedPermissionInfo.group))
? AppOpsManager.permissionToOp(requestedPermissionInfo.name) : null;
final boolean appOpAllowed;
@@ -1113,6 +1125,8 @@ public final class AppPermissionGroup implements Comparable<AppPermissionGroup>
break;
}
+ boolean wasGranted = permission.isGrantedIncludingAppOp();
+
if (mAppSupportsRuntimePermissions) {
// Revoke the permission if needed.
if (permission.isGranted()) {
@@ -1160,6 +1174,33 @@ public final class AppPermissionGroup implements Comparable<AppPermissionGroup>
}
}
}
+
+ // If we revoke background access to the fine location, we trigger a check to cancel
+ // the location access check notification to avoid stale warnings
+ if (wasGranted && !permission.isGrantedIncludingAppOp()) {
+ if (permission.getName().equals(ACCESS_FINE_LOCATION)) {
+ Permission bgPerm = permission.getBackgroundPermission();
+ if (bgPerm != null) {
+ if (!bgPerm.isGrantedIncludingAppOp()) {
+ mCancelLocationAccessWarningOnRevoke = true;
+ }
+ }
+ } else if (permission.getName().equals(ACCESS_BACKGROUND_LOCATION)) {
+ ArrayList<Permission> fgPerms = permission.getForegroundPermissions();
+ if (fgPerms != null) {
+ int numFgPerms = fgPerms.size();
+ for (int fgPermNum = 0; fgPermNum < numFgPerms; fgPermNum++) {
+ Permission fgPerm = fgPerms.get(fgPermNum);
+ if (fgPerm.getName().equals(ACCESS_FINE_LOCATION)) {
+ if (!fgPerm.isGrantedIncludingAppOp()) {
+ mCancelLocationAccessWarningOnRevoke = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
}
if (!mDelayChanges) {
@@ -1299,7 +1340,7 @@ public final class AppPermissionGroup implements Comparable<AppPermissionGroup>
* @return {@code true} iff this group supports one-time permissions
*/
public boolean supportsOneTimeGrant() {
- return Utils.supportsOneTimeGrant(getName());
+ return PermissionMapping.supportsOneTimeGrant(getName());
}
public int getFlags() {
@@ -1553,12 +1594,13 @@ public final class AppPermissionGroup implements Comparable<AppPermissionGroup>
// Enabling/Disabling an app op may put the app in a situation in which it has
// a handle to state it shouldn't have, so we have to kill the app. This matches
// the revoke runtime permission behavior.
+ boolean wasChanged;
if (permission.isAppOpAllowed()) {
- boolean wasChanged = allowAppOp(permission, uid);
- shouldKillApp |= wasChanged && !mAppSupportsRuntimePermissions;
+ wasChanged = allowAppOp(permission, uid);
} else {
- shouldKillApp |= disallowAppOp(permission, uid);
+ wasChanged = disallowAppOp(permission, uid);
}
+ shouldKillApp |= wasChanged && !mAppSupportsRuntimePermissions;
}
}
}
@@ -1572,6 +1614,12 @@ public final class AppPermissionGroup implements Comparable<AppPermissionGroup>
mTriggerLocationAccessCheckOnPersist = false;
}
+ if (mCancelLocationAccessWarningOnRevoke) {
+ new LocationAccessCheck(mContext, null).cancelBackgroundAccessWarningNotification(
+ mPackageInfo.packageName, mUserHandle, true);
+ mCancelLocationAccessWarningOnRevoke = false;
+ }
+
String packageName = mPackageInfo.packageName;
if (areRuntimePermissionsGranted(null, true, false)) {
// Required to read device config in Utils.getOneTimePermissions*().
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/legacy/PermissionApps.java b/PermissionController/src/com/android/permissioncontroller/permission/model/legacy/PermissionApps.java
index 53ba48ace..196bfc6af 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/legacy/PermissionApps.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/legacy/PermissionApps.java
@@ -38,8 +38,8 @@ import androidx.annotation.Nullable;
import com.android.modules.utils.build.SdkLevel;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.model.AppPermissionGroup;
-import com.android.permissioncontroller.permission.utils.SubattributionUtils;
import com.android.permissioncontroller.permission.utils.Utils;
+import com.android.permissioncontroller.permission.utils.v31.SubattributionUtils;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/legacy/PermissionGroups.java b/PermissionController/src/com/android/permissioncontroller/permission/model/legacy/PermissionGroups.java
index 39e4e9eef..78d0c760d 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/legacy/PermissionGroups.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/legacy/PermissionGroups.java
@@ -39,6 +39,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.permissioncontroller.R;
+import com.android.permissioncontroller.permission.utils.PermissionMapping;
import com.android.permissioncontroller.permission.utils.Utils;
import java.util.ArrayList;
@@ -186,7 +187,8 @@ public final class PermissionGroups implements LoaderCallbacks<List<PermissionGr
}
// Ignore non-platform permissions and the UNDEFINED group.
- if (!getNonPlatformPermissions && !Utils.isModernPermissionGroup(groupInfo.name)) {
+ if (!getNonPlatformPermissions
+ && !PermissionMapping.isPlatformPermissionGroup(groupInfo.name)) {
continue;
}
@@ -264,7 +266,7 @@ public final class PermissionGroups implements LoaderCallbacks<List<PermissionGr
}
// Ignore non-platform permissions and the UNDEFINED group.
- if (!getNonPlatformPermissions && !Utils.isModernPermissionGroup(
+ if (!getNonPlatformPermissions && !PermissionMapping.isPlatformPermissionGroup(
permissionInfo.name)) {
continue;
}
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 64d63bd1a..3c87f0b7a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightAppPermGroup.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightAppPermGroup.kt
@@ -42,8 +42,11 @@ data class LightAppPermGroup(
val hasInstallToRuntimeSplit: Boolean,
val specialLocationGrant: Boolean?
) {
- constructor(pI: LightPackageInfo, pGI: LightPermGroupInfo, perms: Map<String, LightPermission>):
- this(pI, pGI, perms, false, null)
+ constructor(
+ pI: LightPackageInfo,
+ pGI: LightPermGroupInfo,
+ perms: Map<String, LightPermission>
+ ) : this(pI, pGI, perms, false, null)
/**
* All unrestricted permissions. Usually restricted permissions are ignored
@@ -164,11 +167,14 @@ data class LightAppPermGroup(
val isRevokeWhenRequested = permissions.any { it.value.isRevokeWhenRequested }
/**
- * Whether a runtime permission request dialog must be shown on behalf of the app, rather than
- * the app requesting explicitly
+ * Whether any of this App Permission Groups permissions are fixed by the user
*/
- val isRuntimePermReviewRequired = supportsRuntimePerms &&
- permissions.any { it.value.isReviewRequired }
+ val isUserFixed = foreground.isUserFixed || background.isUserFixed
+
+ /**
+ * 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
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 2b9ee3702..0f6b6c000 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt
@@ -19,9 +19,11 @@ package com.android.permissioncontroller.permission.model.livedatatypes
import android.app.Application
import android.content.pm.ApplicationInfo
+import android.content.pm.Attribution
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.Utils
/**
@@ -47,28 +49,40 @@ data class LightPackageInfo(
val isInstantApp: Boolean,
val enabled: Boolean,
val appFlags: Int,
- val firstInstallTime: Long
+ val firstInstallTime: Long,
+ val lastUpdateTime: Long,
+ val areAttributionsUserVisible: Boolean,
+ val attributionTagsToLabels: Map<String, Int>
) {
- constructor(pI: PackageInfo) : this(pI.packageName,
+ constructor(
+ pI: PackageInfo
+ ) : this(
+ pI.packageName,
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.firstInstallTime)
+ 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())
- /**
- * 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) {
- grantedPermissions.add(requestedPermissions[i])
+ /** 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) {
+ grantedPermissions.add(requestedPermissions[i])
+ }
}
+ return grantedPermissions
}
- return grantedPermissions
- }
/**
* Gets the ApplicationInfo for this package from the system. Can be expensive if called too
@@ -76,34 +90,41 @@ data class LightPackageInfo(
*
* @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
+ * @return The ApplicationInfo corresponding to this package, with this UID, or null, if no such
+ * package exists
*/
fun getApplicationInfo(app: Application): ApplicationInfo? {
try {
val userContext = Utils.getUserContext(app, UserHandle.getUserHandleForUid(uid))
return userContext.packageManager.getApplicationInfo(packageName, 0)
- } catch (e: PackageManager.NameNotFoundException) {
- }
+ } catch (e: PackageManager.NameNotFoundException) {}
return null
}
/**
- * Gets the PackageInfo for this package from the system. Can be expensive if called too
- * often.
+ * Gets the PackageInfo for this package from the system. Can be expensive if called too often.
*
* @param app The current application, which will be used to get the PackageInfo
- *
- * @return The PackageInfo corresponding to this package, with this UID, or null, if no
- * such package exists
+ * @return The PackageInfo corresponding to this package, with this UID, or null, if no such
+ * package exists
*/
fun toPackageInfo(app: Application): PackageInfo? {
try {
val userContext = Utils.getUserContext(app, UserHandle.getUserHandleForUid(uid))
- return userContext.packageManager.getPackageInfo(packageName,
- PackageManager.GET_PERMISSIONS)
- } catch (e: PackageManager.NameNotFoundException) {
- }
+ return userContext.packageManager.getPackageInfo(
+ packageName, PackageManager.GET_PERMISSIONS)
+ } catch (e: PackageManager.NameNotFoundException) {}
return null
}
+
+ /** Companion object for [LightPackageInfo]. */
+ companion object {
+ /** Creates a mapping of attribution tag to labels from the provided attributions. */
+ fun buildAttributionTagsToLabelsMap(attributions: Array<Attribution>?): Map<String, Int> {
+ val attributionTagToLabel = mutableMapOf<String, Int>()
+ attributions?.forEach { attributionTagToLabel[it.tag] = it.label }
+
+ return attributionTagToLabel.toMap()
+ }
+ }
}
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 c3d087fd2..fd7d82dfc 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermission.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPermission.kt
@@ -16,11 +16,12 @@
package com.android.permissioncontroller.permission.model.livedatatypes
+import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.PermissionInfo
+import com.android.permissioncontroller.permission.utils.PermissionMapping.isRuntimePlatformPermission
import com.android.permissioncontroller.permission.utils.SoftRestrictedPermissionPolicy
import com.android.permissioncontroller.permission.utils.Utils
-import com.android.permissioncontroller.permission.utils.Utils.isRuntimePlatformPermission
/**
* Represents a single permission, and its state
@@ -71,6 +72,20 @@ data class LightPermission(
val isOneTime = flags and PackageManager.FLAG_PERMISSION_ONE_TIME != 0
/** Whether this permission is an instant app permission */
val isInstantPerm = permInfo.protectionFlags and PermissionInfo.PROTECTION_FLAG_INSTANT != 0
+ /** Whether this permission is implicitly added to the package */
+ 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
+ ) {
+ implicit = true
+ break
+ }
+ }
+ implicit
+ }
/** Whether this permission is a runtime only permission */
val isRuntimeOnly =
permInfo.protectionFlags and PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY != 0
@@ -124,4 +139,4 @@ data class LightPermission(
if (isAutoRevoked) append(", AutoRevoked")
if (isSelectedLocationAccuracy) append(", SelectedLocationAccuracy")
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/AppPermissionId.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/AppPermissionId.kt
new file mode 100644
index 000000000..061bcb8a3
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/AppPermissionId.kt
@@ -0,0 +1,10 @@
+package com.android.permissioncontroller.permission.model.livedatatypes.v31
+
+import android.os.UserHandle
+
+/** Identifier for an app permission group combination. */
+data class AppPermissionId(
+ val packageName: String,
+ val userHandle: UserHandle,
+ val permissionGroup: String,
+)
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
new file mode 100644
index 000000000..4c2051f9c
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightHistoricalPackageOps.kt
@@ -0,0 +1,229 @@
+/*
+ * 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.permissioncontroller.permission.model.livedatatypes.v31
+
+import android.app.AppOpsManager.AttributedHistoricalOps
+import android.app.AppOpsManager.AttributedOpEntry
+import android.app.AppOpsManager.HistoricalOp
+import android.app.AppOpsManager.HistoricalPackageOps
+import android.app.AppOpsManager.OP_FLAG_SELF
+import android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED
+import android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXY
+import android.app.AppOpsManager.OpEventProxyInfo
+import android.os.UserHandle
+import com.android.permissioncontroller.permission.utils.PermissionMapping.getPlatformPermissionGroupForOp
+
+/**
+ * Light version of [HistoricalPackageOps] class, tracking the last permission access for system
+ * permission groups.
+ */
+data class LightHistoricalPackageOps(
+ /** Name of the package. */
+ val packageName: String,
+ /** [UserHandle] running the package. */
+ val userHandle: UserHandle,
+ /**
+ * Data about permission accesses, one [AppPermissionDiscreteAccesses] for each permission
+ * group.
+ */
+ // TODO(b/262042582): Consider removing this field and using attributed accesses aggregated over
+ // attribution tags instead.
+ val appPermissionDiscreteAccesses: List<AppPermissionDiscreteAccesses>,
+ /**
+ * Attributed data about permission accesses, one [AttributedAppPermissionDiscreteAccesses] for
+ * each permission group.
+ */
+ val attributedAppPermissionDiscreteAccesses: List<AttributedAppPermissionDiscreteAccesses>
+) {
+ constructor(
+ historicalPackageOps: HistoricalPackageOps,
+ userHandle: UserHandle,
+ opNames: Set<String>
+ ) : this(
+ historicalPackageOps.packageName,
+ userHandle,
+ historicalPackageOps.getAppPermissionDiscreteAccesses(userHandle, opNames),
+ historicalPackageOps.getAttributedAppPermissionDiscreteAccesses(userHandle, opNames),
+ )
+
+ /** Companion object for [LightHistoricalPackageOps]. */
+ companion object {
+ /** String to represent the absence of an attribution tag. */
+ const val NO_ATTRIBUTION_TAG = "no_attribution_tag"
+ /** String to represent the absence of a permission group. */
+ private const val NO_PERM_GROUP = "no_perm_group"
+ private const val DISCRETE_ACCESS_OP_FLAGS =
+ OP_FLAG_SELF or OP_FLAG_TRUSTED_PROXIED or OP_FLAG_TRUSTED_PROXY
+
+ /**
+ * Creates a list of [AppPermissionDiscreteAccesses] for the provided package, user and ops.
+ */
+ private fun HistoricalPackageOps.getAppPermissionDiscreteAccesses(
+ userHandle: UserHandle,
+ opNames: Set<String>
+ ): List<AppPermissionDiscreteAccesses> {
+ val permissionsToOpNames = partitionOpsByPermission(opNames)
+ val appPermissionDiscreteAccesses = mutableListOf<AppPermissionDiscreteAccesses>()
+ for (permissionToOpNames in permissionsToOpNames.entries) {
+ this.getDiscreteAccesses(permissionToOpNames.value)?.let {
+ appPermissionDiscreteAccesses.add(
+ AppPermissionDiscreteAccesses(
+ AppPermissionId(packageName, userHandle, permissionToOpNames.key), it))
+ }
+ }
+
+ return appPermissionDiscreteAccesses
+ }
+
+ /**
+ * Creates a list of [AttributedAppPermissionDiscreteAccesses] for the provided package,
+ * user and ops.
+ */
+ private fun HistoricalPackageOps.getAttributedAppPermissionDiscreteAccesses(
+ userHandle: UserHandle,
+ opNames: Set<String>
+ ): List<AttributedAppPermissionDiscreteAccesses> {
+ val permissionsToOpNames = partitionOpsByPermission(opNames)
+ val attributedAppPermissionDiscreteAccesses =
+ mutableMapOf<AppPermissionId, MutableMap<String, List<DiscreteAccess>>>()
+
+ val attributedHistoricalOpsList = mutableListOf<AttributedHistoricalOps>()
+ for (i in 0 until attributedOpsCount) {
+ attributedHistoricalOpsList.add(getAttributedOpsAt(i))
+ }
+
+ for (permissionToOpNames in permissionsToOpNames.entries) {
+ attributedHistoricalOpsList.forEach { attributedHistoricalOps ->
+ attributedHistoricalOps.getDiscreteAccesses(permissionToOpNames.value)?.let {
+ discAccessData ->
+ val appPermissionId =
+ AppPermissionId(packageName, userHandle, permissionToOpNames.key)
+ if (!attributedAppPermissionDiscreteAccesses.containsKey(appPermissionId)) {
+ attributedAppPermissionDiscreteAccesses[appPermissionId] =
+ mutableMapOf()
+ }
+ attributedAppPermissionDiscreteAccesses[appPermissionId]?.put(
+ attributedHistoricalOps.tag ?: NO_ATTRIBUTION_TAG, discAccessData)
+ }
+ }
+ }
+
+ return attributedAppPermissionDiscreteAccesses.map {
+ AttributedAppPermissionDiscreteAccesses(it.key, it.value)
+ }
+ }
+
+ /**
+ * Retrieves all discrete accesses for the provided op names, if any.
+ *
+ * Returns null if there are no accesses.
+ */
+ private fun HistoricalPackageOps.getDiscreteAccesses(
+ opNames: List<String>
+ ): List<DiscreteAccess>? {
+ if (opCount == 0) {
+ return null
+ }
+
+ val historicalOps = mutableListOf<HistoricalOp>()
+ for (opName in opNames) {
+ getOp(opName)?.let { historicalOps.add(it) }
+ }
+
+ val discreteAccessList = mutableListOf<DiscreteAccess>()
+ historicalOps.forEach {
+ for (i in 0 until it.discreteAccessCount) {
+ val opEntry: AttributedOpEntry = it.getDiscreteAccessAt(i)
+ discreteAccessList.add(
+ DiscreteAccess(
+ opEntry.getLastAccessTime(DISCRETE_ACCESS_OP_FLAGS),
+ opEntry.getLastDuration(DISCRETE_ACCESS_OP_FLAGS),
+ opEntry.getLastProxyInfo(DISCRETE_ACCESS_OP_FLAGS)))
+ }
+ }
+
+ if (discreteAccessList.isEmpty()) {
+ return null
+ }
+ return discreteAccessList.sortedWith(compareBy { -it.accessTimeMs })
+ }
+
+ /**
+ * Retrieves all discrete accesses for the provided op names, if any.
+ *
+ * Returns null if there are no accesses.
+ */
+ private fun AttributedHistoricalOps.getDiscreteAccesses(
+ opNames: List<String>
+ ): List<DiscreteAccess>? {
+ if (opCount == 0) {
+ return null
+ }
+
+ val historicalOps = mutableListOf<HistoricalOp>()
+ for (opName in opNames) {
+ getOp(opName)?.let { historicalOps.add(it) }
+ }
+
+ val discreteAccessList = mutableListOf<DiscreteAccess>()
+ historicalOps.forEach {
+ for (i in 0 until it.discreteAccessCount) {
+ val attributedOpEntry: AttributedOpEntry = it.getDiscreteAccessAt(i)
+ discreteAccessList.add(
+ DiscreteAccess(
+ attributedOpEntry.getLastAccessTime(DISCRETE_ACCESS_OP_FLAGS),
+ attributedOpEntry.getLastDuration(DISCRETE_ACCESS_OP_FLAGS),
+ attributedOpEntry.getLastProxyInfo(DISCRETE_ACCESS_OP_FLAGS)))
+ }
+ }
+
+ if (discreteAccessList.isEmpty()) {
+ return null
+ }
+ return discreteAccessList.sortedWith(compareBy { -it.accessTimeMs })
+ }
+
+ private fun partitionOpsByPermission(ops: Set<String>): Map<String, List<String>> =
+ ops.groupBy { getPlatformPermissionGroupForOp(it) ?: NO_PERM_GROUP }
+ .filter { it.key != NO_PERM_GROUP }
+ }
+
+ /**
+ * Data class representing permissions accesses for a particular permission group by a
+ * particular package and user.
+ */
+ data class AppPermissionDiscreteAccesses(
+ val appPermissionId: AppPermissionId,
+ val discreteAccesses: List<DiscreteAccess>
+ )
+
+ /**
+ * Data class representing permissions accesses for a particular permission group by a
+ * particular package and user, partitioned by attribution tag.
+ */
+ data class AttributedAppPermissionDiscreteAccesses(
+ val appPermissionId: AppPermissionId,
+ val attributedDiscreteAccesses: Map<String, List<DiscreteAccess>>
+ )
+
+ /** Data class representing a discrete permission access. */
+ data class DiscreteAccess(
+ val accessTimeMs: Long,
+ val accessDurationMs: Long,
+ val proxy: OpEventProxyInfo?
+ )
+}
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
new file mode 100644
index 000000000..dde4857e2
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/LightPackageOps.kt
@@ -0,0 +1,79 @@
+/*
+ * 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.permissioncontroller.permission.model.livedatatypes.v31
+
+import android.app.AppOpsManager.OP_FLAG_SELF
+import android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED
+import android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXY
+import android.app.AppOpsManager.PackageOps
+import android.os.UserHandle
+import com.android.permissioncontroller.permission.utils.PermissionMapping.getPlatformPermissionGroupForOp
+
+/**
+ * Light version of [PackageOps] class, tracking the last permission access for system permission
+ * groups.
+ */
+data class LightPackageOps(
+ /** Name of the package. */
+ val packageName: String,
+ /** [UserHandle] running the package. */
+ val userHandle: UserHandle,
+ /**
+ * Mapping of permission group name to the last access time of any op backing a permission in
+ * the group.
+ */
+ val lastPermissionGroupAccessTimesMs: Map<String, Long>
+) {
+ constructor(
+ ops: Set<String>,
+ packageOps: PackageOps
+ ) : this(
+ packageOps.packageName,
+ UserHandle.getUserHandleForUid(packageOps.uid),
+ createLastPermissionGroupAccessTimesMap(ops, packageOps))
+
+ /** Companion object for [LightPackageOps]. */
+ companion object {
+ /** Flags to use for querying an op's last access time. */
+ private const val OPS_LAST_ACCESS_FLAGS =
+ OP_FLAG_SELF or OP_FLAG_TRUSTED_PROXIED or OP_FLAG_TRUSTED_PROXY
+
+ /** Creates a mapping from permission group to the last time it was accessed. */
+ private fun createLastPermissionGroupAccessTimesMap(
+ opNames: Set<String>,
+ packageOps: PackageOps
+ ): Map<String, Long> {
+ val lastAccessTimeMs = mutableMapOf<String, Long>()
+ // Add keys for all permissions groups covered by the provided ops, regardless of
+ // whether they have been observed recently.
+ for (permissionGroup in
+ opNames.mapNotNull { getPlatformPermissionGroupForOp(it) }.toSet()) {
+ lastAccessTimeMs[permissionGroup] = -1
+ }
+
+ for (opEntry in packageOps.ops) {
+ val permissionGroupOfOp = getPlatformPermissionGroupForOp(opEntry.opStr) ?: continue
+ lastAccessTimeMs[permissionGroupOfOp] =
+ maxOf(
+ lastAccessTimeMs[permissionGroupOfOp] ?: -1,
+ opEntry.getLastAccessTime(OPS_LAST_ACCESS_FLAGS))
+ }
+
+ return lastAccessTimeMs
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/package-info.java b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/package-info.java
new file mode 100644
index 000000000..b724ba43f
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v31/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+@androidx.annotation.RequiresApi(android.os.Build.VERSION_CODES.S)
+package com.android.permissioncontroller.permission.model.livedatatypes.v31;
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
new file mode 100644
index 000000000..e75c1eadf
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v34/LightInstallSourceInfo.kt
@@ -0,0 +1,61 @@
+/*
+ * 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.permissioncontroller.permission.model.livedatatypes.v34
+
+import android.content.pm.PackageInstaller.PACKAGE_SOURCE_STORE
+import android.content.pm.PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED
+
+/**
+ * A lighter version of the system's InstallSourceInfo class, containing select information about
+ * the install source.
+ */
+class LightInstallSourceInfo {
+ private constructor() {
+ initiatingPackageName = null
+ isPreloadedApp = false
+ supportsSafetyLabel = false
+ }
+
+ constructor(packageSource: Int, initiatingPackage: String?) {
+ initiatingPackageName = initiatingPackage
+ // Stores should be setting PACKAGE_SOURCE_STORE, but it's not enforced. So include the
+ // 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)
+
+ isPreloadedApp = initiatingPackageName == null &&
+ packageSource == PACKAGE_SOURCE_UNSPECIFIED
+ supportsSafetyLabel = isStoreInstalled || isPreloadedApp
+ }
+
+ /** The package name of the install source (usually the app store) */
+ val initiatingPackageName: String?
+
+ /** Whether packages from this install source support safety labels. */
+ val supportsSafetyLabel: Boolean
+
+ /** Whether this install source indicates that the package was preloaded onto the device. */
+ val isPreloadedApp: Boolean
+
+ companion object {
+ /** Indicates an unavailable install source. */
+ val INSTALL_SOURCE_UNAVAILABLE = LightInstallSourceInfo()
+ }
+}
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
new file mode 100644
index 000000000..7128e3069
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v34/SafetyLabelInfo.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.permissioncontroller.permission.model.livedatatypes.v34
+
+import com.android.permission.safetylabel.SafetyLabel
+import com.android.permissioncontroller.permission.model.livedatatypes.v34.LightInstallSourceInfo.Companion.INSTALL_SOURCE_UNAVAILABLE
+
+/**
+ * A wrapping class for [SafetyLabel] class that includes the install source package name
+ *
+ * @param safetyLabel the resulting [SafetyLabel], or null if none found
+ * @param installSourceInfo the install source information for the package
+ */
+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/model/livedatatypes/v34/package-info.java b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v34/package-info.java
new file mode 100644
index 000000000..8d4e3e60b
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/v34/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+@androidx.annotation.RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+package com.android.permissioncontroller.permission.model.livedatatypes.v34;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/v31/AppPermissionUsage.java b/PermissionController/src/com/android/permissioncontroller/permission/model/v31/AppPermissionUsage.java
index 0bd61be15..b7cddace2 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/v31/AppPermissionUsage.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/v31/AppPermissionUsage.java
@@ -125,16 +125,6 @@ public final class AppPermissionUsage {
return lastAccessTime;
}
- public long getAccessCount() {
- long accessCount = 0;
- final int permissionCount = mGroupUsages.size();
- for (int i = 0; i < permissionCount; i++) {
- final GroupUsage permission = mGroupUsages.get(i);
- accessCount += permission.getAccessCount();
- }
- return accessCount;
- }
-
public @NonNull List<GroupUsage> getGroupUsages() {
return mGroupUsages;
}
@@ -163,62 +153,6 @@ public final class AppPermissionUsage {
return lastAccessAggregate((op) -> op.getLastAccessTime(PRIVACY_HUB_FLAGS));
}
- public long getLastAccessForegroundTime() {
- if (mLastUsage == null) {
- return 0;
- }
-
- return lastAccessAggregate((op) -> op.getLastAccessForegroundTime(PRIVACY_HUB_FLAGS));
- }
-
- public long getLastAccessBackgroundTime() {
- if (mLastUsage == null) {
- return 0;
- }
-
- return lastAccessAggregate((op) -> op.getLastAccessBackgroundTime(PRIVACY_HUB_FLAGS));
- }
-
- public long getForegroundAccessCount() {
- if (mHistoricalUsage == null) {
- return 0;
- }
-
- return extractAggregate((HistoricalOp op)
- -> op.getForegroundAccessCount(PRIVACY_HUB_FLAGS));
- }
-
- public long getBackgroundAccessCount() {
- if (mHistoricalUsage == null) {
- return 0;
- }
-
- return extractAggregate((HistoricalOp op)
- -> op.getBackgroundAccessCount(PRIVACY_HUB_FLAGS));
- }
-
- public long getAccessCount() {
- if (mHistoricalUsage == null) {
- return 0;
- }
-
- return extractAggregate((HistoricalOp op) ->
- op.getForegroundAccessCount(PRIVACY_HUB_FLAGS)
- + op.getBackgroundAccessCount(PRIVACY_HUB_FLAGS)
- );
- }
-
- /**
- * Get the last access duration.
- */
- public long getLastAccessDuration() {
- if (mLastUsage == null) {
- return 0;
- }
- return lastAccessAggregate(
- (op) -> op.getLastDuration(AppOpsManager.OP_FLAGS_ALL_TRUSTED));
- }
-
/**
* Get the access duration.
*/
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/v31/PermissionUsages.java b/PermissionController/src/com/android/permissioncontroller/permission/model/v31/PermissionUsages.java
index a8044796a..03c9ce584 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/v31/PermissionUsages.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/v31/PermissionUsages.java
@@ -20,8 +20,10 @@ import static android.Manifest.permission.CAMERA;
import static android.Manifest.permission.RECORD_AUDIO;
import static android.app.AppOpsManager.OPSTR_PHONE_CALL_CAMERA;
import static android.app.AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE;
+import static android.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP;
import static com.android.permissioncontroller.Constants.OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO;
+import static com.android.permissioncontroller.permission.utils.Utils.isHealthPermissionUiEnabled;
import android.app.AppOpsManager;
import android.app.AppOpsManager.HistoricalOps;
@@ -233,7 +235,9 @@ public final class PermissionUsages implements LoaderCallbacks<List<AppPermissio
for (int groupIdx = 0; groupIdx < groupCount; groupIdx++) {
final PermissionGroup group = groups.get(groupIdx);
// Filter out third party permissions
- if (!group.getDeclaringPackage().equals(Utils.OS_PKG)) {
+ if (!(group.getDeclaringPackage().equals(Utils.OS_PKG)
+ || (isHealthPermissionUiEnabled() && HEALTH_PERMISSION_GROUP.equals(
+ group.getName())))) {
continue;
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/v34/AppDataSharingUpdate.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/v34/AppDataSharingUpdate.kt
new file mode 100644
index 000000000..2f6d921f8
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/v34/AppDataSharingUpdate.kt
@@ -0,0 +1,106 @@
+/*
+ * 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.permissioncontroller.permission.model.v34
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import com.android.permission.safetylabel.DataCategoryConstants.CATEGORY_LOCATION
+import com.android.permissioncontroller.permission.model.v34.DataSharingUpdateType.ADDS_ADVERTISING_PURPOSE
+import com.android.permissioncontroller.permission.model.v34.DataSharingUpdateType.ADDS_SHARING_WITHOUT_ADVERTISING_PURPOSE
+import com.android.permissioncontroller.permission.model.v34.DataSharingUpdateType.ADDS_SHARING_WITH_ADVERTISING_PURPOSE
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.AppSafetyLabelDiff
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.SafetyLabel
+
+/**
+ * Class representing a significant update in an app's data sharing policy from its safety label.
+ *
+ * Note that safety labels are part of package information, and therefore the safety label
+ * information applies to apps for all users that have the app installed.
+ */
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+data class AppDataSharingUpdate(
+ /** Package name for the app with the data sharing update. */
+ val packageName: String,
+ /** How data sharing for each category has changed. */
+ val categorySharingUpdates: Map<String, DataSharingUpdateType>
+) {
+
+ /** Companion object for [AppDataSharingUpdate]. */
+ companion object {
+ /**
+ * Builds and returns an [AppDataSharingUpdate] from an [AppSafetyLabelDiff], if the change
+ * in safety labels is significant, else returns null.
+ */
+ fun AppSafetyLabelDiff.buildUpdateIfSignificantChange(): AppDataSharingUpdate? {
+ // In Android U, only updates for the location data category will be displayed in
+ // the UI.
+ val updates = getUpdatesForCategories(listOf(CATEGORY_LOCATION))
+
+ return if (updates.isEmpty()) null
+ else AppDataSharingUpdate(safetyLabelBefore.appInfo.packageName, updates)
+ }
+
+ private fun AppSafetyLabelDiff.getUpdatesForCategories(
+ categories: List<String>
+ ): Map<String, DataSharingUpdateType> {
+ val categoryUpdateMap = mutableMapOf<String, DataSharingUpdateType>()
+
+ for (category in categories) {
+ var categoryUpdateType: DataSharingUpdateType?
+
+ val beforeSharesData = safetyLabelBefore.sharesData(category)
+ val beforeSharesDataForAds = safetyLabelBefore.sharesDataForAdsPurpose(category)
+ val afterSharesData = safetyLabelAfter.sharesData(category)
+ val afterSharesDataForAds = safetyLabelAfter.sharesDataForAdsPurpose(category)
+
+ categoryUpdateType =
+ when {
+ !beforeSharesData && afterSharesDataForAds ->
+ ADDS_SHARING_WITH_ADVERTISING_PURPOSE
+ !beforeSharesData && afterSharesData && !afterSharesDataForAds ->
+ ADDS_SHARING_WITHOUT_ADVERTISING_PURPOSE
+ beforeSharesData && !beforeSharesDataForAds && afterSharesDataForAds ->
+ ADDS_ADVERTISING_PURPOSE
+ else -> null
+ }
+
+ if (categoryUpdateType == null) {
+ continue
+ }
+
+ categoryUpdateMap[category] = categoryUpdateType
+ }
+
+ return categoryUpdateMap
+ }
+
+ private fun SafetyLabel.sharesData(category: String) =
+ dataLabel.dataShared.containsKey(category)
+
+ private fun SafetyLabel.sharesDataForAdsPurpose(category: String) =
+ dataLabel.dataShared[category]?.containsAdvertisingPurpose ?: false
+ }
+}
+
+/**
+ * Different ways in which data sharing can be significantly updated for a particular data category.
+ */
+enum class DataSharingUpdateType {
+ ADDS_ADVERTISING_PURPOSE,
+ ADDS_SHARING_WITHOUT_ADVERTISING_PURPOSE,
+ ADDS_SHARING_WITH_ADVERTISING_PURPOSE
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/AutoRevokePermissions.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/AutoRevokePermissions.kt
index 92596409c..ae9ccf19e 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/AutoRevokePermissions.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/AutoRevokePermissions.kt
@@ -31,13 +31,14 @@ import com.android.permissioncontroller.DumpableLog
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.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.Utils
import com.android.permissioncontroller.permission.utils.application
import com.android.permissioncontroller.permission.utils.forEachInParallel
import com.android.permissioncontroller.permission.utils.updatePermissionFlags
@@ -77,12 +78,23 @@ suspend fun revokeAppPermissions(
continue
}
+ val pkgPermChanges = PermissionChangeStorageImpl.getInstance().loadEvents()
+ .associateBy { it.packageName }
// For each autorevoke-eligible app...
userApps.forEachInParallel(Main) forEachInParallelOuter@ { pkg: LightPackageInfo ->
if (pkg.grantedPermissions.isEmpty()) {
return@forEachInParallelOuter
}
val packageName = pkg.packageName
+ val pkgPermChange = pkgPermChanges[packageName]
+ 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")
+ }
+ return@forEachInParallelOuter
+ }
val targetSdk = pkg.targetSdkVersion
val pkgPermGroups: Map<String, List<String>> =
PackagePermissionsLiveData[packageName, user]
@@ -94,7 +106,7 @@ suspend fun revokeAppPermissions(
if (groupName == PackagePermissionsLiveData.NON_RUNTIME_NORMAL_PERMS) {
continue
}
- if (groupName !in Utils.getPlatformPermissionGroups()) {
+ if (groupName !in PermissionMapping.getPlatformPermissionGroups()) {
continue
}
val group: LightAppPermGroup =
@@ -160,7 +172,8 @@ suspend fun revokeAppPermissions(
for (permName in revocablePermissions) {
PermissionControllerStatsLog.write(
PERMISSION_GRANT_REQUEST_RESULT_REPORTED,
- sessionId, uid, packageName, permName, false, SERVER_LOG_ID)
+ sessionId, uid, packageName, permName, false, SERVER_LOG_ID,
+ /* permission_rationale_shown = */ false)
}
if (DEBUG_AUTO_REVOKE) {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/v33/BasePermissionEventStorage.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/BasePermissionEventStorage.kt
index 9ed94002a..840b7e483 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/v33/BasePermissionEventStorage.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/BasePermissionEventStorage.kt
@@ -14,16 +14,14 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.service.v33
+package com.android.permissioncontroller.permission.service
import android.app.job.JobScheduler
import android.content.Context
-import android.os.Build
import android.util.AtomicFile
import android.util.Log
-import androidx.annotation.RequiresApi
import com.android.permissioncontroller.DumpableLog
-import com.android.permissioncontroller.permission.data.v33.PermissionEvent
+import com.android.permissioncontroller.permission.data.PermissionEvent
import org.xmlpull.v1.XmlPullParserException
import java.io.File
import java.io.FileOutputStream
@@ -35,7 +33,6 @@ import java.io.OutputStream
* Thread-safe implementation of [PermissionEventStorage] using an XML file as the
* database.
*/
-@RequiresApi(Build.VERSION_CODES.TIRAMISU)
abstract class BasePermissionEventStorage<T : PermissionEvent>(
private val context: Context,
jobScheduler: JobScheduler = context.getSystemService(JobScheduler::class.java)!!
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/LocationAccessCheck.java b/PermissionController/src/com/android/permissioncontroller/permission/service/LocationAccessCheck.java
index d1d6c03bc..e21be6a05 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/LocationAccessCheck.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/LocationAccessCheck.java
@@ -23,10 +23,10 @@ import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_ONE_SHOT;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
-import static android.app.PendingIntent.getBroadcast;
import static android.app.job.JobScheduler.RESULT_SUCCESS;
import static android.content.Context.MODE_PRIVATE;
import static android.content.Intent.ACTION_MANAGE_APP_PERMISSION;
+import static android.content.Intent.ACTION_SAFETY_CENTER;
import static android.content.Intent.EXTRA_PACKAGE_NAME;
import static android.content.Intent.EXTRA_PERMISSION_GROUP_NAME;
import static android.content.Intent.EXTRA_UID;
@@ -53,9 +53,16 @@ import static com.android.permissioncontroller.Constants.PERIODIC_LOCATION_ACCES
import static com.android.permissioncontroller.Constants.PERMISSION_REMINDER_CHANNEL_ID;
import static com.android.permissioncontroller.Constants.PREFERENCES_FILE;
import static com.android.permissioncontroller.PermissionControllerStatsLog.LOCATION_ACCESS_CHECK_NOTIFICATION_ACTION;
-import static com.android.permissioncontroller.PermissionControllerStatsLog.LOCATION_ACCESS_CHECK_NOTIFICATION_ACTION__RESULT__NOTIFICATION_CLICKED;
import static com.android.permissioncontroller.PermissionControllerStatsLog.LOCATION_ACCESS_CHECK_NOTIFICATION_ACTION__RESULT__NOTIFICATION_DECLINED;
import static com.android.permissioncontroller.PermissionControllerStatsLog.LOCATION_ACCESS_CHECK_NOTIFICATION_ACTION__RESULT__NOTIFICATION_PRESENTED;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__ACTION__CARD_DISMISSED;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__ACTION__CLICKED_CTA1;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__PRIVACY_SOURCE__BG_LOCATION;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_NOTIFICATION_INTERACTION;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__ACTION__DISMISSED;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__ACTION__NOTIFICATION_SHOWN;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__PRIVACY_SOURCE__BG_LOCATION;
import static com.android.permissioncontroller.permission.utils.Utils.OS_PKG;
import static com.android.permissioncontroller.permission.utils.Utils.getParcelableExtraSafe;
import static com.android.permissioncontroller.permission.utils.Utils.getParentUserContext;
@@ -71,6 +78,7 @@ import android.app.AppOpsManager.PackageOps;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
@@ -86,25 +94,39 @@ import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.location.LocationManager;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.DeviceConfig;
import android.provider.Settings;
+import android.safetycenter.SafetyCenterManager;
+import android.safetycenter.SafetyEvent;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceIssue;
+import android.safetycenter.SafetySourceIssue.Action;
import android.service.notification.StatusBarNotification;
+import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import androidx.annotation.ChecksSdkIntAtLeast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import androidx.annotation.WorkerThread;
import androidx.core.util.Preconditions;
+import com.android.modules.utils.build.SdkLevel;
import com.android.permissioncontroller.PermissionControllerStatsLog;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.model.AppPermissionGroup;
+import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.Utils;
import java.io.BufferedReader;
@@ -115,9 +137,12 @@ import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Random;
+import java.util.Set;
import java.util.function.BooleanSupplier;
+import java.util.stream.Collectors;
/**
* Show notification that double-guesses the user if she/he really wants to grant fine background
@@ -136,8 +161,36 @@ import java.util.function.BooleanSupplier;
public class LocationAccessCheck {
private static final String LOG_TAG = LocationAccessCheck.class.getSimpleName();
private static final boolean DEBUG = false;
+ private static final long DEFAULT_RENOTIFY_DURATION_MILLIS = DAYS.toMillis(90);
+ private static final String ISSUE_ID_PREFIX = "bg_location_";
+ private static final String ISSUE_TYPE_ID = "bg_location_privacy_issue";
+ private static final String REVOKE_LOCATION_ACCESS_ID_PREFIX = "revoke_location_access_";
+ private static final String VIEW_LOCATION_ACCESS_ID = "view_location_access";
+ public static final String BG_LOCATION_SOURCE_ID = "AndroidBackgroundLocation";
- /** Lock required for all methods called {@code ...Locked} */
+ /**
+ * Device config property for delay in milliseconds
+ * between granting a permission and the follow up check
+ **/
+ public static final String PROPERTY_LOCATION_ACCESS_CHECK_DELAY_MILLIS =
+ "location_access_check_delay_millis";
+
+ /**
+ * Device config property for delay in milliseconds
+ * between periodic checks for background location access
+ **/
+ public static final String PROPERTY_LOCATION_ACCESS_PERIODIC_INTERVAL_MILLIS =
+ "location_access_check_periodic_interval_millis";
+
+ /**
+ * Device config property for flag that determines whether location check for safety center
+ * is enabled.
+ */
+ public static final String PROPERTY_BG_LOCATION_CHECK_ENABLED = "bg_location_check_is_enabled";
+
+ /**
+ * Lock required for all methods called {@code ...Locked}
+ */
private static final Object sLock = new Object();
private final Random mRandom = new Random();
@@ -150,7 +203,9 @@ public class LocationAccessCheck {
private final @NonNull UserManager mUserManager;
private final @NonNull SharedPreferences mSharedPrefs;
- /** If the current long running operation should be canceled */
+ /**
+ * If the current long running operation should be canceled
+ */
private final @Nullable BooleanSupplier mShouldCancel;
/**
@@ -161,8 +216,10 @@ public class LocationAccessCheck {
* @return The time in between check in milliseconds
*/
private long getPeriodicCheckIntervalMillis() {
- return Settings.Secure.getLong(mContentResolver,
- LOCATION_ACCESS_CHECK_INTERVAL_MILLIS, DAYS.toMillis(1));
+ return SdkLevel.isAtLeastT() ? DeviceConfig.getLong(DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_LOCATION_ACCESS_PERIODIC_INTERVAL_MILLIS, DAYS.toMillis(1))
+ : Settings.Secure.getLong(mContentResolver,
+ LOCATION_ACCESS_CHECK_INTERVAL_MILLIS, DAYS.toMillis(1));
}
/**
@@ -184,8 +241,10 @@ public class LocationAccessCheck {
* @return The delay in milliseconds
*/
private long getDelayMillis() {
- return Settings.Secure.getLong(mContentResolver,
- LOCATION_ACCESS_CHECK_DELAY_MILLIS, DAYS.toMillis(1));
+ return SdkLevel.isAtLeastT() ? DeviceConfig.getLong(DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_LOCATION_ACCESS_CHECK_DELAY_MILLIS, DAYS.toMillis(1))
+ : Settings.Secure.getLong(mContentResolver, LOCATION_ACCESS_CHECK_DELAY_MILLIS,
+ DAYS.toMillis(1));
}
/**
@@ -206,34 +265,38 @@ public class LocationAccessCheck {
*/
private @NonNull ArraySet<UserPackage> loadAlreadyNotifiedPackagesLocked() {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
- mContext.openFileInput(LOCATION_ACCESS_CHECK_ALREADY_NOTIFIED_FILE)))) {
+ mContext.openFileInput(LOCATION_ACCESS_CHECK_ALREADY_NOTIFIED_FILE)))) {
ArraySet<UserPackage> packages = new ArraySet<>();
/*
- * The format of the file is <package> <serial of user>, e.g.
+ * The format of the file is <package> <serial of user> <dismissed in safety center>,
+ * Since notification timestamp was added later it is possible that it might be
+ * missing during the first check. We need to handle that.
*
- * com.one.package 5630633845
- * com.two.package 5630633853
- * com.three.package 5630633853
+ * e.g.
+ * com.one.package 5630633845 true
+ * com.two.package 5630633853 false
+ * com.three.package 5630633853 false
*/
while (true) {
String line = reader.readLine();
if (line == null) {
break;
}
-
String[] lineComponents = line.split(" ");
String pkg = lineComponents[0];
UserHandle user = mUserManager.getUserForSerialNumber(
Long.valueOf(lineComponents[1]));
-
+ boolean dismissedInSafetyCenter = lineComponents.length == 3
+ ? Boolean.valueOf(lineComponents[2]) : false;
if (user != null) {
- packages.add(new UserPackage(mContext, pkg, user));
+ UserPackage userPkg = new UserPackage(mContext, pkg, user,
+ dismissedInSafetyCenter);
+ packages.add(userPkg);
} else {
Log.i(LOG_TAG, "Not restoring state \"" + line + "\" as user is unknown");
}
}
-
return packages;
} catch (FileNotFoundException ignored) {
return new ArraySet<>();
@@ -244,29 +307,30 @@ public class LocationAccessCheck {
}
/**
- * Safe the list of {@link UserPackage packages} we have already shown a notification for.
+ * Persist the list of {@link UserPackage packages} we have already shown a notification for.
*
* @param packages The list of packages we already shown a notification for.
*/
- private void safeAlreadyNotifiedPackagesLocked(@NonNull ArraySet<UserPackage> packages) {
+ private void persistAlreadyNotifiedPackagesLocked(@NonNull ArraySet<UserPackage> packages) {
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
mContext.openFileOutput(LOCATION_ACCESS_CHECK_ALREADY_NOTIFIED_FILE,
MODE_PRIVATE)))) {
/*
- * The format of the file is <package> <serial of user>, e.g.
- *
- * com.one.package 5630633845
- * com.two.package 5630633853
- * com.three.package 5630633853
+ * The format of the file is <package> <serial of user> <dismissed in safety center>,
+ * e.g.
+ * com.one.package 5630633845 true
+ * com.two.package 5630633853 false
+ * com.three.package 5630633853 false
*/
int numPkgs = packages.size();
for (int i = 0; i < numPkgs; i++) {
UserPackage userPkg = packages.valueAt(i);
-
writer.append(userPkg.pkg);
writer.append(' ');
writer.append(
Long.valueOf(mUserManager.getSerialNumberForUser(userPkg.user)).toString());
+ writer.append(' ');
+ writer.append(Boolean.toString(userPkg.dismissedInSafetyCenter));
writer.newLine();
}
} catch (IOException e) {
@@ -277,14 +341,21 @@ public class LocationAccessCheck {
/**
* Remember that we showed a notification for a {@link UserPackage}
*
- * @param pkg The package we notified for
- * @param user The user we notified for
+ * @param pkg The package we notified for
+ * @param user The user we notified for
+ * @param dismissedInSafetyCenter Whether this warning was dismissed by the user in safety
+ * center
*/
- private void markAsNotified(@NonNull String pkg, @NonNull UserHandle user) {
+ private void markAsNotified(@NonNull String pkg, @NonNull UserHandle user,
+ boolean dismissedInSafetyCenter) {
synchronized (sLock) {
ArraySet<UserPackage> alreadyNotifiedPackages = loadAlreadyNotifiedPackagesLocked();
- alreadyNotifiedPackages.add(new UserPackage(mContext, pkg, user));
- safeAlreadyNotifiedPackagesLocked(alreadyNotifiedPackages);
+ UserPackage userPackage = new UserPackage(mContext, pkg, user, dismissedInSafetyCenter);
+ // Remove stale persisted info
+ alreadyNotifiedPackages.remove(userPackage);
+ // Persist new info about the package
+ alreadyNotifiedPackages.add(userPackage);
+ persistAlreadyNotifiedPackagesLocked(alreadyNotifiedPackages);
}
}
@@ -315,19 +386,17 @@ public class LocationAccessCheck {
/**
* Create a new {@link LocationAccessCheck} object.
*
- * @param context Used to resolve managers
+ * @param context Used to resolve managers
* @param shouldCancel If supplied, can be used to interrupt long running operations
*/
public LocationAccessCheck(@NonNull Context context, @Nullable BooleanSupplier shouldCancel) {
mContext = getParentUserContext(context);
-
mJobScheduler = getSystemServiceSafe(mContext, JobScheduler.class);
mAppOpsManager = getSystemServiceSafe(mContext, AppOpsManager.class);
mPackageManager = mContext.getPackageManager();
mUserManager = getSystemServiceSafe(mContext, UserManager.class);
mSharedPrefs = mContext.getSharedPreferences(PREFERENCES_FILE, MODE_PRIVATE);
mContentResolver = mContext.getContentResolver();
-
mShouldCancel = shouldCancel;
}
@@ -341,6 +410,7 @@ public class LocationAccessCheck {
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;
}
@@ -350,11 +420,13 @@ public class LocationAccessCheck {
if (currentTimeMillis() - mSharedPrefs.getLong(
KEY_LAST_LOCATION_ACCESS_NOTIFICATION_SHOWN, 0)
< getInBetweenNotificationsMillis()) {
+ Log.v(LOG_TAG, "location notification interval is not enough.");
service.jobFinished(params, false);
return;
}
if (getCurrentlyShownNotificationLocked() != null) {
+ Log.v(LOG_TAG, "already location notification exist.");
service.jobFinished(params, false);
return;
}
@@ -368,6 +440,7 @@ public class LocationAccessCheck {
} finally {
synchronized (sLock) {
service.mAddLocationNotificationIfNeededTask = null;
+ Log.v(LOG_TAG, "LocationAccessCheck privacy job marked complete.");
}
}
}
@@ -376,7 +449,20 @@ public class LocationAccessCheck {
private void addLocationNotificationIfNeeded(@NonNull List<PackageOps> ops)
throws InterruptedException {
synchronized (sLock) {
- List<UserPackage> packages = getLocationUsersWithNoNotificationYetLocked(ops);
+ 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);
+ }
+ throwInterruptedExceptionIfTaskIsCanceled();
+ // Send these issues to safety center
+ if (isSafetyCenterBgLocationReminderEnabled()) {
+ SafetyEvent safetyEvent = new SafetyEvent.Builder(
+ SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build();
+ sendToSafetyCenter(packages, safetyEvent, alreadyNotifiedPackages, null);
+ }
+ filterAlreadyNotifiedPackagesLocked(packages, alreadyNotifiedPackages);
// Get a random package and resolve package info
PackageInfo pkgInfo = null;
@@ -384,6 +470,9 @@ public class LocationAccessCheck {
throwInterruptedExceptionIfTaskIsCanceled();
if (packages.isEmpty()) {
+ if (DEBUG) {
+ Log.v(LOG_TAG, "No package found to send a notification");
+ }
return;
}
@@ -413,23 +502,20 @@ public class LocationAccessCheck {
packages.remove(packageToNotifyFor);
}
}
-
createPermissionReminderChannel(getUserHandleForUid(pkgInfo.applicationInfo.uid));
createNotificationForLocationUser(pkgInfo);
}
}
/**
- * Get the {@link UserPackage packages} which accessed the location but we have not yet shown
- * a notification for.
+ * Get the {@link UserPackage packages} which accessed the location
*
* <p>This also ignores all packages that are excepted from the notification.
*
- * @return The packages we need to show a notification for
- *
+ * @return The packages we might need to show a notification for
* @throws InterruptedException If {@link #mShouldCancel}
*/
- private @NonNull List<UserPackage> getLocationUsersWithNoNotificationYetLocked(
+ private @NonNull List<UserPackage> getLocationUsersLocked(
@NonNull List<PackageOps> allOps) throws InterruptedException {
List<UserPackage> pkgsWithLocationAccess = new ArrayList<>();
List<UserHandle> profiles = mUserManager.getUserProfiles();
@@ -451,8 +537,7 @@ public class LocationAccessCheck {
continue;
}
- UserPackage userPkg = new UserPackage(mContext, pkg, user);
-
+ UserPackage userPkg = new UserPackage(mContext, pkg, user, false);
AppPermissionGroup bgLocationGroup = userPkg.getBackgroundLocationGroup();
// Do not show notification that do not request the background permission anymore
if (bgLocationGroup == null) {
@@ -505,14 +590,14 @@ public class LocationAccessCheck {
}
}
}
+ return pkgsWithLocationAccess;
+ }
- ArraySet<UserPackage> alreadyNotifiedPkgs = loadAlreadyNotifiedPackagesLocked();
- throwInterruptedExceptionIfTaskIsCanceled();
-
+ private void filterAlreadyNotifiedPackagesLocked(
+ @NonNull List<UserPackage> pkgsWithLocationAccess,
+ @NonNull ArraySet<UserPackage> alreadyNotifiedPkgs) throws InterruptedException {
resetAlreadyNotifiedPackagesWithoutPermissionLocked(alreadyNotifiedPkgs);
-
pkgsWithLocationAccess.removeAll(alreadyNotifiedPkgs);
- return pkgsWithLocationAccess;
}
/**
@@ -556,15 +641,12 @@ public class LocationAccessCheck {
*/
private void createNotificationForLocationUser(@NonNull PackageInfo pkg) {
CharSequence pkgLabel = mPackageManager.getApplicationLabel(pkg.applicationInfo);
- Drawable pkgIcon = mPackageManager.getApplicationIcon(pkg.applicationInfo);
- Bitmap pkgIconBmp = createBitmap(pkgIcon.getIntrinsicWidth(), pkgIcon.getIntrinsicHeight(),
- ARGB_8888);
- Canvas canvas = new Canvas(pkgIconBmp);
- pkgIcon.setBounds(0, 0, pkgIcon.getIntrinsicWidth(), pkgIcon.getIntrinsicHeight());
- pkgIcon.draw(canvas);
+
+ boolean safetyCenterBgLocationReminderEnabled = isSafetyCenterBgLocationReminderEnabled();
String pkgName = pkg.packageName;
- UserHandle user = getUserHandleForUid(pkg.applicationInfo.uid);
+ int uid = pkg.applicationInfo.uid;
+ UserHandle user = getUserHandleForUid(uid);
NotificationManager notificationManager = getSystemServiceSafe(mContext,
NotificationManager.class, user);
@@ -574,55 +656,83 @@ public class LocationAccessCheck {
sessionId = new Random().nextLong();
}
- Intent deleteIntent = new Intent(mContext, NotificationDeleteHandler.class);
- deleteIntent.putExtra(EXTRA_PACKAGE_NAME, pkgName);
- deleteIntent.putExtra(EXTRA_SESSION_ID, sessionId);
- deleteIntent.putExtra(EXTRA_UID, pkg.applicationInfo.uid);
- deleteIntent.putExtra(EXTRA_USER, user);
- deleteIntent.setFlags(FLAG_RECEIVER_FOREGROUND);
-
- Intent clickIntent = new Intent(mContext, NotificationClickHandler.class);
- clickIntent.putExtra(EXTRA_PACKAGE_NAME, pkgName);
- clickIntent.putExtra(EXTRA_SESSION_ID, sessionId);
- clickIntent.putExtra(EXTRA_UID, pkg.applicationInfo.uid);
- clickIntent.putExtra(EXTRA_USER, user);
- clickIntent.setFlags(FLAG_RECEIVER_FOREGROUND);
-
CharSequence appName = Utils.getSettingsLabelForNotifications(mPackageManager);
+ CharSequence notificationTitle =
+ safetyCenterBgLocationReminderEnabled ? mContext.getString(
+ R.string.safety_center_background_location_access_notification_title
+ ) : mContext.getString(
+ R.string.background_location_access_reminder_notification_title,
+ pkgLabel);
+
+ CharSequence notificationContent = safetyCenterBgLocationReminderEnabled
+ ? mContext.getString(
+ R.string.safety_center_background_location_access_reminder_notification_content,
+ pkgLabel) : mContext.getString(
+ R.string.background_location_access_reminder_notification_content);
+
+ CharSequence appLabel = appName;
+ Icon smallIcon;
+ int color = mContext.getColor(android.R.color.system_notification_accent_color);
+ if (safetyCenterBgLocationReminderEnabled) {
+ KotlinUtils.NotificationResources notifRes =
+ KotlinUtils.INSTANCE.getSafetyCenterNotificationResources(mContext);
+ appLabel = notifRes.getAppLabel();
+ smallIcon = notifRes.getSmallIcon();
+ color = notifRes.getColor();
+ } else {
+ smallIcon = Icon.createWithResource(mContext, R.drawable.ic_pin_drop);
+ }
+
Notification.Builder b = (new Notification.Builder(mContext,
PERMISSION_REMINDER_CHANNEL_ID))
.setLocalOnly(true)
- .setContentTitle(mContext.getString(
- R.string.background_location_access_reminder_notification_title, pkgLabel))
- .setContentText(mContext.getString(
- R.string.background_location_access_reminder_notification_content))
- .setStyle(new Notification.BigTextStyle().bigText(mContext.getString(
- R.string.background_location_access_reminder_notification_content)))
- .setSmallIcon(R.drawable.ic_pin_drop)
- .setLargeIcon(pkgIconBmp)
- .setColor(mContext.getColor(android.R.color.system_notification_accent_color))
- .setAutoCancel(true)
- .setDeleteIntent(getBroadcast(mContext, 0, deleteIntent,
- FLAG_ONE_SHOT | FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE))
- .setContentIntent(getBroadcast(mContext, 0, clickIntent,
- FLAG_ONE_SHOT | FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE));
-
- if (appName != null) {
+ .setContentTitle(notificationTitle)
+ .setContentText(notificationContent)
+ .setStyle(new Notification.BigTextStyle().bigText(notificationContent))
+ .setSmallIcon(smallIcon)
+ .setColor(color)
+ .setDeleteIntent(createNotificationDismissIntent(pkgName, sessionId, uid))
+ .setContentIntent(createNotificationClickIntent(pkgName, user, sessionId, uid))
+ .setAutoCancel(true);
+
+ if (!safetyCenterBgLocationReminderEnabled) {
+ Drawable pkgIcon = mPackageManager.getApplicationIcon(pkg.applicationInfo);
+ Bitmap pkgIconBmp = createBitmap(pkgIcon.getIntrinsicWidth(),
+ pkgIcon.getIntrinsicHeight(),
+ ARGB_8888);
+ Canvas canvas = new Canvas(pkgIconBmp);
+ pkgIcon.setBounds(0, 0, pkgIcon.getIntrinsicWidth(), pkgIcon.getIntrinsicHeight());
+ pkgIcon.draw(canvas);
+ b.setLargeIcon(pkgIconBmp);
+ }
+
+ if (!TextUtils.isEmpty(appLabel)) {
Bundle extras = new Bundle();
- extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, appName.toString());
+ String appNameSubstitute = appLabel.toString();
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, appNameSubstitute);
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);
- PermissionControllerStatsLog.write(LOCATION_ACCESS_CHECK_NOTIFICATION_ACTION, sessionId,
- pkg.applicationInfo.uid, pkgName,
- LOCATION_ACCESS_CHECK_NOTIFICATION_ACTION__RESULT__NOTIFICATION_PRESENTED);
Log.v(LOG_TAG, "Location access check notification shown with sessionId=" + sessionId + ""
+ " uid=" + pkg.applicationInfo.uid + " pkgName=" + pkgName);
+ if (safetyCenterBgLocationReminderEnabled) {
+ PermissionControllerStatsLog.write(
+ PRIVACY_SIGNAL_NOTIFICATION_INTERACTION,
+ PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__PRIVACY_SOURCE__BG_LOCATION,
+ uid,
+ PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__ACTION__NOTIFICATION_SHOWN,
+ sessionId);
+ } else {
+ PermissionControllerStatsLog.write(LOCATION_ACCESS_CHECK_NOTIFICATION_ACTION, sessionId,
+ pkg.applicationInfo.uid, pkgName,
+ LOCATION_ACCESS_CHECK_NOTIFICATION_ACTION__RESULT__NOTIFICATION_PRESENTED);
+ }
mSharedPrefs.edit().putLong(KEY_LAST_LOCATION_ACCESS_NOTIFICATION_SHOWN,
currentTimeMillis()).apply();
@@ -651,13 +761,12 @@ public class LocationAccessCheck {
int numNotifications = notifications.length;
for (int notificationNum = 0; notificationNum < numNotifications; notificationNum++) {
StatusBarNotification notification = notifications[notificationNum];
-
- if (notification.getId() == LOCATION_ACCESS_CHECK_NOTIFICATION_ID) {
+ if (notification.getId() == LOCATION_ACCESS_CHECK_NOTIFICATION_ID
+ && notification.getUser() != null && notification.getTag() != null) {
return notification;
}
}
}
-
return null;
}
@@ -665,9 +774,8 @@ public class LocationAccessCheck {
* Go through the list of packages we already shown a notification for and remove those that do
* not request fine background location access.
*
- * @param alreadyNotifiedPkgs The packages we already shown a notification for. This paramter is
- * modified inside of this method.
- *
+ * @param alreadyNotifiedPkgs The packages we already shown a notification for. This parameter
+ * is modified inside of this method.
* @throws InterruptedException If {@link #mShouldCancel}
*/
private void resetAlreadyNotifiedPackagesWithoutPermissionLocked(
@@ -676,7 +784,6 @@ public class LocationAccessCheck {
for (UserPackage userPkg : alreadyNotifiedPkgs) {
throwInterruptedExceptionIfTaskIsCanceled();
-
AppPermissionGroup bgLocationGroup = userPkg.getBackgroundLocationGroup();
if (bgLocationGroup == null || !bgLocationGroup.areRuntimePermissionsGranted()) {
packagesToRemove.add(userPkg);
@@ -685,7 +792,7 @@ public class LocationAccessCheck {
if (!packagesToRemove.isEmpty()) {
alreadyNotifiedPkgs.removeAll(packagesToRemove);
- safeAlreadyNotifiedPackagesLocked(alreadyNotifiedPkgs);
+ persistAlreadyNotifiedPackagesLocked(alreadyNotifiedPkgs);
throwInterruptedExceptionIfTaskIsCanceled();
}
}
@@ -693,7 +800,7 @@ public class LocationAccessCheck {
/**
* Remove all persisted state for a package.
*
- * @param pkg name of package
+ * @param pkg name of package
* @param user user the package belongs to
*/
private void forgetAboutPackage(@NonNull String pkg, @NonNull UserHandle user) {
@@ -706,8 +813,8 @@ public class LocationAccessCheck {
}
ArraySet<UserPackage> packages = loadAlreadyNotifiedPackagesLocked();
- packages.remove(new UserPackage(mContext, pkg, user));
- safeAlreadyNotifiedPackagesLocked(packages);
+ packages.remove(new UserPackage(mContext, pkg, user, false));
+ persistAlreadyNotifiedPackagesLocked(packages);
}
}
@@ -730,6 +837,251 @@ public class LocationAccessCheck {
}
/**
+ * Cancel the background access warning notification for an app if the permission has been
+ * revoked for the app and forget persisted information about the app
+ */
+ public void cancelBackgroundAccessWarningNotification(String packageName, UserHandle user,
+ Boolean forgetAboutPackage) {
+ // Cancel the current notification if background
+ // location access for the package is revoked
+ StatusBarNotification notification = getCurrentlyShownNotificationLocked();
+ if (notification != null && notification.getUser().equals(user)
+ && notification.getTag().equals(packageName)) {
+ getSystemServiceSafe(mContext, NotificationManager.class, user).cancel(
+ packageName, LOCATION_ACCESS_CHECK_NOTIFICATION_ID);
+ }
+
+ if (isSafetyCenterBgLocationReminderEnabled()) {
+ rescanAndPushSafetyCenterData(new SafetyEvent.Builder(
+ SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED)
+ .build(), user);
+ }
+
+ if (forgetAboutPackage) {
+ forgetAboutPackage(packageName, user);
+ }
+ }
+
+ /**
+ * Cancel the background access warning notification if currently being shown
+ */
+ public void cancelBackgroundAccessWarningNotification() {
+ StatusBarNotification notification = getCurrentlyShownNotificationLocked();
+ if (notification != null) {
+ getSystemServiceSafe(mContext, NotificationManager.class,
+ notification.getUser()).cancel(
+ notification.getTag(), LOCATION_ACCESS_CHECK_NOTIFICATION_ID);
+ }
+ }
+
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
+ private boolean isSafetyCenterBgLocationReminderEnabled() {
+ if (!SdkLevel.isAtLeastT()) {
+ return false;
+ }
+
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_BG_LOCATION_CHECK_ENABLED, true)
+ && getSystemServiceSafe(mContext,
+ SafetyCenterManager.class).isSafetyCenterEnabled();
+ }
+
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private void sendToSafetyCenter(List<UserPackage> userPackages, SafetyEvent safetyEvent,
+ @Nullable ArraySet<UserPackage> alreadyNotifiedPackages, @Nullable UserHandle user) {
+ try {
+ Set<UserPackage> alreadyDismissedPackages =
+ getAlreadyDismissedPackages(alreadyNotifiedPackages);
+
+ // Filter out packages already dismissed by the user in safety center
+ List<UserPackage> filteredPackages = userPackages.stream().filter(
+ pkg -> !alreadyDismissedPackages.contains(pkg)).collect(
+ Collectors.toList());
+
+ Map<UserHandle, List<UserPackage>> userHandleToUserPackagesMap =
+ splitUserPackageByUserHandle(filteredPackages);
+
+ if (user == null) {
+ // Get all the user profiles
+ List<UserHandle> userProfiles = mUserManager.getUserProfiles();
+ for (UserHandle userProfile : userProfiles) {
+ sendUserDataToSafetyCenter(userHandleToUserPackagesMap.getOrDefault(userProfile,
+ new ArrayList<>()), safetyEvent, userProfile);
+ }
+ } else {
+ sendUserDataToSafetyCenter(userHandleToUserPackagesMap.getOrDefault(user,
+ new ArrayList<>()), safetyEvent, user);
+ }
+
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Could not send to safety center", e);
+ }
+ }
+
+ private Set<UserPackage> getAlreadyDismissedPackages(
+ @Nullable ArraySet<UserPackage> alreadyNotifiedPackages) {
+ if (alreadyNotifiedPackages == null) {
+ alreadyNotifiedPackages = loadAlreadyNotifiedPackagesLocked();
+ }
+ return alreadyNotifiedPackages.stream().filter(
+ pkg -> pkg.dismissedInSafetyCenter).collect(
+ Collectors.toSet());
+ }
+
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private Map<UserHandle, List<UserPackage>> splitUserPackageByUserHandle(
+ List<UserPackage> userPackages) {
+ Map<UserHandle, List<UserPackage>> userHandleToUserPackagesMap = new ArrayMap<>();
+ for (UserPackage userPackage : userPackages) {
+ if (userHandleToUserPackagesMap.get(userPackage.user) == null) {
+ userHandleToUserPackagesMap.put(userPackage.user, new ArrayList<>());
+ }
+ userHandleToUserPackagesMap.get(userPackage.user).add(userPackage);
+ }
+ return userHandleToUserPackagesMap;
+ }
+
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private void sendUserDataToSafetyCenter(List<UserPackage> userPackages,
+ SafetyEvent safetyEvent, @Nullable UserHandle user) {
+ SafetySourceData.Builder safetySourceDataBuilder = new SafetySourceData.Builder();
+ Context userContext = null;
+ for (UserPackage userPkg : userPackages) {
+ if (userContext == null) {
+ userContext = userPkg.mContext;
+ }
+ SafetySourceIssue sourceIssue = createSafetySourceIssue(userPkg);
+ if (sourceIssue != null) {
+ safetySourceDataBuilder.addIssue(sourceIssue);
+ }
+ }
+ if (userContext == null && user != null) {
+ userContext = mContext.createContextAsUser(user, 0);
+ }
+ if (userContext != null) {
+ getSystemServiceSafe(userContext, SafetyCenterManager.class).setSafetySourceData(
+ BG_LOCATION_SOURCE_ID,
+ safetySourceDataBuilder.build(),
+ safetyEvent
+ );
+ }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private SafetySourceIssue createSafetySourceIssue(UserPackage userPackage) {
+ PackageInfo pkgInfo = null;
+ try {
+ pkgInfo = userPackage.getPackageInfo();
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(LOG_TAG, "Could not get package info for " + userPackage, e);
+ return null;
+ }
+
+ long sessionId = INVALID_SESSION_ID;
+ while (sessionId == INVALID_SESSION_ID) {
+ sessionId = new Random().nextLong();
+ }
+
+ int uid = pkgInfo.applicationInfo.uid;
+
+ Intent primaryActionIntent = new Intent(mContext, SafetyCenterPrimaryActionHandler.class);
+ primaryActionIntent.putExtra(EXTRA_PACKAGE_NAME, userPackage.pkg);
+ primaryActionIntent.putExtra(EXTRA_USER, userPackage.user);
+ primaryActionIntent.putExtra(EXTRA_UID, uid);
+ primaryActionIntent.putExtra(EXTRA_SESSION_ID, sessionId);
+ primaryActionIntent.setFlags(FLAG_RECEIVER_FOREGROUND);
+ primaryActionIntent.setIdentifier(userPackage.pkg + userPackage.user);
+
+ PendingIntent revokeIntent = PendingIntent.getBroadcast(mContext, 0,
+ primaryActionIntent,
+ FLAG_ONE_SHOT | FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE);
+
+ Action revokeAction = new Action.Builder(createLocationRevokeActionId(userPackage.pkg,
+ userPackage.user),
+ mContext.getString(R.string.permission_access_only_foreground),
+ revokeIntent).setWillResolve(true).setSuccessMessage(mContext.getString(
+ R.string.safety_center_background_location_access_revoked)).build();
+
+ Intent secondaryActionIntent = new Intent(Intent.ACTION_REVIEW_PERMISSION_HISTORY);
+ secondaryActionIntent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, LOCATION);
+
+ PendingIntent locationUsageIntent = PendingIntent.getActivity(mContext, 0,
+ secondaryActionIntent,
+ FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE);
+
+ Action viewLocationUsageAction = new Action.Builder(VIEW_LOCATION_ACCESS_ID,
+ mContext.getString(R.string.safety_center_view_recent_location_access),
+ locationUsageIntent).build();
+
+ String pkgName = userPackage.pkg;
+ String id = createSafetySourceIssueId(pkgName, userPackage.user);
+
+ CharSequence pkgLabel = mPackageManager.getApplicationLabel(pkgInfo.applicationInfo);
+
+ return new SafetySourceIssue.Builder(
+ id,
+ mContext.getString(
+ R.string.safety_center_background_location_access_reminder_title),
+ mContext.getString(
+ R.string.safety_center_background_location_access_reminder_summary),
+ SafetySourceData.SEVERITY_LEVEL_INFORMATION,
+ ISSUE_TYPE_ID)
+ .setSubtitle(pkgLabel)
+ .addAction(revokeAction)
+ .addAction(viewLocationUsageAction)
+ .setOnDismissPendingIntent(
+ createWarningCardDismissalIntent(pkgName, sessionId, uid))
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
+ .build();
+ }
+
+ private PendingIntent createNotificationDismissIntent(String pkgName, long sessionId, int uid) {
+ Intent dismissIntent = new Intent(mContext, NotificationDeleteHandler.class);
+ dismissIntent.putExtra(EXTRA_PACKAGE_NAME, pkgName);
+ dismissIntent.putExtra(EXTRA_SESSION_ID, sessionId);
+ dismissIntent.putExtra(EXTRA_UID, uid);
+ UserHandle user = getUserHandleForUid(uid);
+ dismissIntent.putExtra(EXTRA_USER, user);
+ dismissIntent.setIdentifier(pkgName + user);
+ dismissIntent.setFlags(FLAG_RECEIVER_FOREGROUND);
+ return PendingIntent.getBroadcast(mContext, 0, dismissIntent,
+ FLAG_ONE_SHOT | FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE);
+ }
+
+ private PendingIntent createNotificationClickIntent(String pkg, UserHandle user,
+ long sessionId, int uid) {
+ Intent clickIntent = null;
+ if (isSafetyCenterBgLocationReminderEnabled()) {
+ clickIntent = new Intent(ACTION_SAFETY_CENTER);
+ } else {
+ clickIntent = new Intent(ACTION_MANAGE_APP_PERMISSION);
+ clickIntent.putExtra(EXTRA_PERMISSION_GROUP_NAME, LOCATION);
+ }
+ clickIntent.putExtra(EXTRA_PACKAGE_NAME, pkg);
+ clickIntent.putExtra(EXTRA_USER, user);
+ clickIntent.putExtra(EXTRA_SESSION_ID, sessionId);
+ clickIntent.putExtra(EXTRA_UID, uid);
+ clickIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK);
+ return PendingIntent.getActivity(mContext, 0, clickIntent,
+ FLAG_ONE_SHOT | FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE);
+ }
+
+ private PendingIntent createWarningCardDismissalIntent(String pkgName, long sessionId,
+ int uid) {
+ Intent dismissIntent = new Intent(mContext, WarningCardDismissalHandler.class);
+ dismissIntent.putExtra(EXTRA_PACKAGE_NAME, pkgName);
+ dismissIntent.putExtra(EXTRA_SESSION_ID, sessionId);
+ dismissIntent.putExtra(EXTRA_UID, uid);
+ UserHandle user = getUserHandleForUid(uid);
+ dismissIntent.putExtra(EXTRA_USER, user);
+ dismissIntent.setIdentifier(pkgName + user);
+ dismissIntent.setFlags(FLAG_RECEIVER_FOREGROUND);
+ return PendingIntent.getBroadcast(mContext, 0, dismissIntent,
+ FLAG_ONE_SHOT | FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE);
+ }
+
+ /**
* Check if the current user is the profile parent.
*
* @return {@code true} if the current user is the profile parent.
@@ -742,6 +1094,26 @@ public class LocationAccessCheck {
}
/**
+ * Query for packages having background location access and push to safety center
+ *
+ * @param safetyEvent Safety event for which data is being pushed
+ * @param user Optional, if supplied only send safety center data for that user
+ */
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ public void rescanAndPushSafetyCenterData(SafetyEvent safetyEvent, @Nullable UserHandle user) {
+ if (!isSafetyCenterBgLocationReminderEnabled()) {
+ return;
+ }
+ try {
+ List<UserPackage> packages = getLocationUsersLocked(mAppOpsManager.getPackagesForOps(
+ new String[]{OPSTR_FINE_LOCATION}));
+ sendToSafetyCenter(packages, safetyEvent, null, user);
+ } catch (InterruptedException e) {
+ Log.e(LOG_TAG, "Couldn't get ops for location");
+ }
+ }
+
+ /**
* On boot set up a periodic job that starts checks.
*/
public static class SetupPeriodicBackgroundLocationAccessCheck extends BroadcastReceiver {
@@ -779,12 +1151,15 @@ public class LocationAccessCheck {
public static class LocationAccessCheckJobService extends JobService {
private LocationAccessCheck mLocationAccessCheck;
- /** If we currently check if we should show a notification, the task executing the check */
+ /**
+ * If we currently check if we should show a notification, the task executing the check
+ */
// @GuardedBy("sLock")
private @Nullable AddLocationNotificationIfNeededTask mAddLocationNotificationIfNeededTask;
@Override
public void onCreate() {
+ Log.v(LOG_TAG, "LocationAccessCheck privacy job is created");
super.onCreate();
mLocationAccessCheck = new LocationAccessCheck(this, () -> {
synchronized (sLock) {
@@ -799,13 +1174,14 @@ public class LocationAccessCheck {
* Starts an asynchronous check if a location access notification should be shown.
*
* @param params Not used other than for interacting with job scheduling
- *
* @return {@code false} iff another check if already running
*/
@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.");
return false;
}
@@ -822,11 +1198,11 @@ public class LocationAccessCheck {
* Abort the check if still running.
*
* @param params ignored
- *
* @return false
*/
@Override
public boolean onStopJob(JobParameters params) {
+ Log.v(LOG_TAG, "LocationAccessCheck privacy source onStopJob called.");
AddLocationNotificationIfNeededTask task;
synchronized (sLock) {
if (mAddLocationNotificationIfNeededTask == null) {
@@ -872,48 +1248,97 @@ public class LocationAccessCheck {
String pkg = getStringExtraSafe(intent, EXTRA_PACKAGE_NAME);
UserHandle user = getParcelableExtraSafe(intent, EXTRA_USER);
long sessionId = intent.getLongExtra(EXTRA_SESSION_ID, INVALID_SESSION_ID);
- int uid = intent.getIntExtra(EXTRA_UID, 0);
+ int uid = intent.getIntExtra(EXTRA_UID, -1);
- PermissionControllerStatsLog.write(LOCATION_ACCESS_CHECK_NOTIFICATION_ACTION, sessionId,
- uid, pkg,
- LOCATION_ACCESS_CHECK_NOTIFICATION_ACTION__RESULT__NOTIFICATION_DECLINED);
Log.v(LOG_TAG,
"Location access check notification declined with sessionId=" + sessionId + ""
+ " uid=" + uid + " pkgName=" + pkg);
+ LocationAccessCheck locationAccessCheck = new LocationAccessCheck(context, null);
- new LocationAccessCheck(context, null).markAsNotified(pkg, user);
+ if (locationAccessCheck.isSafetyCenterBgLocationReminderEnabled()) {
+ PermissionControllerStatsLog.write(
+ PRIVACY_SIGNAL_NOTIFICATION_INTERACTION,
+ PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__PRIVACY_SOURCE__BG_LOCATION,
+ uid,
+ PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__ACTION__DISMISSED,
+ sessionId
+ );
+ } else {
+ PermissionControllerStatsLog.write(LOCATION_ACCESS_CHECK_NOTIFICATION_ACTION,
+ sessionId,
+ uid, pkg,
+ LOCATION_ACCESS_CHECK_NOTIFICATION_ACTION__RESULT__NOTIFICATION_DECLINED);
+ }
+ locationAccessCheck.markAsNotified(pkg, user, false);
}
}
/**
- * Show the location permission switch when the notification is clicked.
+ * Broadcast receiver to handle the primary action from a safety center warning card
*/
- public static class NotificationClickHandler extends BroadcastReceiver {
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ public static class SafetyCenterPrimaryActionHandler extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- String pkg = getStringExtraSafe(intent, EXTRA_PACKAGE_NAME);
+ String packageName = getStringExtraSafe(intent, EXTRA_PACKAGE_NAME);
UserHandle user = getParcelableExtraSafe(intent, EXTRA_USER);
- int uid = intent.getIntExtra(EXTRA_UID, 0);
+ int uid = intent.getIntExtra(EXTRA_UID, -1);
long sessionId = intent.getLongExtra(EXTRA_SESSION_ID, INVALID_SESSION_ID);
+ // Revoke bg location permission and notify safety center
+ KotlinUtils.INSTANCE.revokeBackgroundRuntimePermissions(context, packageName, LOCATION,
+ user, () -> {
+ new LocationAccessCheck(context, null).rescanAndPushSafetyCenterData(
+ new SafetyEvent.Builder(
+ SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED)
+ .setSafetySourceIssueId(
+ createSafetySourceIssueId(packageName, user))
+ .setSafetySourceIssueActionId(
+ createLocationRevokeActionId(packageName, user))
+ .build(), user);
+ });
+ PermissionControllerStatsLog.write(
+ PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION,
+ PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__PRIVACY_SOURCE__BG_LOCATION,
+ uid,
+ PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__ACTION__CLICKED_CTA1,
+ sessionId
+ );
- new LocationAccessCheck(context, null).markAsNotified(pkg, user);
+ }
+ }
- PermissionControllerStatsLog.write(LOCATION_ACCESS_CHECK_NOTIFICATION_ACTION, sessionId,
- uid, pkg,
- LOCATION_ACCESS_CHECK_NOTIFICATION_ACTION__RESULT__NOTIFICATION_CLICKED);
- Log.v(LOG_TAG,
- "Location access check notification clicked with sessionId=" + sessionId + ""
- + " uid=" + uid + " pkgName=" + pkg);
+ private static String createSafetySourceIssueId(String packageName, UserHandle user) {
+ return ISSUE_ID_PREFIX + packageName + user;
+ }
- Intent manageAppPermission = new Intent(ACTION_MANAGE_APP_PERMISSION);
- manageAppPermission.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK);
- manageAppPermission.putExtra(EXTRA_PERMISSION_GROUP_NAME, LOCATION);
- manageAppPermission.putExtra(EXTRA_PACKAGE_NAME, pkg);
- manageAppPermission.putExtra(EXTRA_USER, user);
- manageAppPermission.putExtra(EXTRA_SESSION_ID, sessionId);
+ private static String createLocationRevokeActionId(String packageName, UserHandle user) {
+ return REVOKE_LOCATION_ACCESS_ID_PREFIX + packageName + user;
+ }
+ /**
+ * Handle the case where the warning card is dismissed by the user in Safety center
+ */
+ public static class WarningCardDismissalHandler extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String pkg = getStringExtraSafe(intent, EXTRA_PACKAGE_NAME);
+ 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,
+ "Location access check warning card dismissed with sessionId=" + sessionId + ""
+ + " uid=" + uid + " pkgName=" + pkg);
+ PermissionControllerStatsLog.write(
+ PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION,
+ PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__PRIVACY_SOURCE__BG_LOCATION,
+ uid,
+ PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__ACTION__CARD_DISMISSED,
+ sessionId
+ );
- context.startActivity(manageAppPermission);
+ LocationAccessCheck locationAccessCheck = new LocationAccessCheck(context, null);
+ locationAccessCheck.markAsNotified(pkg, user, true);
+ locationAccessCheck.cancelBackgroundAccessWarningNotification(pkg, user, false);
}
}
@@ -932,11 +1357,15 @@ public class LocationAccessCheck {
Uri data = Preconditions.checkNotNull(intent.getData());
UserHandle user = getUserHandleForUid(intent.getIntExtra(EXTRA_UID, 0));
-
if (DEBUG) Log.i(LOG_TAG, "Reset " + data.getSchemeSpecificPart());
-
- new LocationAccessCheck(context, null).forgetAboutPackage(
- data.getSchemeSpecificPart(), user);
+ LocationAccessCheck locationAccessCheck = new LocationAccessCheck(context, null);
+ String packageName = data.getSchemeSpecificPart();
+ locationAccessCheck.forgetAboutPackage(packageName, user);
+ if (locationAccessCheck.isSafetyCenterBgLocationReminderEnabled()) {
+ locationAccessCheck.rescanAndPushSafetyCenterData(
+ new SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED)
+ .build(), user);
+ }
}
}
@@ -948,15 +1377,19 @@ public class LocationAccessCheck {
public final @NonNull String pkg;
public final @NonNull UserHandle user;
+ public final boolean dismissedInSafetyCenter;
/**
* Create a new {@link UserPackage}
*
- * @param context A context to be used by methods of this object
- * @param pkg The name of the package
- * @param user The user the package belongs to
+ * @param context A context to be used by methods of this object
+ * @param pkg The name of the package
+ * @param user The user the package belongs to
+ * @param dismissedInSafetyCenter Optional boolean recording if the safety center
+ * warning was dismissed by the user
*/
- UserPackage(@NonNull Context context, @NonNull String pkg, @NonNull UserHandle user) {
+ UserPackage(@NonNull Context context, @NonNull String pkg, @NonNull UserHandle user,
+ boolean dismissedInSafetyCenter) {
try {
mContext = context.createPackageContextAsUser(context.getPackageName(), 0, user);
} catch (PackageManager.NameNotFoundException e) {
@@ -965,16 +1398,17 @@ public class LocationAccessCheck {
this.pkg = pkg;
this.user = user;
+ this.dismissedInSafetyCenter = dismissedInSafetyCenter;
}
/**
* Get {@link PackageInfo} for this user package.
*
* @return The package info
- *
* @throws PackageManager.NameNotFoundException if package/user does not exist
*/
- @NonNull PackageInfo getPackageInfo() throws PackageManager.NameNotFoundException {
+ @NonNull
+ PackageInfo getPackageInfo() throws PackageManager.NameNotFoundException {
return mContext.getPackageManager().getPackageInfo(pkg, GET_PERMISSIONS);
}
@@ -984,10 +1418,11 @@ public class LocationAccessCheck {
*
* @return The app permission group or {@code null} if the app does not request location
*/
- @Nullable AppPermissionGroup getLocationGroup() {
+ @Nullable
+ AppPermissionGroup getLocationGroup() {
try {
return AppPermissionGroup.create(mContext, getPackageInfo(), ACCESS_FINE_LOCATION,
- false);
+ false);
} catch (PackageManager.NameNotFoundException e) {
return null;
}
@@ -998,9 +1433,10 @@ public class LocationAccessCheck {
* {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and this user package.
*
* @return The app permission group or {@code null} if the app does not request background
- * location
+ * location
*/
- @Nullable AppPermissionGroup getBackgroundLocationGroup() {
+ @Nullable
+ AppPermissionGroup getBackgroundLocationGroup() {
AppPermissionGroup locationGroup = getLocationGroup();
if (locationGroup == null) {
return null;
@@ -1023,5 +1459,13 @@ public class LocationAccessCheck {
public int hashCode() {
return Objects.hash(pkg, user);
}
+
+ @Override
+ public String toString() {
+ return "UserPackage { "
+ + "pkg = " + pkg + ", "
+ + "UserHandle = " + user.toString() + ", "
+ + "dismissedInSafetyCenter = " + dismissedInSafetyCenter + " }";
+ }
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionChangeStorageImpl.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionChangeStorageImpl.kt
new file mode 100644
index 000000000..bdcf833fc
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionChangeStorageImpl.kt
@@ -0,0 +1,214 @@
+/*
+ * 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.permissioncontroller.permission.service
+
+import android.app.job.JobScheduler
+import android.content.Context
+import android.provider.DeviceConfig
+import android.util.Log
+import android.util.Xml
+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
+import java.nio.charset.StandardCharsets
+import java.text.ParseException
+import java.text.SimpleDateFormat
+import java.util.Date
+import java.util.Locale
+
+/**
+ * Implementation of [BasePermissionEventStorage] for storing [PermissionChange] events for long
+ * periods of time.
+ */
+class PermissionChangeStorageImpl(
+ context: Context,
+ jobScheduler: JobScheduler = context.getSystemService(JobScheduler::class.java)!!
+) : BasePermissionEventStorage<PermissionChange>(context, jobScheduler) {
+
+ // We don't use namespaces
+ private val ns: String? = null
+
+ /**
+ * 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
+ */
+ private val exactTimeFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US)
+
+ companion object {
+ private const val LOG_TAG = "PermissionChangeStorageImpl"
+
+ private const val DB_VERSION = 1
+
+ /**
+ * 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"
+ private const val TAG_PERMISSION_CHANGE = "permission-change"
+ private const val ATTR_VERSION = "version"
+ private const val ATTR_STORE_EXACT_TIME = "store-exact-time"
+ private const val ATTR_PACKAGE_NAME = "package-name"
+ private const val ATTR_EVENT_TIME = "event-time"
+
+ @Volatile
+ private var INSTANCE: PermissionEventStorage<PermissionChange>? = null
+
+ fun getInstance(): PermissionEventStorage<PermissionChange> =
+ INSTANCE ?: synchronized(this) {
+ INSTANCE ?: createInstance().also { INSTANCE = it }
+ }
+
+ private fun createInstance(): PermissionEventStorage<PermissionChange> {
+ return PermissionChangeStorageImpl(PermissionControllerApplication.get())
+ }
+
+ @OptIn(DelicateCoroutinesApi::class)
+ fun recordPermissionChange(packageName: String) {
+ GlobalScope.launch(Dispatchers.IO) {
+ getInstance().storeEvent(PermissionChange(packageName, System.currentTimeMillis()))
+ }
+ }
+ }
+
+ override fun serialize(stream: OutputStream, events: List<PermissionChange>) {
+ val out = Xml.newSerializer()
+ out.setOutput(stream, StandardCharsets.UTF_8.name())
+ out.startDocument(/* encoding= */ null, /* standalone= */ true)
+ out.startTag(ns, TAG_PERMISSION_CHANGES)
+ out.attribute(ns, ATTR_VERSION, DB_VERSION.toString())
+ val storesExactTime = storesExactTime()
+ out.attribute(ns, ATTR_STORE_EXACT_TIME, storesExactTime.toString())
+ val format = if (storesExactTime) exactTimeFormat else dateFormat
+ for (change in events) {
+ out.startTag(ns, TAG_PERMISSION_CHANGE)
+ out.attribute(ns, ATTR_PACKAGE_NAME, change.packageName)
+ val date = format.format(Date(change.eventTime))
+ out.attribute(ns, ATTR_EVENT_TIME, date)
+ out.endTag(ns, TAG_PERMISSION_CHANGE)
+ }
+ out.endTag(ns, TAG_PERMISSION_CHANGES)
+ out.endDocument()
+ }
+
+ override fun parse(inputStream: InputStream): List<PermissionChange> {
+ inputStream.use {
+ val parser: XmlPullParser = Xml.newPullParser()
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, /* state= */ false)
+ parser.setInput(inputStream, /* inputEncoding= */ null)
+ parser.nextTag()
+ return readPermissionChanges(parser)
+ }
+ }
+
+ @Throws(XmlPullParserException::class, IOException::class)
+ private fun readPermissionChanges(parser: XmlPullParser): List<PermissionChange> {
+ val entries = mutableListOf<PermissionChange>()
+
+ parser.require(XmlPullParser.START_TAG, ns, TAG_PERMISSION_CHANGES)
+ // Parse using whatever format was previously used no matter what current device config
+ // value is but truncate if we switched from exact granularity to day granularity
+ val didStoreExactTime =
+ parser.getAttributeValueNullSafe(ns, ATTR_STORE_EXACT_TIME).toBoolean()
+ val format = if (didStoreExactTime) exactTimeFormat else dateFormat
+ val storesExactTime = storesExactTime()
+ val truncateToDay = didStoreExactTime != storesExactTime && !storesExactTime
+ while (parser.next() != XmlPullParser.END_TAG) {
+ readPermissionChange(parser, format, truncateToDay)?.let {
+ entries.add(it)
+ }
+ }
+ return entries
+ }
+
+ @Throws(XmlPullParserException::class, IOException::class)
+ private fun readPermissionChange(
+ parser: XmlPullParser,
+ format: SimpleDateFormat,
+ truncateToDay: Boolean
+ ): PermissionChange? {
+ var change: PermissionChange? = null
+ parser.require(XmlPullParser.START_TAG, ns, TAG_PERMISSION_CHANGE)
+ 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")
+ if (truncateToDay) {
+ changeTime = dateFormat.parse(dateFormat.format(Date(changeTime)))!!.time
+ }
+ change = PermissionChange(packageName, changeTime)
+ } catch (e: XmlPullParserException) {
+ Log.e(LOG_TAG, "Unable to parse permission change", e)
+ } catch (e: ParseException) {
+ Log.e(LOG_TAG, "Unable to parse permission change", e)
+ } catch (e: IllegalArgumentException) {
+ Log.e(LOG_TAG, "Unable to parse permission change", e)
+ } finally {
+ parser.nextTag()
+ parser.require(XmlPullParser.END_TAG, ns, TAG_PERMISSION_CHANGE)
+ }
+ return change
+ }
+
+ @Throws(XmlPullParserException::class)
+ private fun XmlPullParser.getAttributeValueNullSafe(namespace: String?, name: String): String {
+ return this.getAttributeValue(namespace, name)
+ ?: throw XmlPullParserException(
+ "Could not find attribute: namespace $namespace, name $name")
+ }
+
+ override fun getDatabaseFileName(): String {
+ return STORE_FILE_NAME
+ }
+
+ override fun getMaxDataAgeMs(): Long {
+ // Only retain data up to the threshold needed for auto-revoke to trigger
+ return getUnusedThresholdMs()
+ }
+
+ override fun hasTheSamePrimaryKey(first: PermissionChange, second: PermissionChange): Boolean {
+ return first.packageName == second.packageName
+ }
+
+ override fun PermissionChange.copyWithTimeDelta(timeDelta: Long): PermissionChange {
+ return this.copy(eventTime = this.eventTime + timeDelta)
+ }
+
+ /**
+ * 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)
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java
index ff2559933..d5c43335c 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java
@@ -29,10 +29,12 @@ import static com.android.permissioncontroller.PermissionControllerStatsLog.PERM
import static java.nio.charset.StandardCharsets.UTF_8;
import android.Manifest;
+import android.app.admin.DevicePolicyManager;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Process;
@@ -49,6 +51,7 @@ import android.util.Xml;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import com.android.permissioncontroller.PermissionControllerProto.PermissionControllerDumpProto;
import com.android.permissioncontroller.PermissionControllerStatsLog;
@@ -58,13 +61,16 @@ import com.android.permissioncontroller.permission.model.Permission;
import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGroupUiInfo;
import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGroupUiInfo.PermGrantState;
import com.android.permissioncontroller.permission.ui.AutoGrantPermissionsNotifier;
-import com.android.permissioncontroller.permission.utils.AdminRestrictedPermissionsUtils;
import com.android.permissioncontroller.permission.utils.ArrayUtils;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
+import com.android.permissioncontroller.permission.utils.PermissionMapping;
import com.android.permissioncontroller.permission.utils.UserSensitiveFlagsUtils;
import com.android.permissioncontroller.permission.utils.Utils;
-import com.android.permissioncontroller.role.model.Role;
-import com.android.permissioncontroller.role.model.Roles;
+import com.android.permissioncontroller.permission.utils.v31.AdminRestrictedPermissionsUtils;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.Roles;
+
+import kotlin.Pair;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
@@ -87,7 +93,6 @@ import java.util.function.Consumer;
import java.util.function.IntConsumer;
import java.util.stream.Collectors;
-import kotlin.Pair;
import kotlinx.coroutines.BuildersKt;
import kotlinx.coroutines.GlobalScope;
@@ -434,7 +439,8 @@ public final class PermissionControllerServiceImpl extends PermissionControllerL
for (Pair<String, AppPermGroupUiInfo> groupNameAndUiInfo : groupUiInfos) {
String groupName = groupNameAndUiInfo.getFirst();
AppPermGroupUiInfo uiInfo = groupNameAndUiInfo.getSecond();
- boolean isPlatform = Utils.getPlatformPermissionGroups().contains(groupName);
+ boolean isPlatform =
+ PermissionMapping.getPlatformPermissionGroups().contains(groupName);
CharSequence label = KotlinUtils.INSTANCE.getPermGroupLabel(this, groupName);
RuntimePermissionPresentationInfo permission =
@@ -540,7 +546,7 @@ public final class PermissionControllerServiceImpl extends PermissionControllerL
new AutoGrantPermissionsNotifier(this, pkgInfo);
final boolean isManagedProfile = getSystemService(UserManager.class).isManagedProfile();
-
+ DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
int numPerms = expandedPermissions.size();
for (int i = 0; i < numPerms; i++) {
String permName = expandedPermissions.get(i);
@@ -557,7 +563,7 @@ public final class PermissionControllerServiceImpl extends PermissionControllerL
switch (grantState) {
case PERMISSION_GRANT_STATE_GRANTED:
if (AdminRestrictedPermissionsUtils.mayAdminGrantPermission(perm.getName(),
- canAdminGrantSensorsPermissions, isManagedProfile)) {
+ canAdminGrantSensorsPermissions, isManagedProfile, dpm)) {
perm.setPolicyFixed(true);
group.grantRuntimePermissions(false, false, new String[]{permName});
autoGrantPermissionsNotifier.onPermissionAutoGranted(permName);
@@ -678,10 +684,16 @@ public final class PermissionControllerServiceImpl extends PermissionControllerL
oneTimeGrantedPermissions.toArray(new String[0]));
}
for (String permissionName : oneTimeGrantedPermissions) {
- // We only reset the USER_SET flag if the permission was granted.
+ // We only reset the USER_SET and REVOKED_COMPAT flags if the permission was
+ // granted.
Permission permission = group.getPermission(permissionName);
if (permission != null) {
permission.setUserSet(false);
+ if (!permission.isGranted() && permission.isRevokedCompat()) {
+ // If we revoked the permission, but the Revoked Compat flag is set,
+ // reset it
+ permission.setRevokedCompat(false);
+ }
}
}
if (bgGroup != null) {
@@ -725,7 +737,8 @@ public final class PermissionControllerServiceImpl extends PermissionControllerL
PermissionControllerStatsLog.write(
PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED,
- requestId, uid, packageName, permName, false, r);
+ requestId, uid, packageName, permName, false, r,
+ /* permission_rationale_shown = */ false);
}
}
}
@@ -742,13 +755,13 @@ public final class PermissionControllerServiceImpl extends PermissionControllerL
@Override
public void onGetPlatformPermissionsForGroup(@NonNull String permissionGroupName,
@NonNull Consumer<List<String>> callback) {
- callback.accept(Utils.getPlatformPermissionNamesOfGroup(permissionGroupName));
+ callback.accept(PermissionMapping.getPlatformPermissionNamesOfGroup(permissionGroupName));
}
@Override
public void onGetGroupOfPlatformPermission(@NonNull String permissionName,
@NonNull Consumer<String> callback) {
- callback.accept(Utils.getGroupOfPlatformPermission(permissionName));
+ callback.accept(PermissionMapping.getGroupOfPlatformPermission(permissionName));
}
@Override
@@ -763,6 +776,7 @@ public final class PermissionControllerServiceImpl extends PermissionControllerL
}
@Override
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
public void onRevokeSelfPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions, @NonNull Runnable callback) {
PackageInfo pkgInfo = getPkgInfo(packageName);
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceModel.kt
index 3d4b0db77..4b239ec71 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceModel.kt
@@ -25,9 +25,10 @@ import androidx.core.util.Consumer
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
-import androidx.lifecycle.Transformations
+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
@@ -87,13 +88,13 @@ class PermissionControllerServiceModel(private val service: PermissionController
var updated = false
val observer = object : Observer<T> {
- override fun onChanged(data: T) {
+ override fun onChanged(value: T) {
if (updated) {
return
}
if ((liveData is SmartUpdateMediatorLiveData<T> && !liveData.isStale) ||
liveData !is SmartUpdateMediatorLiveData<T>) {
- onChangedFun(data)
+ onChangedFun(value)
liveData.removeObserver(this)
updated = true
}
@@ -173,7 +174,7 @@ class PermissionControllerServiceModel(private val service: PermissionController
}
if (Utils.isPermissionDangerousInstalledNotRemoved(permInfo)) {
- permToGroup[permName] = Utils.getGroupOfPermission(permInfo)
+ permToGroup[permName] = PermissionMapping.getGroupOfPermission(permInfo)
}
}
@@ -288,9 +289,7 @@ class PermissionControllerServiceModel(private val service: PermissionController
callback: IntConsumer
) {
GlobalScope.launch(Main.immediate) {
- val unusedAppsCount = Transformations.map(getUnusedPackages()) {
- it?.size ?: 0
- }
+ val unusedAppsCount = getUnusedPackages().map { it?.size ?: 0 }
observeAndCheckForLifecycleState(unusedAppsCount) { count ->
callback.accept(count ?: 0)
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionEventCleanupJobService.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventCleanupJobService.kt
index b87e54dfd..d22b63e9a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionEventCleanupJobService.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventCleanupJobService.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.service.v33
+package com.android.permissioncontroller.permission.service
import android.app.job.JobInfo
import android.app.job.JobParameters
@@ -22,9 +22,7 @@ import android.app.job.JobScheduler
import android.app.job.JobService
import android.content.ComponentName
import android.content.Context
-import android.os.Build
import android.provider.DeviceConfig
-import androidx.annotation.RequiresApi
import com.android.permissioncontroller.Constants
import com.android.permissioncontroller.DumpableLog
import com.android.permissioncontroller.permission.utils.Utils
@@ -37,7 +35,6 @@ import java.util.concurrent.TimeUnit
/**
* A job to clean up old permission events.
*/
-@RequiresApi(Build.VERSION_CODES.TIRAMISU)
class PermissionEventCleanupJobService : JobService() {
companion object {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionEventStorage.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventStorage.kt
index e6ae96fcc..67a1cb4a4 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionEventStorage.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventStorage.kt
@@ -14,16 +14,13 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.service.v33
+package com.android.permissioncontroller.permission.service
-import android.os.Build
-import androidx.annotation.RequiresApi
-import com.android.permissioncontroller.permission.data.v33.PermissionEvent
+import com.android.permissioncontroller.permission.data.PermissionEvent
/**
* Persistent storage for retrieving persisted permission event data.
*/
-@RequiresApi(Build.VERSION_CODES.TIRAMISU)
interface PermissionEventStorage<T : PermissionEvent> {
/**
* Persist a permission event for retrieval later.
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionEventStorageImpls.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventStorageImpls.kt
index e3c3e3a1f..de6a0d9e2 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionEventStorageImpls.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionEventStorageImpls.kt
@@ -14,17 +14,16 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.service.v33
+package com.android.permissioncontroller.permission.service
-import android.os.Build
-import androidx.annotation.RequiresApi
+import android.annotation.SuppressLint
import com.android.permissioncontroller.PermissionControllerApplication
-import com.android.permissioncontroller.permission.data.v33.PermissionEvent
+import com.android.permissioncontroller.permission.data.PermissionEvent
+import com.android.permissioncontroller.permission.service.v33.PermissionDecisionStorageImpl
/**
* Singleton of all supported [PermissionEventStorage] on the device.
*/
-@RequiresApi(Build.VERSION_CODES.TIRAMISU)
class PermissionEventStorageImpls {
companion object {
@Volatile
@@ -35,9 +34,10 @@ class PermissionEventStorageImpls {
INSTANCE ?: createInstance().also { INSTANCE = it }
}
+ @SuppressLint("NewApi")
private fun createInstance(): List<PermissionEventStorage<out PermissionEvent>> {
- // TODO(205642821): Add storage for permission change events
val list = mutableListOf<PermissionEventStorage<out PermissionEvent>>()
+ list.add(PermissionChangeStorageImpl.getInstance())
val context = PermissionControllerApplication.get().applicationContext
if (PermissionDecisionStorageImpl.isRecordPermissionsSupported(context)) {
list.add(PermissionDecisionStorageImpl.getInstance())
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionSearchIndexablesProvider.java b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionSearchIndexablesProvider.java
index 517a14477..f8720a0a3 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionSearchIndexablesProvider.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionSearchIndexablesProvider.java
@@ -31,7 +31,7 @@ import android.database.MatrixCursor;
import android.util.Log;
import com.android.permissioncontroller.R;
-import com.android.permissioncontroller.permission.utils.Utils;
+import com.android.permissioncontroller.permission.utils.PermissionMapping;
import java.util.List;
@@ -49,7 +49,7 @@ public class PermissionSearchIndexablesProvider extends BaseSearchIndexablesProv
Context context = getContext();
PackageManager pm = context.getPackageManager();
- List<String> permissionGroupNames = Utils.getPlatformPermissionGroups();
+ List<String> permissionGroupNames = PermissionMapping.getPlatformPermissionGroups();
MatrixCursor cursor = new MatrixCursor(INDEXABLES_RAW_COLUMNS);
int numPermissionGroups = permissionGroupNames.size();
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionStorageTimeChangeReceiver.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionStorageTimeChangeReceiver.kt
index 3e900867e..43970dd13 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionStorageTimeChangeReceiver.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionStorageTimeChangeReceiver.kt
@@ -14,18 +14,16 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.service.v33
+package com.android.permissioncontroller.permission.service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
-import android.os.Build
-import androidx.annotation.RequiresApi
import androidx.annotation.VisibleForTesting
import androidx.preference.PreferenceManager
import com.android.permissioncontroller.DumpableLog
-import com.android.permissioncontroller.permission.data.v33.PermissionEvent
+import com.android.permissioncontroller.permission.data.PermissionEvent
import com.android.permissioncontroller.permission.utils.SystemTimeSource
import com.android.permissioncontroller.permission.utils.TimeSource
import kotlinx.coroutines.Dispatchers
@@ -40,7 +38,6 @@ import kotlin.math.abs
* of the delta we take a snapshot of the current time and time since boot after the
* [Intent.ACTION_BOOT_COMPLETED] action.
*/
-@RequiresApi(Build.VERSION_CODES.TIRAMISU)
class PermissionStorageTimeChangeReceiver(
private val storages: List<PermissionEventStorage<out PermissionEvent>> =
PermissionEventStorageImpls.getInstance(),
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/v33/PersistedStoragePackageUninstalledReceiver.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/PersistedStoragePackageUninstalledReceiver.kt
index 39a72ba4d..37fa2b36d 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/v33/PersistedStoragePackageUninstalledReceiver.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PersistedStoragePackageUninstalledReceiver.kt
@@ -14,17 +14,15 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.service.v33
+package com.android.permissioncontroller.permission.service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
-import android.os.Build
import android.os.Process
-import androidx.annotation.RequiresApi
import androidx.annotation.VisibleForTesting
import com.android.permissioncontroller.DumpableLog
-import com.android.permissioncontroller.permission.data.v33.PermissionEvent
+import com.android.permissioncontroller.permission.data.PermissionEvent
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
@@ -34,7 +32,6 @@ import kotlinx.coroutines.launch
* [BroadcastReceiver] to clear user decision information when a package has its data cleared or
* is fully removed.
*/
-@RequiresApi(Build.VERSION_CODES.TIRAMISU)
class PersistedStoragePackageUninstalledReceiver(
@VisibleForTesting
private val storages: List<PermissionEventStorage<out PermissionEvent>> =
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/RuntimePermissionsUpgradeController.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/RuntimePermissionsUpgradeController.kt
index 7279d6ede..3405ab014 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/RuntimePermissionsUpgradeController.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/RuntimePermissionsUpgradeController.kt
@@ -23,6 +23,7 @@ import android.content.pm.PackageInfo
import android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT
import android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
import android.content.pm.PermissionInfo
+import android.os.Build
import android.os.Process.myUserHandle
import android.permission.PermissionManager
import android.util.Log
@@ -41,8 +42,8 @@ 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.Utils.getPlatformPermissionNamesOfGroup
-import com.android.permissioncontroller.permission.utils.Utils.getRuntimePlatformPermissionNames
+import com.android.permissioncontroller.permission.utils.PermissionMapping.getPlatformPermissionNamesOfGroup
+import com.android.permissioncontroller.permission.utils.PermissionMapping.getRuntimePlatformPermissionNames
import com.android.permissioncontroller.permission.utils.application
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
@@ -54,23 +55,27 @@ internal object RuntimePermissionsUpgradeController {
private val LOG_TAG = RuntimePermissionsUpgradeController::class.java.simpleName
// The latest version of the runtime permissions database
- private val LATEST_VERSION = 9
+ private val LATEST_VERSION = if (SdkLevel.isAtLeastT()) {
+ 10
+ } else {
+ 9
+ }
fun upgradeIfNeeded(context: Context, onComplete: Runnable) {
val permissionManager = context.getSystemService(PermissionManager::class.java)
- val currentVersion = permissionManager!!.runtimePermissionsVersion
+ val storedVersion = permissionManager!!.runtimePermissionsVersion
+ val currentVersion = minOf(storedVersion, LATEST_VERSION)
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())
+ " 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")
}
- if (currentVersion != upgradedVersion) {
+ if (storedVersion != upgradedVersion) {
permissionManager.runtimePermissionsVersion = LATEST_VERSION
}
onComplete.run()
@@ -128,6 +133,8 @@ internal object RuntimePermissionsUpgradeController {
val needBackgroundAppPermGroups = sdkUpgradedFromP && currentVersion <= 6
val needAccessMediaAppPermGroups = !isNewUser && currentVersion <= 7
+ val needGrantedExternalStorage = currentVersion <= 9 && SdkLevel.isAtLeastT()
+ val isDeviceUpgrading = context.packageManager.isDeviceUpgrading
// All data needed by this method.
//
@@ -199,10 +206,11 @@ internal object RuntimePermissionsUpgradeController {
permGroupProviders = mutableListOf()
// Only load app-perm-groups needed for this upgrade
- if (needBackgroundAppPermGroups || needAccessMediaAppPermGroups) {
+ if (needBackgroundAppPermGroups || needAccessMediaAppPermGroups ||
+ needGrantedExternalStorage) {
for ((pkgName, _, requestedPerms, requestedPermFlags) in
pkgInfoProvider.value!!) {
- var hasAccessMedia = false
+ var requestsAccessMediaLocation = false
var hasGrantedExternalStorage = false
for ((perm, flags) in requestedPerms.zip(requestedPermFlags)) {
@@ -212,9 +220,10 @@ internal object RuntimePermissionsUpgradeController {
permission_group.LOCATION, myUserHandle()])
}
- if (needAccessMediaAppPermGroups) {
- if (perm == permission.ACCESS_MEDIA_LOCATION) {
- hasAccessMedia = true
+ if (needAccessMediaAppPermGroups || needGrantedExternalStorage) {
+ if (needAccessMediaAppPermGroups &&
+ perm == permission.ACCESS_MEDIA_LOCATION) {
+ requestsAccessMediaLocation = true
}
if (perm == permission.READ_EXTERNAL_STORAGE &&
@@ -231,9 +240,20 @@ internal object RuntimePermissionsUpgradeController {
else
permission_group.STORAGE
- if (hasAccessMedia && hasGrantedExternalStorage) {
- permGroupProviders!!.add(LightAppPermGroupLiveData[pkgName,
- accessMediaLocationPermGroup, myUserHandle()])
+ 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()])
+ }
}
}
}
@@ -272,6 +292,12 @@ internal object RuntimePermissionsUpgradeController {
permission_group.STORAGE -> {
storageGroups.add(group)
}
+ permission_group.READ_MEDIA_AURAL -> {
+ storageGroups.add(group)
+ }
+ permission_group.READ_MEDIA_VISUAL -> {
+ storageGroups.add(group)
+ }
}
}
@@ -307,7 +333,8 @@ internal object RuntimePermissionsUpgradeController {
val (newVersion, upgradeExemptions, grants) = onUpgradeLockedDataLoaded(currentVersion,
upgradeData.pkgs, upgradeData.restrictedPermissions,
- upgradeData.bgGroups, upgradeData.storageGroups)
+ upgradeData.bgGroups, upgradeData.storageGroups,
+ isDeviceUpgrading)
// Do not run in parallel. Measurements have shown that this is slower than sequential
for (exemption in (preinstalledAppExemptions union upgradeExemptions)) {
@@ -326,7 +353,8 @@ internal object RuntimePermissionsUpgradeController {
pkgs: List<LightPackageInfo>,
restrictedPermissions: Set<String>,
bgApps: List<LightAppPermGroup>,
- accessMediaApps: List<LightAppPermGroup>
+ storageAndMediaAppPermGroups: List<LightAppPermGroup>,
+ isDeviceUpgrading: Boolean
): Triple<Int, List<RestrictionExemption>, List<Grant>> {
val exemptions = mutableListOf<RestrictionExemption>()
val grants = mutableListOf<Grant>()
@@ -441,7 +469,7 @@ internal object RuntimePermissionsUpgradeController {
if (!isNewUser) {
Log.i(LOG_TAG, "Expanding read storage to access media location")
- for (appPermGroup in accessMediaApps) {
+ for (appPermGroup in storageAndMediaAppPermGroups) {
val perm = appPermGroup.permissions[permission.ACCESS_MEDIA_LOCATION]
?: continue
@@ -465,6 +493,49 @@ internal object RuntimePermissionsUpgradeController {
currentVersion = 9
}
+ 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")
+ } else if (!isDeviceUpgrading) {
+ Log.i(LOG_TAG, "Not migrating STORAGE permissions to READ_MEDIA 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
+ }
+ 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 }
+ }
+
+ if (auralAppPermGroup != null) {
+ grants.add(Grant(false, auralAppPermGroup))
+ }
+ if (visualAppPermGroup != null) {
+ grants.add(Grant(false, visualAppPermGroup))
+ }
+ }
+ }
+ currentVersion = 10
+ }
+
// XXX: Add new upgrade steps above this point.
return Triple(currentVersion, exemptions, grants)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/SplitPermissionIndex.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/SplitPermissionIndex.kt
index 9ff4b839e..115200b2f 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/SplitPermissionIndex.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/SplitPermissionIndex.kt
@@ -17,7 +17,7 @@
package com.android.permissioncontroller.permission.service
import android.permission.PermissionManager
-import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.permission.utils.PermissionMapping
/**
* Takes a list of split permissions, and provides methods that return which split-permissions will
@@ -37,8 +37,8 @@ class SplitPermissionIndex() {
for (splitPerm in splitPermissionInfos) {
val oldPerm = splitPerm.splitPermission
for (newPerm in splitPerm.newPermissions) {
- val oldPermGroup = Utils.getGroupOfPlatformPermission(oldPerm)
- val newPermGroup = Utils.getGroupOfPlatformPermission(newPerm)
+ val oldPermGroup = PermissionMapping.getGroupOfPlatformPermission(oldPerm)
+ val newPermGroup = PermissionMapping.getGroupOfPlatformPermission(newPerm)
if (newPermGroup != null) {
permToGroupSplits.add(SplitPermissionIndexEntry(
oldPerm, splitPerm.targetSdk, newPermGroup))
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/TEST_MAPPING b/PermissionController/src/com/android/permissioncontroller/permission/service/TEST_MAPPING
index 476483608..b8dd3d77a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/TEST_MAPPING
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/TEST_MAPPING
@@ -15,6 +15,23 @@
]
},
{
+ "name": "CtsPermission3TestCases",
+ "options": [
+ {
+ "include-filter": "android.permission3.cts.SafetyLabelChangesJobServiceTest"
+ }
+ ]
+ },
+ {
+ "name": "CtsPermissionTestCases",
+ "options": [
+ {
+ "include-filter": "android.permission.cts.LocationAccessCheckTest"
+ }
+ ],
+ "file_patterns": ["LocationAccessCheck\\.java"]
+ },
+ {
"name": "CtsBackupTestCases",
"options": [
{
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 b930fa0cd..578b74783 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionDecisionStorageImpl.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/v33/PermissionDecisionStorageImpl.kt
@@ -26,6 +26,8 @@ import androidx.annotation.RequiresApi
import com.android.permissioncontroller.DeviceUtils
import com.android.permissioncontroller.PermissionControllerApplication
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
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/v33/SafetyCenterQsTileService.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/v33/SafetyCenterQsTileService.kt
index b6ee664c4..6ffd894ce 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/v33/SafetyCenterQsTileService.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/v33/SafetyCenterQsTileService.kt
@@ -17,13 +17,18 @@
package com.android.permissioncontroller.permission.service.v33
+import android.app.PendingIntent
+import android.app.PendingIntent.FLAG_IMMUTABLE
import android.content.ComponentName
import android.content.Intent
import android.content.pm.PackageManager
import android.os.IBinder
+import android.provider.DeviceConfig
import android.safetycenter.SafetyCenterManager
import android.service.quicksettings.Tile
import android.service.quicksettings.TileService
+import android.util.Log
+import com.android.modules.utils.build.SdkLevel
import com.android.permissioncontroller.R
/**
@@ -34,9 +39,18 @@ class SafetyCenterQsTileService : TileService() {
override fun onBind(intent: Intent?): IBinder? {
val scManager = getSystemService(SafetyCenterManager::class.java)!!
+ val qsTileComponentSettingFlags =
+ DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ QS_TILE_COMPONENT_SETTING_FLAGS,
+ PackageManager.DONT_KILL_APP
+ )
if (!scManager.isSafetyCenterEnabled) {
- packageManager.setComponentEnabledSetting(ComponentName(this, this::class.java),
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0)
+ packageManager.setComponentEnabledSetting(
+ ComponentName(this, this::class.java),
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ qsTileComponentSettingFlags
+ )
disabled = true
}
@@ -47,6 +61,10 @@ class SafetyCenterQsTileService : TileService() {
if (disabled) {
return
}
+ if (qsTile == null) {
+ Log.w(TAG, "qsTile was null, skipping tile update")
+ return
+ }
qsTile.label = getString(R.string.safety_privacy_qs_tile_title)
qsTile.subtitle = getString(R.string.safety_privacy_qs_tile_subtitle)
@@ -57,6 +75,20 @@ class SafetyCenterQsTileService : TileService() {
override fun onClick() {
val intent = Intent(Intent.ACTION_VIEW_SAFETY_CENTER_QS)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
- startActivityAndCollapse(intent)
+ if (SdkLevel.isAtLeastU()) {
+ startActivityAndCollapse(PendingIntent.getActivity(this, 0, intent, FLAG_IMMUTABLE))
+ } else {
+ startActivityAndCollapse(intent)
+ }
+ }
+
+ companion object {
+ /**
+ * Device config property to make sure toggling the tile does not kill the app during CTS
+ * tests and cause flakiness.
+ */
+ const val QS_TILE_COMPONENT_SETTING_FLAGS = "safety_center_qs_tile_component_setting_flags"
+
+ private const val TAG = "SafetyCenterQsTile"
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/v33/TEST_MAPPING b/PermissionController/src/com/android/permissioncontroller/permission/service/v33/TEST_MAPPING
new file mode 100644
index 000000000..3cad386bc
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/v33/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "packages/modules/Permission/SafetyCenter"
+ }
+ ]
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/v34/SafetyLabelChangesJobService.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/v34/SafetyLabelChangesJobService.kt
new file mode 100644
index 000000000..9231dc17b
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/v34/SafetyLabelChangesJobService.kt
@@ -0,0 +1,723 @@
+/*
+ * 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.service.v34
+
+import android.Manifest
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.app.job.JobInfo
+import android.app.job.JobParameters
+import android.app.job.JobScheduler
+import android.app.job.JobService
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.Intent.ACTION_BOOT_COMPLETED
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Bundle
+import android.os.PersistableBundle
+import android.os.Process
+import android.os.UserHandle
+import android.os.UserManager
+import android.provider.DeviceConfig
+import android.util.Log
+import androidx.annotation.RequiresApi
+import androidx.core.app.NotificationCompat
+import androidx.core.graphics.drawable.IconCompat
+import com.android.permission.safetylabel.DataCategoryConstants.CATEGORY_LOCATION
+import com.android.permission.safetylabel.SafetyLabel as AppMetadataSafetyLabel
+import com.android.permissioncontroller.Constants.EXTRA_SESSION_ID
+import com.android.permissioncontroller.Constants.INVALID_SESSION_ID
+import com.android.permissioncontroller.Constants.PERMISSION_REMINDER_CHANNEL_ID
+import com.android.permissioncontroller.Constants.SAFETY_LABEL_CHANGES_DETECT_UPDATES_JOB_ID
+import com.android.permissioncontroller.Constants.SAFETY_LABEL_CHANGES_NOTIFICATION_ID
+import com.android.permissioncontroller.Constants.SAFETY_LABEL_CHANGES_PERIODIC_NOTIFICATION_JOB_ID
+import com.android.permissioncontroller.PermissionControllerApplication
+import com.android.permissioncontroller.PermissionControllerStatsLog
+import com.android.permissioncontroller.PermissionControllerStatsLog.APP_DATA_SHARING_UPDATES_NOTIFICATION_INTERACTION
+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.v34.AppDataSharingUpdatesLiveData
+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
+import com.android.permissioncontroller.permission.model.v34.AppDataSharingUpdate
+import com.android.permissioncontroller.permission.utils.KotlinUtils
+import com.android.permissioncontroller.permission.utils.Utils.getSystemServiceSafe
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.AppInfo
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.SafetyLabel as SafetyLabelForPersistence
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistoryPersistence
+import java.time.Duration
+import java.time.Instant
+import java.time.ZoneId
+import java.util.Random
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+import kotlinx.coroutines.yield
+
+/**
+ * Runs a monthly job that performs Safety Labels-related tasks. (E.g., data policy changes
+ * notification, hygiene, etc.)
+ */
+// TODO(b/265202443): Review support for safe cancellation of this Job. Currently this is
+// implemented by implementing `onStopJob` method and including `yield()` calls in computation
+// loops.
+// TODO(b/276511043): Refactor this class into separate components
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+class SafetyLabelChangesJobService : JobService() {
+ private val mutex = Mutex()
+ private var detectUpdatesJob: Job? = null
+ private var notificationJob: Job? = null
+ private val context = this@SafetyLabelChangesJobService
+ private val random = Random()
+
+ class Receiver : BroadcastReceiver() {
+ override fun onReceive(receiverContext: Context, intent: Intent) {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Received broadcast with intent action '${intent.action}'")
+ }
+ if (!KotlinUtils.isSafetyLabelChangeNotificationsEnabled(receiverContext)) {
+ Log.i(LOG_TAG, "onReceive: Safety label change notifications are not enabled.")
+ return
+ }
+ if (KotlinUtils.safetyLabelChangesJobServiceKillSwitch()) {
+ Log.i(LOG_TAG, "onReceive: kill switch is set.")
+ return
+ }
+ if (isContextInProfileUser(receiverContext)) {
+ Log.i(
+ LOG_TAG,
+ "onReceive: Received broadcast in profile, not scheduling safety label" +
+ " change job"
+ )
+ return
+ }
+ if (
+ intent.action != ACTION_BOOT_COMPLETED &&
+ intent.action != ACTION_SET_UP_SAFETY_LABEL_CHANGES_JOB
+ ) {
+ return
+ }
+ scheduleDetectUpdatesJob(receiverContext)
+ schedulePeriodicNotificationJob(receiverContext)
+ }
+
+ private fun isContextInProfileUser(context: Context): Boolean {
+ val userManager: UserManager = context.getSystemService(UserManager::class.java)!!
+ return userManager.isProfile
+ }
+ }
+
+ /** Handle the case where the notification is swiped away without further interaction. */
+ class NotificationDeleteHandler : BroadcastReceiver() {
+ override fun onReceive(receiverContext: Context, intent: Intent) {
+ Log.d(LOG_TAG, "NotificationDeleteHandler: received broadcast")
+ if (!KotlinUtils.isSafetyLabelChangeNotificationsEnabled(receiverContext)) {
+ Log.i(
+ LOG_TAG,
+ "NotificationDeleteHandler: " +
+ "safety label change notifications are not enabled."
+ )
+ return
+ }
+ val sessionId = intent.getLongExtra(EXTRA_SESSION_ID, INVALID_SESSION_ID)
+ val numberOfAppUpdates = intent.getIntExtra(EXTRA_NUMBER_OF_APP_UPDATES, 0)
+ logAppDataSharingUpdatesNotificationInteraction(
+ sessionId,
+ APP_DATA_SHARING_UPDATES_NOTIFICATION_INTERACTION__ACTION__DISMISSED,
+ numberOfAppUpdates
+ )
+ }
+ }
+
+ /**
+ * Called for two different jobs: the detect updates job
+ * [SAFETY_LABEL_CHANGES_DETECT_UPDATES_JOB_ID] and the notification job
+ * [SAFETY_LABEL_CHANGES_PERIODIC_NOTIFICATION_JOB_ID].
+ */
+ override fun onStartJob(params: JobParameters): Boolean {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "onStartJob called for job id: ${params.jobId}")
+ }
+ if (!KotlinUtils.isSafetyLabelChangeNotificationsEnabled(context)) {
+ Log.w(LOG_TAG, "Not starting job: safety label change notifications are not enabled.")
+ return false
+ }
+ if (KotlinUtils.safetyLabelChangesJobServiceKillSwitch()) {
+ Log.i(LOG_TAG, "Not starting job: kill switch is set.")
+ return false
+ }
+ when (params.jobId) {
+ SAFETY_LABEL_CHANGES_DETECT_UPDATES_JOB_ID -> {
+ dispatchDetectUpdatesJob(params)
+ return true
+ }
+ SAFETY_LABEL_CHANGES_PERIODIC_NOTIFICATION_JOB_ID -> {
+ dispatchNotificationJob(params)
+ return true
+ }
+ else -> Log.w(LOG_TAG, "Unexpected job Id: ${params.jobId}")
+ }
+ return false
+ }
+
+ private fun dispatchDetectUpdatesJob(params: JobParameters) {
+ Log.i(LOG_TAG, "Dispatching detect updates job")
+ detectUpdatesJob =
+ GlobalScope.launch(Dispatchers.Default) {
+ try {
+ Log.i(LOG_TAG, "Detect updates job started")
+ runDetectUpdatesJob()
+ Log.i(LOG_TAG, "Detect updates job finished successfully")
+ } catch (e: Throwable) {
+ Log.e(LOG_TAG, "Detect updates job failed", e)
+ throw e
+ } finally {
+ jobFinished(params, false)
+ }
+ }
+ }
+
+ private fun dispatchNotificationJob(params: JobParameters) {
+ Log.i(LOG_TAG, "Dispatching notification job")
+ notificationJob =
+ GlobalScope.launch(Dispatchers.Default) {
+ try {
+ Log.i(LOG_TAG, "Notification job started")
+ runNotificationJob()
+ Log.i(LOG_TAG, "Notification job finished successfully")
+ } catch (e: Throwable) {
+ Log.e(LOG_TAG, "Notification job failed", e)
+ throw e
+ } finally {
+ jobFinished(params, false)
+ }
+ }
+ }
+
+ private suspend fun runDetectUpdatesJob() {
+ mutex.withLock { recordSafetyLabelsIfMissing() }
+ }
+
+ private suspend fun runNotificationJob() {
+ mutex.withLock {
+ recordSafetyLabelsIfMissing()
+ deleteSafetyLabelsNoLongerNeeded()
+ postSafetyLabelChangedNotification()
+ }
+ }
+
+ /**
+ * Records safety labels for apps that may not have propagated their safety labels to
+ * persistence through [SafetyLabelChangedBroadcastReceiver].
+ *
+ * This is done by:
+ * 1. Initializing safety labels for apps that are relevant, but have no persisted safety labels
+ * yet.
+ * 2. Update safety labels for apps that are relevant and have persisted safety labels, if we
+ * identify that we have missed an update for them.
+ */
+ private suspend fun recordSafetyLabelsIfMissing() {
+ val historyFile = AppsSafetyLabelHistoryPersistence.getSafetyLabelHistoryFile(context)
+ val safetyLabelsLastUpdatedTimes: Map<AppInfo, Instant> =
+ AppsSafetyLabelHistoryPersistence.getSafetyLabelsLastUpdatedTimes(historyFile)
+ // Retrieve all installed packages that are store installed on the system and
+ // that request the location permission; these are the packages that we care about for the
+ // safety labels feature. The variable name does not specify all these filters for brevity.
+ val packagesRequestingLocation: Set<Pair<String, UserHandle>> =
+ getAllStoreInstalledPackagesRequestingLocation()
+
+ val safetyLabelsToRecord = mutableSetOf<SafetyLabelForPersistence>()
+ val packageNamesWithPersistedSafetyLabels =
+ safetyLabelsLastUpdatedTimes.keys.map { it.packageName }
+
+ // Partition relevant apps by whether we already store safety labels for them.
+ val (packagesToConsiderUpdate, packagesToInitialize) =
+ packagesRequestingLocation.partition { (packageName, _) ->
+ packageName in packageNamesWithPersistedSafetyLabels
+ }
+ if (DEBUG) {
+ Log.d(
+ LOG_TAG,
+ "recording safety labels if missing:" +
+ " packagesRequestingLocation:" +
+ " $packagesRequestingLocation, packageNamesWithPersistedSafetyLabels:" +
+ " $packageNamesWithPersistedSafetyLabels"
+ )
+ }
+ safetyLabelsToRecord.addAll(getSafetyLabels(packagesToInitialize))
+ safetyLabelsToRecord.addAll(
+ getSafetyLabelsIfUpdatesMissed(packagesToConsiderUpdate, safetyLabelsLastUpdatedTimes)
+ )
+
+ AppsSafetyLabelHistoryPersistence.recordSafetyLabels(safetyLabelsToRecord, historyFile)
+ }
+
+ private suspend fun getSafetyLabels(
+ packages: List<Pair<String, UserHandle>>
+ ): List<SafetyLabelForPersistence> {
+ val safetyLabelsToPersist = mutableListOf<SafetyLabelForPersistence>()
+
+ for ((packageName, user) in packages) {
+ yield() // cancellation point
+ val safetyLabelToPersist = getSafetyLabelToPersist(Pair(packageName, user))
+ if (safetyLabelToPersist != null) {
+ safetyLabelsToPersist.add(safetyLabelToPersist)
+ }
+ }
+ return safetyLabelsToPersist
+ }
+
+ private suspend fun getSafetyLabelsIfUpdatesMissed(
+ packages: List<Pair<String, UserHandle>>,
+ safetyLabelsLastUpdatedTimes: Map<AppInfo, Instant>
+ ): List<SafetyLabelForPersistence> {
+ val safetyLabelsToPersist = mutableListOf<SafetyLabelForPersistence>()
+ for ((packageName, user) in packages) {
+ yield() // cancellation point
+
+ // If safety labels are considered up-to-date, continue as there is no need to retrieve
+ // the latest safety label; it was already captured.
+ if (areSafetyLabelsUpToDate(Pair(packageName, user), safetyLabelsLastUpdatedTimes)) {
+ continue
+ }
+
+ val safetyLabelToPersist = getSafetyLabelToPersist(Pair(packageName, user))
+ if (safetyLabelToPersist != null) {
+ safetyLabelsToPersist.add(safetyLabelToPersist)
+ }
+ }
+
+ return safetyLabelsToPersist
+ }
+
+ /**
+ * Returns whether the provided app's safety labels are up-to-date by checking that there have
+ * been no app updates since the persisted safety label history was last updated.
+ */
+ private suspend fun areSafetyLabelsUpToDate(
+ packageKey: Pair<String, UserHandle>,
+ safetyLabelsLastUpdatedTimes: Map<AppInfo, Instant>
+ ): Boolean {
+ val lightPackageInfo = LightPackageInfoLiveData[packageKey].getInitializedValue()
+ val lastAppUpdateTime: Instant = Instant.ofEpochMilli(lightPackageInfo?.lastUpdateTime ?: 0)
+ val latestSafetyLabelUpdateTime: Instant? =
+ safetyLabelsLastUpdatedTimes[AppInfo(packageKey.first)]
+ return latestSafetyLabelUpdateTime != null &&
+ !lastAppUpdateTime.isAfter(latestSafetyLabelUpdateTime)
+ }
+
+ private suspend fun getSafetyLabelToPersist(
+ packageKey: Pair<String, UserHandle>
+ ): SafetyLabelForPersistence? {
+ val (packageName, user) = packageKey
+
+ // Get the context for the user in which the app is installed.
+ val userContext =
+ if (user == Process.myUserHandle()) {
+ context
+ } else {
+ context.createContextAsUser(user, 0)
+ }
+ val appMetadataBundle: PersistableBundle =
+ try {
+ userContext.packageManager.getAppMetadata(packageName)
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(LOG_TAG, "Package $packageName not found while retrieving app metadata")
+ return null
+ }
+ val appMetadataSafetyLabel: AppMetadataSafetyLabel =
+ AppMetadataSafetyLabel.getSafetyLabelFromMetadata(appMetadataBundle) ?: return null
+ val lastUpdateTime =
+ Instant.ofEpochMilli(
+ LightPackageInfoLiveData[packageKey].getInitializedValue()?.lastUpdateTime ?: 0
+ )
+
+ val safetyLabelForPersistence: SafetyLabelForPersistence =
+ AppsSafetyLabelHistory.SafetyLabel.extractLocationSharingSafetyLabel(
+ packageName,
+ lastUpdateTime,
+ appMetadataSafetyLabel
+ )
+
+ return safetyLabelForPersistence
+ }
+
+ /**
+ * Deletes safety labels from persistence that are no longer necessary to persist.
+ *
+ * This is done by:
+ * 1. Deleting safety labels for apps that are no longer relevant (e.g. app not installed or app
+ * not requesting location permission).
+ * 2. Delete safety labels if there are multiple safety labels prior to the update period; at
+ * most one safety label is necessary to be persisted prior to the update period to determine
+ * updates to safety labels.
+ */
+ private suspend fun deleteSafetyLabelsNoLongerNeeded() {
+ val historyFile = AppsSafetyLabelHistoryPersistence.getSafetyLabelHistoryFile(context)
+ val safetyLabelsLastUpdatedTimes: Map<AppInfo, Instant> =
+ AppsSafetyLabelHistoryPersistence.getSafetyLabelsLastUpdatedTimes(historyFile)
+ // Retrieve all installed packages that are store installed on the system and
+ // that request the location permission; these are the packages that we care about for the
+ // safety labels feature. The variable name does not specify all these filters for brevity.
+ val packagesRequestingLocation: Set<Pair<String, UserHandle>> =
+ getAllStoreInstalledPackagesRequestingLocation()
+
+ val packageNamesWithPersistedSafetyLabels: List<String> =
+ safetyLabelsLastUpdatedTimes.keys.map { appInfo -> appInfo.packageName }
+ val packageNamesWithRelevantSafetyLabels: List<String> =
+ packagesRequestingLocation.map { (packageName, _) -> packageName }
+
+ val appInfosToDelete: Set<AppInfo> =
+ packageNamesWithPersistedSafetyLabels
+ .filter { packageName -> packageName !in packageNamesWithRelevantSafetyLabels }
+ .map { packageName -> AppInfo(packageName) }
+ .toSet()
+ AppsSafetyLabelHistoryPersistence.deleteSafetyLabelsForApps(appInfosToDelete, historyFile)
+
+ val updatePeriod =
+ DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ DATA_SHARING_UPDATE_PERIOD_PROPERTY,
+ Duration.ofDays(DEFAULT_DATA_SHARING_UPDATE_PERIOD_DAYS).toMillis()
+ )
+ AppsSafetyLabelHistoryPersistence.deleteSafetyLabelsOlderThan(
+ Instant.now().atZone(ZoneId.systemDefault()).toInstant().minusMillis(updatePeriod),
+ historyFile
+ )
+ }
+
+ // TODO(b/261607291): Modify this logic when we enable safety label change notifications for
+ // preinstalled apps.
+ private suspend fun getAllStoreInstalledPackagesRequestingLocation():
+ Set<Pair<String, UserHandle>> =
+ getAllPackagesRequestingLocation()
+ .filter { isSafetyLabelSupported(it) }
+ .toSet()
+
+ private suspend fun getAllPackagesRequestingLocation(): Set<Pair<String, UserHandle>> =
+ SinglePermGroupPackagesUiInfoLiveData[Manifest.permission_group.LOCATION]
+ .getInitializedValue(staleOk = false, forceUpdate = true)
+ .keys
+
+ private suspend fun getAllPackagesGrantedLocation(): Set<Pair<String, UserHandle>> =
+ SinglePermGroupPackagesUiInfoLiveData[Manifest.permission_group.LOCATION]
+ .getInitializedValue(staleOk = false, forceUpdate = true)
+ .filter { (_, appPermGroupUiInfo) -> appPermGroupUiInfo.isPermissionGranted() }
+ .keys
+
+ private fun AppPermGroupUiInfo.isPermissionGranted() =
+ permGrantState in setOf(PERMS_ALLOWED_ALWAYS, PERMS_ALLOWED_FOREGROUND_ONLY)
+
+ private suspend fun isSafetyLabelSupported(packageUser: Pair<String, UserHandle>): Boolean {
+ val lightInstallSourceInfo =
+ LightInstallSourceInfoLiveData[packageUser].getInitializedValue()
+ return lightInstallSourceInfo.supportsSafetyLabel
+ }
+
+ private suspend fun postSafetyLabelChangedNotification() {
+ val numberOfAppUpdates = getNumberOfAppsWithDataSharingChanged()
+ if (numberOfAppUpdates > 0) {
+ Log.i(LOG_TAG, "Showing notification: data sharing has changed")
+ showNotification(numberOfAppUpdates)
+ } else {
+ cancelNotification()
+ Log.i(LOG_TAG, "Not showing notification: data sharing has not changed")
+ }
+ }
+
+ override fun onStopJob(params: JobParameters?): Boolean {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "onStopJob called for job id: ${params?.jobId}")
+ }
+ runBlocking {
+ when (params?.jobId) {
+ SAFETY_LABEL_CHANGES_DETECT_UPDATES_JOB_ID -> {
+ Log.i(LOG_TAG, "onStopJob: cancelling detect updates job")
+ detectUpdatesJob?.cancel()
+ detectUpdatesJob = null
+ }
+ SAFETY_LABEL_CHANGES_PERIODIC_NOTIFICATION_JOB_ID -> {
+ Log.i(LOG_TAG, "onStopJob: cancelling notification job")
+ notificationJob?.cancel()
+ notificationJob = null
+ }
+ else -> Log.w(LOG_TAG, "onStopJob: unexpected job Id: ${params?.jobId}")
+ }
+ }
+ return true
+ }
+
+ /**
+ * Count the number of packages that have location granted and have location sharing updates.
+ */
+ private suspend fun getNumberOfAppsWithDataSharingChanged(): Int {
+ val appDataSharingUpdates =
+ AppDataSharingUpdatesLiveData(PermissionControllerApplication.get())
+ .getInitializedValue()
+
+ return appDataSharingUpdates
+ .map { appDataSharingUpdate ->
+ val locationDataSharingUpdate =
+ appDataSharingUpdate.categorySharingUpdates[CATEGORY_LOCATION]
+
+ if (locationDataSharingUpdate == null) {
+ emptyList()
+ } else {
+ val users =
+ SinglePermGroupPackagesUiInfoLiveData[Manifest.permission_group.LOCATION]
+ .getUsersWithPermGrantedForApp(appDataSharingUpdate.packageName)
+ users
+ }
+ }
+ .flatten()
+ .count()
+ }
+
+ private fun SinglePermGroupPackagesUiInfoLiveData.getUsersWithPermGrantedForApp(
+ packageName: String
+ ): List<UserHandle> {
+ return value
+ ?.filter {
+ packageToPermInfoEntry: Map.Entry<Pair<String, UserHandle>, AppPermGroupUiInfo> ->
+ val appPermGroupUiInfo = packageToPermInfoEntry.value
+
+ appPermGroupUiInfo.isPermissionGranted()
+ }
+ ?.keys
+ ?.filter { packageUser: Pair<String, UserHandle> -> packageUser.first == packageName }
+ ?.map { packageUser: Pair<String, UserHandle> -> packageUser.second }
+ ?: listOf()
+ }
+
+ private fun AppDataSharingUpdate.containsLocationCategoryUpdate() =
+ categorySharingUpdates[CATEGORY_LOCATION] != null
+
+ private fun showNotification(numberOfAppUpdates: Int) {
+ var sessionId = INVALID_SESSION_ID
+ while (sessionId == INVALID_SESSION_ID) {
+ sessionId = random.nextLong()
+ }
+ val context = PermissionControllerApplication.get() as Context
+ val notificationManager = getSystemServiceSafe(context, NotificationManager::class.java)
+ createNotificationChannel(context, notificationManager)
+
+ val (appLabel, smallIcon, color) = KotlinUtils.getSafetyCenterNotificationResources(this)
+ 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 =
+ NotificationCompat.Builder(context, PERMISSION_REMINDER_CHANNEL_ID)
+ .setColor(color)
+ .setSmallIcon(smallIconCompat)
+ .setContentTitle(title)
+ .setContentText(text)
+ .setPriority(NotificationCompat.PRIORITY_DEFAULT)
+ .setLocalOnly(true)
+ .setAutoCancel(true)
+ .setSilent(true)
+ .setContentIntent(createIntentToOpenAppDataSharingUpdates(context, sessionId))
+ .setDeleteIntent(
+ createIntentToLogDismissNotificationEvent(
+ context,
+ sessionId,
+ numberOfAppUpdates
+ )
+ )
+ notificationBuilder.addExtras(
+ Bundle().apply { putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, appLabel) }
+ )
+
+ notificationManager.notify(
+ SAFETY_LABEL_CHANGES_NOTIFICATION_ID,
+ notificationBuilder.build()
+ )
+
+ logAppDataSharingUpdatesNotificationInteraction(
+ sessionId,
+ APP_DATA_SHARING_UPDATES_NOTIFICATION_INTERACTION__ACTION__NOTIFICATION_SHOWN,
+ numberOfAppUpdates
+ )
+ Log.v(LOG_TAG, "Safety label change notification sent.")
+ }
+
+ private fun cancelNotification() {
+ val notificationManager = getSystemServiceSafe(context, NotificationManager::class.java)
+ notificationManager.cancel(SAFETY_LABEL_CHANGES_NOTIFICATION_ID)
+ Log.v(LOG_TAG, "Safety label change notification cancelled.")
+ }
+
+ private fun createIntentToOpenAppDataSharingUpdates(
+ context: Context,
+ sessionId: Long
+ ): PendingIntent {
+ return PendingIntent.getActivity(
+ context,
+ 0,
+ Intent(Intent.ACTION_REVIEW_APP_DATA_SHARING_UPDATES).apply {
+ putExtra(EXTRA_SESSION_ID, sessionId)
+ },
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+ }
+
+ private fun createIntentToLogDismissNotificationEvent(
+ context: Context,
+ sessionId: Long,
+ numberOfAppUpdates: Int
+ ): PendingIntent {
+ return PendingIntent.getBroadcast(
+ context,
+ 0,
+ Intent(context, NotificationDeleteHandler::class.java).apply {
+ putExtra(EXTRA_SESSION_ID, sessionId)
+ putExtra(EXTRA_NUMBER_OF_APP_UPDATES, numberOfAppUpdates)
+ },
+ PendingIntent.FLAG_ONE_SHOT or
+ PendingIntent.FLAG_UPDATE_CURRENT or
+ PendingIntent.FLAG_IMMUTABLE
+ )
+ }
+
+ private fun createNotificationChannel(
+ context: Context,
+ notificationManager: NotificationManager
+ ) {
+ val notificationChannel =
+ NotificationChannel(
+ PERMISSION_REMINDER_CHANNEL_ID,
+ context.getString(R.string.permission_reminders),
+ NotificationManager.IMPORTANCE_LOW
+ )
+
+ notificationManager.createNotificationChannel(notificationChannel)
+ }
+
+ companion object {
+ private val LOG_TAG = SafetyLabelChangesJobService::class.java.simpleName
+ private const val DEBUG = true
+
+ private const val ACTION_SET_UP_SAFETY_LABEL_CHANGES_JOB =
+ "com.android.permissioncontroller.action.SET_UP_SAFETY_LABEL_CHANGES_JOB"
+ private const val EXTRA_NUMBER_OF_APP_UPDATES =
+ "com.android.permissioncontroller.extra.NUMBER_OF_APP_UPDATES"
+
+ private const val DATA_SHARING_UPDATE_PERIOD_PROPERTY = "data_sharing_update_period_millis"
+ private const val DEFAULT_DATA_SHARING_UPDATE_PERIOD_DAYS: Long = 30
+
+ private fun scheduleDetectUpdatesJob(context: Context) {
+ try {
+ val jobScheduler = getSystemServiceSafe(context, JobScheduler::class.java)
+
+ if (
+ jobScheduler.getPendingJob(SAFETY_LABEL_CHANGES_DETECT_UPDATES_JOB_ID) != null
+ ) {
+ Log.i(LOG_TAG, "Not scheduling detect updates job: already scheduled.")
+ return
+ }
+
+ val job =
+ JobInfo.Builder(
+ SAFETY_LABEL_CHANGES_DETECT_UPDATES_JOB_ID,
+ ComponentName(context, SafetyLabelChangesJobService::class.java)
+ )
+ .setRequiresDeviceIdle(
+ KotlinUtils.runSafetyLabelChangesJobOnlyWhenDeviceIdle()
+ )
+ .build()
+ val result = jobScheduler.schedule(job)
+ if (result != JobScheduler.RESULT_SUCCESS) {
+ Log.w(LOG_TAG, "Detect updates job not scheduled, result code: $result")
+ } else {
+ Log.i(LOG_TAG, "Detect updates job scheduled successfully.")
+ }
+ } catch (e: Throwable) {
+ Log.e(LOG_TAG, "Failed to schedule detect updates job", e)
+ throw e
+ }
+ }
+
+ private fun schedulePeriodicNotificationJob(context: Context) {
+ try {
+ val jobScheduler = getSystemServiceSafe(context, JobScheduler::class.java)
+ if (
+ jobScheduler.getPendingJob(SAFETY_LABEL_CHANGES_PERIODIC_NOTIFICATION_JOB_ID) !=
+ null
+ ) {
+ Log.i(LOG_TAG, "Not scheduling notification job: already scheduled.")
+ return
+ }
+
+ val job =
+ JobInfo.Builder(
+ SAFETY_LABEL_CHANGES_PERIODIC_NOTIFICATION_JOB_ID,
+ ComponentName(context, SafetyLabelChangesJobService::class.java)
+ )
+ .setRequiresDeviceIdle(
+ KotlinUtils.runSafetyLabelChangesJobOnlyWhenDeviceIdle()
+ )
+ .setPeriodic(KotlinUtils.getSafetyLabelChangesJobIntervalMillis())
+ .setPersisted(true)
+ .build()
+ val result = jobScheduler.schedule(job)
+ if (result != JobScheduler.RESULT_SUCCESS) {
+ Log.w(LOG_TAG, "Notification job not scheduled, result code: $result")
+ } else {
+ Log.i(LOG_TAG, "Notification job scheduled successfully.")
+ }
+ } catch (e: Throwable) {
+ Log.e(LOG_TAG, "Failed to schedule notification job", e)
+ throw e
+ }
+ }
+
+ private fun logAppDataSharingUpdatesNotificationInteraction(
+ sessionId: Long,
+ interactionType: Int,
+ numberOfAppUpdates: Int
+ ) {
+ PermissionControllerStatsLog.write(
+ APP_DATA_SHARING_UPDATES_NOTIFICATION_INTERACTION,
+ sessionId,
+ interactionType,
+ numberOfAppUpdates
+ )
+ Log.v(
+ LOG_TAG,
+ "Notification interaction occurred with" +
+ " sessionId=$sessionId" +
+ " action=$interactionType" +
+ " numberOfAppUpdates=$numberOfAppUpdates"
+ )
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/v34/package-info.java b/PermissionController/src/com/android/permissioncontroller/permission/service/v34/package-info.java
new file mode 100644
index 000000000..0625654c0
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/v34/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+@androidx.annotation.RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+package com.android.permissioncontroller.permission.service.v34;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/AutoGrantPermissionsNotifier.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/AutoGrantPermissionsNotifier.java
index 6d81983aa..e9ed63b9a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/AutoGrantPermissionsNotifier.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/AutoGrantPermissionsNotifier.java
@@ -30,6 +30,8 @@ import static android.os.UserHandle.getUserHandleForUid;
import static com.android.permissioncontroller.Constants.ADMIN_AUTO_GRANTED_PERMISSIONS_ALERTING_NOTIFICATION_CHANNEL_ID;
import static com.android.permissioncontroller.Constants.ADMIN_AUTO_GRANTED_PERMISSIONS_NOTIFICATION_CHANNEL_ID;
+import static com.android.permissioncontroller.Constants.ADMIN_AUTO_GRANTED_PERMISSIONS_NOTIFICATION_GROUP_ID;
+import static com.android.permissioncontroller.Constants.ADMIN_AUTO_GRANTED_PERMISSIONS_NOTIFICATION_SUMMARY_ID;
import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
import static com.android.permissioncontroller.Constants.PERMISSION_GRANTED_BY_ADMIN_NOTIFICATION_ID;
import static com.android.permissioncontroller.permission.utils.Utils.getSystemServiceSafe;
@@ -154,14 +156,15 @@ public class AutoGrantPermissionsNotifier {
int packageBasedRequestCode = mPackageInfo.packageName.hashCode();
String title = mContext.getString(
- R.string.auto_granted_location_permission_notification_title);
+ R.string.auto_granted_location_permission_notification_title, pkgLabel);
String messageText = Utils.getEnterpriseString(mContext, LOCATION_AUTO_GRANTED_MESSAGE,
R.string.auto_granted_permission_notification_body, pkgLabel);
- Notification.Builder b = (new Notification.Builder(mContext,
+ Notification.Builder notificationBuilder = (new Notification.Builder(mContext,
getNotificationChannelId(shouldNotifySilently))).setContentTitle(title)
.setContentText(messageText)
.setStyle(new Notification.BigTextStyle().bigText(messageText).setBigContentTitle(
title))
+ .setGroup(ADMIN_AUTO_GRANTED_PERMISSIONS_NOTIFICATION_GROUP_ID)
// NOTE: Different icons would be needed for different permissions.
.setSmallIcon(R.drawable.ic_pin_drop)
.setLargeIcon(pkgIconBmp)
@@ -174,9 +177,18 @@ public class AutoGrantPermissionsNotifier {
if (appName != null) {
Bundle extras = new Bundle();
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, appName.toString());
- b.addExtras(extras);
+ notificationBuilder.addExtras(extras);
}
+ String summaryTitle = mContext.getString(R.string.auto_granted_permissions);
+
+ Notification.Builder summaryNotificationBuilder = new Notification.Builder(mContext,
+ getNotificationChannelId(shouldNotifySilently))
+ .setContentTitle(summaryTitle)
+ .setSmallIcon(R.drawable.ic_pin_drop)
+ .setGroup(ADMIN_AUTO_GRANTED_PERMISSIONS_NOTIFICATION_GROUP_ID)
+ .setGroupSummary(true);
+
NotificationManager notificationManager = getSystemServiceSafe(mContext,
NotificationManager.class);
// Cancel previous notifications for the same package to avoid redundant notifications.
@@ -188,7 +200,9 @@ public class AutoGrantPermissionsNotifier {
mPackageInfo.packageName, PERMISSION_GRANTED_BY_ADMIN_NOTIFICATION_ID);
notificationManager.notify(mPackageInfo.packageName,
PERMISSION_GRANTED_BY_ADMIN_NOTIFICATION_ID,
- b.build());
+ notificationBuilder.build());
+ notificationManager.notify(ADMIN_AUTO_GRANTED_PERMISSIONS_NOTIFICATION_SUMMARY_ID,
+ summaryNotificationBuilder.build());
}
/**
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java
index 9781cb472..ff63cdae5 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java
@@ -18,22 +18,35 @@ package com.android.permissioncontroller.permission.ui;
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.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.CANCELED;
import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.DENIED;
import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.DENIED_DO_NOT_ASK_AGAIN;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.DENIED_MORE;
import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.GRANTED_ALWAYS;
import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.GRANTED_FOREGROUND_ONLY;
import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.GRANTED_ONE_TIME;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.GRANTED_USER_SELECTED;
+import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.LINKED_TO_PERMISSION_RATIONALE;
import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.LINKED_TO_SETTINGS;
+import static com.android.permissioncontroller.permission.ui.model.GrantPermissionsViewModel.APP_PERMISSION_REQUEST_CODE;
+import static com.android.permissioncontroller.permission.ui.model.GrantPermissionsViewModel.PHOTO_PICKER_REQUEST_CODE;
import static com.android.permissioncontroller.permission.utils.Utils.getRequestMessage;
+import android.Manifest;
+import android.app.Activity;
import android.app.KeyguardManager;
import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.drawable.Icon;
+import android.os.Build;
import android.os.Bundle;
import android.os.Process;
import android.text.Annotation;
@@ -51,24 +64,27 @@ import android.view.inputmethod.InputMethodManager;
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.v31.GrantPermissionsViewModel;
-import com.android.permissioncontroller.permission.ui.model.v31.GrantPermissionsViewModel.RequestInfo;
-import com.android.permissioncontroller.permission.ui.model.v31.GrantPermissionsViewModelFactory;
+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.wear.GrantPermissionsWearViewHandler;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
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;
/**
@@ -77,13 +93,13 @@ import java.util.Random;
public class GrantPermissionsActivity extends SettingsActivity
implements GrantPermissionsViewHandler.ResultListener {
- private static final String LOG_TAG = "GrantPermissionsActivit";
+ private static final String LOG_TAG = "GrantPermissionsActivity";
private static final String KEY_SESSION_ID = GrantPermissionsActivity.class.getName()
+ "_REQUEST_ID";
public static final String ANNOTATION_ID = "link";
- public static final int NEXT_BUTTON = 11;
+ public static final int NEXT_BUTTON = 15;
public static final int ALLOW_BUTTON = 0;
public static final int ALLOW_ALWAYS_BUTTON = 1; // Used in auto
public static final int ALLOW_FOREGROUND_BUTTON = 2;
@@ -95,6 +111,11 @@ public class GrantPermissionsActivity extends SettingsActivity
public static final int NO_UPGRADE_OT_BUTTON = 8; // one-time
public static final int NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON = 9; // one-time
public static final int LINK_TO_SETTINGS = 10;
+ public static final int ALLOW_ALL_BUTTON = 11; // button for options with a picker, allow all
+ public static final int ALLOW_SELECTED_BUTTON = 12; // allow selected, with picker
+ // button to cancel a request for more data with a picker
+ public static final int DONT_ALLOW_MORE_SELECTED_BUTTON = 13;
+ public static final int LINK_TO_PERMISSION_RATIONALE = 14;
public static final int NEXT_LOCATION_DIALOG = 6;
public static final int LOCATION_ACCURACY_LAYOUT = 0;
@@ -108,13 +129,13 @@ public class GrantPermissionsActivity extends SettingsActivity
ACCESS_COARSE_LOCATION, 0,
ACCESS_FINE_LOCATION, 1);
- private static final int APP_PERMISSION_REQUEST_CODE = 1;
+ public static final String INTENT_PHOTOS_SELECTED = "intent_extra_result";
/**
* A map of the currently shown GrantPermissionsActivity for this user, per package and task ID
*/
@GuardedBy("sCurrentGrantRequests")
- private static final Map<Pair<String, Integer>, GrantPermissionsActivity>
+ public static final Map<Pair<String, Integer>, GrantPermissionsActivity>
sCurrentGrantRequests = new HashMap<>();
/** Unique Id of a request */
@@ -127,12 +148,12 @@ public class GrantPermissionsActivity extends SettingsActivity
private String mPreMergeShownGroupName;
/** The current list of permissions requested, across all current requests for this app */
- private String[] mRequestedPermissions;
- /** The list of permissions requested in the intent to this activity*/
- private String[] mOriginalRequestedPermissions;
+ private List<String> mRequestedPermissions = new ArrayList<>();
+ /** A copy of the list of permissions originally requested in the intent to this activity */
+ private String[] mOriginalRequestedPermissions = new String[0];
private boolean[] mButtonVisibilities;
- private boolean[] mLocationVisibilities;
+ private int mRequestCounts = 0;
private List<RequestInfo> mRequestInfos = new ArrayList<>();
private GrantPermissionsViewHandler mViewHandler;
private GrantPermissionsViewModel mViewModel;
@@ -143,16 +164,18 @@ public class GrantPermissionsActivity extends SettingsActivity
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 mTotalRequests = 0;
private int mCurrentRequestIdx = 0;
private float mOriginalDimAmount;
private View mRootView;
+ private int mStoragePermGroupIcon = R.drawable.ic_empty_icon;
@Override
public void onCreate(Bundle icicle) {
@@ -169,10 +192,9 @@ public class GrantPermissionsActivity extends SettingsActivity
getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
- mRequestedPermissions = getIntent()
- .getStringArrayExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES);
-
+ int permissionsSdkLevel;
if (PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(getIntent().getAction())) {
+ mIsSystemTriggered = true;
mTargetPackage = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
if (mTargetPackage == null) {
Log.e(LOG_TAG, "null EXTRA_PACKAGE_NAME. Must be set for "
@@ -180,44 +202,60 @@ public class GrantPermissionsActivity extends SettingsActivity
finishAfterTransition();
return;
}
- } else if (getCallingPackage() == null) {
- Log.e(LOG_TAG, "null callingPackageName. Please use \"RequestPermission\" to "
- + "request permissions");
- finishAfterTransition();
- return;
+ // We don't want to do any filtering in this case.
+ // These calls are coming from the system on behalf of the app.
+ permissionsSdkLevel = Build.VERSION_CODES.CUR_DEVELOPMENT;
} else {
// Cache this as this can only read on onCreate, not later.
mTargetPackage = getCallingPackage();
-
- // If this app is below the android T targetSdk, filter out the POST_NOTIFICATIONS
- // permission, if present
- mRequestedPermissions = GrantPermissionsViewModel.Companion
- .filterNotificationPermissionIfNeededSync(
- mTargetPackage, mRequestedPermissions);
+ if (mTargetPackage == null) {
+ Log.e(LOG_TAG, "null callingPackageName. Please use \"RequestPermission\" to "
+ + "request permissions");
+ finishAfterTransition();
+ return;
+ }
+ try {
+ PackageInfo packageInfo = getPackageManager().getPackageInfo(mTargetPackage, 0);
+ permissionsSdkLevel = packageInfo.applicationInfo.targetSdkVersion;
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(LOG_TAG, "Unable to get package info for the calling package.", e);
+ finishAfterTransition();
+ return;
+ }
}
+ String[] requestedPermissionsArray = getIntent().getStringArrayExtra(
+ PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES);
+ if (requestedPermissionsArray == null) {
+ setResultAndFinish();
+ return;
+ }
- if (mRequestedPermissions == null || mRequestedPermissions.length == 0) {
+ mRequestedPermissions = GrantPermissionsViewModel.Companion.getSanitizedPermissionsList(
+ requestedPermissionsArray, permissionsSdkLevel);
+ if (mRequestedPermissions.isEmpty()) {
setResultAndFinish();
return;
}
- mOriginalRequestedPermissions = mRequestedPermissions;
+
+ mOriginalRequestedPermissions = mRequestedPermissions.toArray(new String[0]);
synchronized (sCurrentGrantRequests) {
mKey = new Pair<>(mTargetPackage, getTaskId());
if (!sCurrentGrantRequests.containsKey(mKey)) {
sCurrentGrantRequests.put(mKey, this);
finishSystemStartedDialogsOnOtherTasksLocked();
- } else if (getCallingPackage() == null) {
- // The trampoline doesn't require results. Delegate, and finish.
+ } else if (mIsSystemTriggered) {
+ // The system triggered dialog doesn't require results. Delegate, and finish.
sCurrentGrantRequests.get(mKey).onNewFollowerActivity(null,
mRequestedPermissions);
finishAfterTransition();
return;
- } else {
+ } else if (sCurrentGrantRequests.get(mKey).mIsSystemTriggered) {
+ // Normal permission requests should only merge into the system triggered dialog,
+ // which has task overlay set
mDelegated = true;
- sCurrentGrantRequests.get(mKey).onNewFollowerActivity(this,
- mRequestedPermissions);
+ sCurrentGrantRequests.get(mKey).onNewFollowerActivity(this, mRequestedPermissions);
}
}
@@ -236,14 +274,15 @@ public class GrantPermissionsActivity extends SettingsActivity
.setResultListener(this);
} else {
mViewHandler = new com.android.permissioncontroller.permission.ui.handheld
- .GrantPermissionsViewHandlerImpl(this, mTargetPackage,
- Process.myUserHandle()).setResultListener(this);
+ .GrantPermissionsViewHandlerImpl(this, this);
}
GrantPermissionsViewModelFactory factory = new GrantPermissionsViewModelFactory(
getApplication(), mTargetPackage, mRequestedPermissions, mSessionId, icicle);
- mViewModel = factory.create(GrantPermissionsViewModel.class);
- mViewModel.getRequestInfosLiveData().observe(this, this::onRequestInfoLoad);
+ if (!mDelegated) {
+ mViewModel = factory.create(GrantPermissionsViewModel.class);
+ mViewModel.getRequestInfosLiveData().observe(this, this::onRequestInfoLoad);
+ }
mRootView = mViewHandler.createView();
mRootView.setVisibility(View.GONE);
@@ -280,6 +319,12 @@ public class GrantPermissionsActivity extends SettingsActivity
// Do not show screen dim until data is loaded
window.setDimAmount(0f);
}
+
+ PackageItemInfo storageGroupInfo =
+ Utils.getGroupInfo(Manifest.permission_group.STORAGE, this.getApplicationContext());
+ if (storageGroupInfo != null) {
+ mStoragePermGroupIcon = storageGroupInfo.icon;
+ }
}
/**
@@ -289,10 +334,12 @@ public class GrantPermissionsActivity extends SettingsActivity
* activity finishing
* @param newPermissions The new permissions requested in the activity
*/
- private void onNewFollowerActivity(GrantPermissionsActivity follower, String[] newPermissions) {
+ private void onNewFollowerActivity(@Nullable GrantPermissionsActivity follower,
+ @NonNull List<String> newPermissions) {
if (follower != null) {
// Ensure the list of follower activities is a stack
mFollowerActivities.add(0, follower);
+ follower.mViewModel = mViewModel;
}
boolean isShowingGroup = mRootView != null && mRootView.getVisibility() == View.VISIBLE;
@@ -301,21 +348,19 @@ public class GrantPermissionsActivity extends SettingsActivity
&& currentGroups != null && !currentGroups.isEmpty()) {
mPreMergeShownGroupName = currentGroups.get(0).getGroupName();
}
- boolean newPermission = false;
- ArrayList<String> currentPermissions =
- new ArrayList<>(Arrays.asList(mRequestedPermissions));
- for (String newPerm: newPermissions) {
+
+ if (mRequestedPermissions.containsAll(newPermissions)) {
+ return;
+ }
+
+ ArrayList<String> currentPermissions = new ArrayList<>(mRequestedPermissions);
+ for (String newPerm : newPermissions) {
if (!currentPermissions.contains(newPerm)) {
currentPermissions.add(newPerm);
- newPermission = true;
}
}
+ mRequestedPermissions = currentPermissions;
- if (!newPermission) {
- return;
- }
-
- mRequestedPermissions = currentPermissions.toArray(new String[0]);
Bundle oldState = new Bundle();
mViewModel.getRequestInfosLiveData().removeObservers(this);
mViewModel.saveInstanceState(oldState);
@@ -324,6 +369,9 @@ public class GrantPermissionsActivity extends SettingsActivity
mSessionId, oldState);
mViewModel = factory.create(GrantPermissionsViewModel.class);
mViewModel.getRequestInfosLiveData().observe(this, this::onRequestInfoLoad);
+ if (follower != null) {
+ follower.mViewModel = mViewModel;
+ }
}
/**
@@ -346,9 +394,6 @@ public class GrantPermissionsActivity extends SettingsActivity
return;
}
- if (mRequestInfos == null) {
- mTotalRequests = requests.size();
- }
mRequestInfos = requests;
// If we were already showing a group, and then another request came in with more groups,
@@ -361,14 +406,25 @@ public class GrantPermissionsActivity extends SettingsActivity
}
private void showNextRequest() {
- if (mRequestInfos == null || mRequestInfos.isEmpty()) {
+ if (mRequestInfos.isEmpty()) {
return;
}
RequestInfo info = mRequestInfos.get(0);
+ // Only the top activity can receive activity results
+ Activity top = mFollowerActivities.isEmpty() ? this : mFollowerActivities.get(0);
if (info.getSendToSettingsImmediately()) {
- mViewModel.sendDirectlyToSettings(this, info.getGroupName());
+ mViewModel.sendDirectlyToSettings(top, info.getGroupName());
+ return;
+ } else if (info.getOpenPhotoPicker()) {
+ mViewModel.openPhotoPicker(top, GRANTED_USER_SELECTED);
+ return;
+ }
+
+ if (Utils.isHealthPermissionUiEnabled() && HEALTH_PERMISSION_GROUP.equals(
+ info.getGroupName())) {
+ mViewModel.handleHealthConnectPermissions(top);
return;
}
@@ -394,13 +450,16 @@ public class GrantPermissionsActivity extends SettingsActivity
messageId = Utils.getUpgradeRequest(info.getGroupName());
break;
case STORAGE_SUPERGROUP_MESSAGE_Q_TO_S:
- icon = Icon.createWithResource(getPackageName(), R.drawable.perm_group_storage);
+ icon = Icon.createWithResource(getPackageName(), mStoragePermGroupIcon);
messageId = R.string.permgrouprequest_storage_q_to_s;
break;
case STORAGE_SUPERGROUP_MESSAGE_PRE_Q:
- icon = Icon.createWithResource(getPackageName(), R.drawable.perm_group_storage);
+ 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,
@@ -466,13 +525,26 @@ public class GrantPermissionsActivity extends SettingsActivity
}
}
- mLocationVisibilities = new boolean[info.getLocationVisibilities().size()];
+ CharSequence permissionRationaleMessage = null;
+ if (isPermissionRationaleVisible()) {
+ permissionRationaleMessage =
+ getString(
+ getPermissionRationaleMessageResIdForPermissionGroup(
+ info.getGroupName()));
+ }
+
+ boolean[] locationVisibilities = new boolean[info.getLocationVisibilities().size()];
for (int i = 0; i < info.getLocationVisibilities().size(); i++) {
- mLocationVisibilities[i] = info.getLocationVisibilities().get(i);
+ locationVisibilities[i] = info.getLocationVisibilities().get(i);
}
- mViewHandler.updateUi(info.getGroupName(), mTotalRequests, mCurrentRequestIdx, icon,
- message, detailMessage, mButtonVisibilities, mLocationVisibilities);
+ if (mRequestCounts < mRequestInfos.size()) {
+ mRequestCounts = mRequestInfos.size();
+ }
+
+ mViewHandler.updateUi(info.getGroupName(), mRequestCounts, mCurrentRequestIdx, icon,
+ message, detailMessage, permissionRationaleMessage, mButtonVisibilities,
+ locationVisibilities);
if (showingNewGroup) {
mCurrentRequestIdx++;
}
@@ -485,6 +557,7 @@ public class GrantPermissionsActivity extends SettingsActivity
}
}
+ // LINT.IfChange(dispatchTouchEvent)
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
View rootView = getWindow().getDecorView();
@@ -495,10 +568,14 @@ public class GrantPermissionsActivity extends SettingsActivity
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();
+ }
finishAfterTransition();
}
return super.dispatchTouchEvent(ev);
}
+ // LINT.ThenChange(PermissionRationaleActivity.java:dispatchTouchEvent)
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
@@ -530,30 +607,21 @@ public class GrantPermissionsActivity extends SettingsActivity
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Consumer<Intent> callback = mViewModel.getActivityResultCallback();
-
- if (requestCode == APP_PERMISSION_REQUEST_CODE && callback != null) {
- callback.accept(data);
- mViewModel.setActivityResultCallback(null);
+ if (callback == null || (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);
}
@Override
public void onPermissionGrantResult(String name,
@GrantPermissionsViewHandler.Result int result) {
- if (checkKgm(name, null, result)) {
- return;
- }
-
- if (name.equals(mPreMergeShownGroupName)) {
- mPreMergeShownGroupName = null;
- }
-
- logGrantPermissionActivityButtons(name, null, result);
- mViewModel.onPermissionGrantResult(name, null, result);
- showNextRequest();
- if (result == CANCELED) {
- setResultAndFinish();
- }
+ onPermissionGrantResult(name, null, result);
}
@Override
@@ -563,10 +631,19 @@ public class GrantPermissionsActivity extends SettingsActivity
return;
}
- if (name.equals(mPreMergeShownGroupName)) {
+ if (name == null || name.equals(mPreMergeShownGroupName)) {
mPreMergeShownGroupName = null;
}
+ if (Objects.equals(READ_MEDIA_VISUAL, name)
+ && result == GrantPermissionsViewHandler.GRANTED_USER_SELECTED) {
+ // Only the top activity can receive activity results
+ Activity top = mFollowerActivities.isEmpty() ? this : mFollowerActivities.get(0);
+ mViewModel.openPhotoPicker(top, result);
+ logGrantPermissionActivityButtons(name, affectedForegroundPermissions, result);
+ return;
+ }
+
logGrantPermissionActivityButtons(name, affectedForegroundPermissions, result);
mViewModel.onPermissionGrantResult(name, affectedForegroundPermissions, result);
showNextRequest();
@@ -576,7 +653,18 @@ public class GrantPermissionsActivity extends SettingsActivity
}
@Override
+ public void onPermissionRationaleClicked(String groupName) {
+ logGrantPermissionActivityButtons(groupName,
+ /* affectedForegroundPermissions= */ null,
+ LINKED_TO_PERMISSION_RATIONALE);
+ mViewModel.showPermissionRationaleActivity(this, groupName);
+ }
+
+ @Override
public void onBackPressed() {
+ if (mViewHandler == null) {
+ return;
+ }
mViewHandler.onBackPressed();
}
@@ -604,11 +692,11 @@ public class GrantPermissionsActivity extends SettingsActivity
*/
private void removeActivityFromMap() {
synchronized (sCurrentGrantRequests) {
- GrantPermissionsActivity top = sCurrentGrantRequests.get(mKey);
- if (this.equals(top)) {
+ GrantPermissionsActivity leader = sCurrentGrantRequests.get(mKey);
+ if (this.equals(leader)) {
sCurrentGrantRequests.remove(mKey);
- } else if (top != null) {
- top.mFollowerActivities.remove(this);
+ } else if (leader != null) {
+ leader.mFollowerActivities.remove(this);
}
}
for (GrantPermissionsActivity activity: mFollowerActivities) {
@@ -651,21 +739,22 @@ public class GrantPermissionsActivity extends SettingsActivity
private boolean setResultIfNeeded(int resultCode) {
if (!isResultSet()) {
- String[] oldRequestedPermissions = mRequestedPermissions;
+ List<String> oldRequestedPermissions = mRequestedPermissions;
removeActivityFromMap();
// If a new merge request came in before we managed to remove this activity from the
// map, then cancel the result set for now.
- if (!Arrays.equals(oldRequestedPermissions, mRequestedPermissions)) {
+ if (!Objects.equals(oldRequestedPermissions, mRequestedPermissions)) {
return false;
}
+
mResultCode = resultCode;
if (mViewModel != null) {
mViewModel.logRequestedPermissionGroups();
}
+
// Only include the originally requested permissions in the result
Intent result = new Intent(PackageManager.ACTION_REQUEST_PERMISSIONS);
- String[] resultPermissions = mOriginalRequestedPermissions != null
- ? mOriginalRequestedPermissions : new String[0];
+ String[] resultPermissions = mOriginalRequestedPermissions;
int[] grantResults = new int[resultPermissions.length];
if ((mDelegated || (mViewModel != null && mViewModel.shouldReturnPermissionState()))
@@ -699,7 +788,13 @@ public class GrantPermissionsActivity extends SettingsActivity
int presentedButtons = getButtonState();
switch (grantResult) {
case GRANTED_ALWAYS:
- clickedButton = 1 << ALLOW_BUTTON;
+ if (mButtonVisibilities[ALLOW_BUTTON]) {
+ clickedButton = 1 << ALLOW_BUTTON;
+ } else if (mButtonVisibilities[ALLOW_ALWAYS_BUTTON]) {
+ clickedButton = 1 << ALLOW_ALWAYS_BUTTON;
+ } else if (mButtonVisibilities[ALLOW_ALL_BUTTON]) {
+ clickedButton = 1 << ALLOW_ALL_BUTTON;
+ }
break;
case GRANTED_FOREGROUND_ONLY:
clickedButton = 1 << ALLOW_FOREGROUND_BUTTON;
@@ -731,6 +826,16 @@ public class GrantPermissionsActivity extends SettingsActivity
break;
case LINKED_TO_SETTINGS:
clickedButton = 1 << LINK_TO_SETTINGS;
+ break;
+ case GRANTED_USER_SELECTED:
+ clickedButton = 1 << ALLOW_SELECTED_BUTTON;
+ break;
+ case DENIED_MORE:
+ clickedButton = 1 << DONT_ALLOW_MORE_SELECTED_BUTTON;
+ break;
+ case LINKED_TO_PERMISSION_RATIONALE:
+ clickedButton = 1 << LINK_TO_PERMISSION_RATIONALE;
+ break;
case CANCELED:
// fall through
default:
@@ -747,7 +852,7 @@ public class GrantPermissionsActivity extends SettingsActivity
}
mViewModel.logClickedButtons(permissionGroupName, selectedPrecision, clickedButton,
- presentedButtons);
+ presentedButtons, isPermissionRationaleVisible());
}
private int getButtonState() {
@@ -764,6 +869,10 @@ public class GrantPermissionsActivity extends SettingsActivity
return buttonState;
}
+ private boolean isPermissionRationaleVisible() {
+ return mButtonVisibilities != null && mButtonVisibilities[LINK_TO_PERMISSION_RATIONALE];
+ }
+
private boolean isResultSet() {
return mResultCode != Integer.MAX_VALUE;
}
@@ -777,12 +886,26 @@ public class GrantPermissionsActivity extends SettingsActivity
for (Pair<String, Integer> key : sCurrentGrantRequests.keySet()) {
if (key.first.equals(mTargetPackage) && key.second != getTaskId()) {
GrantPermissionsActivity other = sCurrentGrantRequests.get(key);
- if (other.getIntent().getAction()
- .equals(PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER)
- && other.mFollowerActivities.isEmpty()) {
+ if (other.mIsSystemTriggered && other.mFollowerActivities.isEmpty()) {
other.finish();
}
}
}
}
+
+ /**
+ * Returns permission rationale message string resource id for the given permission group.
+ *
+ * <p> Supported permission groups: LOCATION
+ *
+ * @param permissionGroupName permission group for which to get a message string id
+ * @throws IllegalArgumentException if passing unsupported permission group
+ */
+ @StringRes
+ private int getPermissionRationaleMessageResIdForPermissionGroup(String permissionGroupName) {
+ Preconditions.checkArgument(LOCATION.equals(permissionGroupName),
+ "Permission Rationale does not support %s", permissionGroupName);
+
+ return R.string.permission_rationale_message_location;
+ }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsViewHandler.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsViewHandler.java
index 05fa41557..3494fdebd 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsViewHandler.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsViewHandler.java
@@ -36,8 +36,9 @@ import java.util.List;
public interface GrantPermissionsViewHandler {
@Retention(SOURCE)
@IntDef({CANCELED, GRANTED_ALWAYS, GRANTED_FOREGROUND_ONLY, DENIED, DENIED_DO_NOT_ASK_AGAIN,
- GRANTED_ONE_TIME})
+ GRANTED_ONE_TIME, GRANTED_USER_SELECTED, DENIED_MORE})
@interface Result {}
+ int LINKED_TO_PERMISSION_RATIONALE = -3;
int LINKED_TO_SETTINGS = -2;
int CANCELED = -1;
int GRANTED_ALWAYS = 0;
@@ -45,6 +46,9 @@ public interface GrantPermissionsViewHandler {
int DENIED = 2;
int DENIED_DO_NOT_ASK_AGAIN = 3;
int GRANTED_ONE_TIME = 4;
+ int GRANTED_USER_SELECTED = 5; // The user has used a picker to select data to share
+ int DENIED_MORE = 6; // The user has used the picker at least once, but has denied a request
+ // for more
/**
* Listener interface for getting notified when the user responds to a
@@ -55,6 +59,8 @@ public interface GrantPermissionsViewHandler {
void onPermissionGrantResult(String groupName, List<String> affectedForegroundPermissions,
@Result int result);
+
+ void onPermissionRationaleClicked(String groupName);
}
/**
@@ -83,11 +89,15 @@ public interface GrantPermissionsViewHandler {
* @param message the message to display the user
* @param detailMessage another message to display to the user. This clarifies "message" in more
* detail
+ * @param permissionRationaleMessage another message to display to the user. This message lets
+ * users know developer stated data usages for the requested
+ * permission
* @param buttonVisibilities visibilities for each button
* @param locationVisibilities visibilities for location options
*/
void updateUi(String groupName, int groupCount, int groupIndex, Icon icon,
- CharSequence message, CharSequence detailMessage, boolean[] buttonVisibilities,
+ CharSequence message, CharSequence detailMessage,
+ CharSequence permissionRationaleMessage, boolean[] buttonVisibilities,
boolean[] locationVisibilities);
/**
@@ -114,6 +124,11 @@ public interface GrantPermissionsViewHandler {
void onBackPressed();
/**
+ * Handles cancel event for the permission dialog.
+ */
+ default void onCancelled() {}
+
+ /**
* Called by {@link GrantPermissionsActivity} to allow the handler to update
* the ui when blur is enabled/disabled.
*/
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/ManagePermissionsActivity.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/ManagePermissionsActivity.java
index c7b1bdcfa..afeb19aa9 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/ManagePermissionsActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/ManagePermissionsActivity.java
@@ -16,11 +16,13 @@
package com.android.permissioncontroller.permission.ui;
+import static android.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static com.android.permissioncontroller.Constants.ACTION_MANAGE_AUTO_REVOKE;
import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
+import static com.android.permissioncontroller.Constants.UNUSED_APPS_SAFETY_CENTER_SOURCE_ID;
import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_GROUPS_FRAGMENT_AUTO_REVOKE_ACTION;
import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_GROUPS_FRAGMENT_AUTO_REVOKE_ACTION__ACTION__OPENED_FOR_AUTO_REVOKE;
import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_GROUPS_FRAGMENT_AUTO_REVOKE_ACTION__ACTION__OPENED_FROM_INTENT;
@@ -30,8 +32,10 @@ import static com.android.permissioncontroller.PermissionControllerStatsLog.PERM
import android.Manifest;
import android.app.ActionBar;
+import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PermissionInfo;
import android.os.Build;
import android.os.Bundle;
@@ -39,6 +43,9 @@ import android.os.Process;
import android.os.UserHandle;
import android.permission.PermissionManager;
import android.provider.Settings;
+import android.safetycenter.SafetyCenterManager;
+import android.safetycenter.SafetyEvent;
+import android.safetycenter.SafetySourceData;
import android.util.Log;
import android.view.MenuItem;
@@ -48,10 +55,12 @@ import androidx.navigation.NavInflater;
import androidx.navigation.Navigation;
import androidx.navigation.fragment.NavHostFragment;
+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.hibernation.HibernationPolicyKt;
import com.android.permissioncontroller.permission.ui.auto.AutoAllAppPermissionsFragment;
import com.android.permissioncontroller.permission.ui.auto.AutoAppPermissionsFragment;
import com.android.permissioncontroller.permission.ui.auto.AutoManageStandardPermissionsFragment;
@@ -65,13 +74,16 @@ import com.android.permissioncontroller.permission.ui.handheld.AppPermissionGrou
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.PermissionUsageV2WrapperFragment;
+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.utils.KotlinUtils;
+import com.android.permissioncontroller.permission.utils.PermissionMapping;
import com.android.permissioncontroller.permission.utils.Utils;
+import java.util.Objects;
import java.util.Random;
/**
@@ -114,12 +126,24 @@ public final class ManagePermissionsActivity extends SettingsActivity {
+ ".permissioncontroller.extra.SHOW_7_DAYS";
/**
+ * Name of the aliased activity.
+ */
+ public static final String ALIAS_ACTIVITY_NAME =
+ "com.android.permissioncontroller.permission.ui.ManagePermissionsActivityAlias";
+
+ /**
* The requestCode used when we decide not to use this activity, but instead launch
* another activity in our place. When that activity finishes, we set it's result
* as our result and then finish.
*/
private static final int PROXY_ACTIVITY_REQUEST_CODE = 5;
+ private static final String LAUNCH_PERMISSION_SETTINGS =
+ "android.permission.LAUNCH_PERMISSION_SETTINGS";
+
+ private static final String APP_PERMISSIONS_SETTINGS =
+ "android.settings.APP_PERMISSIONS_SETTINGS";
+
@Override
public void onCreate(Bundle savedInstanceState) {
if (DeviceUtils.isAuto(this)) {
@@ -141,6 +165,8 @@ public final class ManagePermissionsActivity extends SettingsActivity {
boolean completed = Settings.Secure.getInt(
getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 0) != 0;
if (!provisioned || !completed) {
+ Log.e(LOG_TAG, "Device setup incomplete. device provisioned=" + provisioned
+ + ", user setup complete=" + completed);
finishAfterTransition();
return;
}
@@ -161,6 +187,16 @@ public final class ManagePermissionsActivity extends SettingsActivity {
int openFromIntentAction =
APP_PERMISSION_GROUPS_FRAGMENT_AUTO_REVOKE_ACTION__ACTION__OPENED_FROM_INTENT;
+ ComponentName component = getIntent().getComponent();
+ if (component != null
+ && Objects.equals(component.getClassName(), ALIAS_ACTIVITY_NAME)
+ && !Objects.equals(action, APP_PERMISSIONS_SETTINGS)) {
+ Log.w(LOG_TAG, ALIAS_ACTIVITY_NAME + " can only be launched with "
+ + APP_PERMISSIONS_SETTINGS);
+ finishAfterTransition();
+ return;
+ }
+
String permissionName;
switch (action) {
case Intent.ACTION_MANAGE_PERMISSIONS:
@@ -193,7 +229,7 @@ public final class ManagePermissionsActivity extends SettingsActivity {
if (DeviceUtils.isAuto(this)) {
androidXFragment = new AutoPermissionUsageFragment();
} else {
- androidXFragment = PermissionUsageV2WrapperFragment.newInstance(
+ androidXFragment = PermissionUsageWrapperFragment.newInstance(
Long.MAX_VALUE, sessionId);
}
} break;
@@ -267,7 +303,25 @@ public final class ManagePermissionsActivity extends SettingsActivity {
return;
}
- case Intent.ACTION_MANAGE_APP_PERMISSIONS: {
+ case Intent.ACTION_MANAGE_APP_PERMISSIONS:
+ case APP_PERMISSIONS_SETTINGS: {
+ if (Objects.equals(action, APP_PERMISSIONS_SETTINGS)) {
+ PermissionInfo permissionInfo;
+ try {
+ permissionInfo = getPackageManager()
+ .getPermissionInfo(LAUNCH_PERMISSION_SETTINGS, 0);
+ } catch (NameNotFoundException e) {
+ permissionInfo = null;
+ }
+ if (permissionInfo == null
+ || !Objects.equals(permissionInfo.packageName, Utils.OS_PKG)) {
+ Log.w(LOG_TAG, LAUNCH_PERMISSION_SETTINGS
+ + " must be defined by platform.");
+ finishAfterTransition();
+ return;
+ }
+ }
+
String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
if (packageName == null) {
Log.i(LOG_TAG, "Missing mandatory argument EXTRA_PACKAGE_NAME");
@@ -331,7 +385,8 @@ public final class ManagePermissionsActivity extends SettingsActivity {
setNavGraph(args, R.id.app_permission_groups);
return;
}
- } break;
+ break;
+ }
case Intent.ACTION_MANAGE_PERMISSION_APPS: {
permissionName = getIntent().getStringExtra(Intent.EXTRA_PERMISSION_NAME);
@@ -343,7 +398,7 @@ public final class ManagePermissionsActivity extends SettingsActivity {
try {
PermissionInfo permInfo = getPackageManager().getPermissionInfo(
permissionName, 0);
- permissionGroupName = Utils.getGroupOfPermission(permInfo);
+ permissionGroupName = PermissionMapping.getGroupOfPermission(permInfo);
} catch (PackageManager.NameNotFoundException e) {
Log.i(LOG_TAG, "Permission " + permissionName + " does not exist");
}
@@ -367,6 +422,13 @@ public final class ManagePermissionsActivity extends SettingsActivity {
return;
}
+ if (Utils.isHealthPermissionUiEnabled() && permissionGroupName
+ .equals(HEALTH_PERMISSION_GROUP)) {
+ Utils.navigateToHealthConnectSettings(this);
+ finishAfterTransition();
+ return;
+ }
+
if (DeviceUtils.isAuto(this)) {
androidXFragment =
AutoPermissionAppsFragment.newInstance(permissionGroupName, sessionId);
@@ -386,6 +448,23 @@ public final class ManagePermissionsActivity extends SettingsActivity {
Log.i(LOG_TAG, "sessionId " + sessionId + " starting auto revoke fragment"
+ " from notification");
PermissionControllerStatsLog.write(AUTO_REVOKE_NOTIFICATION_CLICKED, sessionId);
+ if (SdkLevel.isAtLeastT()) {
+ SafetyCenterManager safetyCenterManager =
+ getSystemService(SafetyCenterManager.class);
+ if (safetyCenterManager.isSafetyCenterEnabled()) {
+ SafetySourceData data = safetyCenterManager.getSafetySourceData(
+ UNUSED_APPS_SAFETY_CENTER_SOURCE_ID);
+ if (data != null && !data.getIssues().isEmpty()) {
+ // Clear source data as user has reviewed their unused apps
+ HibernationPolicyKt.setUnusedAppsReviewNeeded(this, false);
+ HibernationPolicyKt.rescanAndPushDataToSafetyCenter(this, sessionId,
+ new SafetyEvent.Builder(
+ SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED)
+ .build());
+ HibernationPolicyKt.cancelUnusedAppsNotification(this);
+ }
+ }
+ }
if (DeviceUtils.isAuto(this)) {
androidXFragment = AutoUnusedAppsFragment.newInstance();
@@ -400,7 +479,9 @@ public final class ManagePermissionsActivity extends SettingsActivity {
setNavGraph(UnusedAppsFragment.createArgs(sessionId), R.id.auto_revoke);
return;
}
- } break;
+
+ break;
+ }
case PermissionManager.ACTION_REVIEW_PERMISSION_DECISIONS: {
UserHandle userHandle = getIntent().getParcelableExtra(Intent.EXTRA_USER);
@@ -420,6 +501,16 @@ public final class ManagePermissionsActivity extends SettingsActivity {
}
} break;
+ case Intent.ACTION_REVIEW_APP_DATA_SHARING_UPDATES: {
+ if (KotlinUtils.INSTANCE.isSafetyLabelChangeNotificationsEnabled(this)) {
+ setNavGraph(AppDataSharingUpdatesFragment.Companion.createArgs(sessionId),
+ R.id.app_data_sharing_updates);
+ } else {
+ finishAfterTransition();
+ return;
+ }
+ } break;
+
default: {
Log.w(LOG_TAG, "Unrecognized action " + action);
finishAfterTransition();
@@ -440,7 +531,7 @@ public final class ManagePermissionsActivity extends SettingsActivity {
try {
PermissionInfo permInfo = getPackageManager().getPermissionInfo(
permissionName, 0);
- return Utils.getGroupOfPermission(permInfo);
+ return PermissionMapping.getGroupOfPermission(permInfo);
} catch (PackageManager.NameNotFoundException e) {
Log.i(LOG_TAG, "Permission " + permissionName + " does not exist");
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/OverlayWarningDialog.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/OverlayWarningDialog.java
deleted file mode 100644
index de1f68c98..000000000
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/OverlayWarningDialog.java
+++ /dev/null
@@ -1,63 +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;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.ActivityNotFoundException;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.DialogInterface.OnDismissListener;
-import android.content.Intent;
-import android.os.Bundle;
-import android.provider.Settings;
-import android.util.Log;
-
-import com.android.permissioncontroller.R;
-
-public class OverlayWarningDialog extends Activity implements OnClickListener, OnDismissListener {
-
- private static final String TAG = "OverlayWarningDialog";
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- new AlertDialog.Builder(this)
- .setTitle(R.string.screen_overlay_title)
- .setMessage(R.string.screen_overlay_message)
- .setPositiveButton(R.string.screen_overlay_button, this)
- .setOnDismissListener(this)
- .show();
- }
-
- @Override
- public void onDismiss(DialogInterface dialog) {
- finish();
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- finish();
- try {
- startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION));
- } catch (ActivityNotFoundException e) {
- Log.w(TAG, "No manage overlay settings", e);
- }
- }
-
-}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/ReviewOngoingUsageActivity.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/ReviewOngoingUsageActivity.java
index 6dfceb90d..05a75f594 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/ReviewOngoingUsageActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/ReviewOngoingUsageActivity.java
@@ -25,8 +25,8 @@ import android.view.MenuItem;
import androidx.annotation.NonNull;
import com.android.permissioncontroller.DeviceUtils;
-import com.android.permissioncontroller.permission.ui.handheld.v31.DashboardUtilsKt;
import com.android.permissioncontroller.permission.ui.handheld.v31.ReviewOngoingUsageWrapperFragment;
+import com.android.permissioncontroller.permission.utils.KotlinUtils;
/**
* A dialog listing the currently uses of camera, microphone, and location.
@@ -40,8 +40,8 @@ public final class ReviewOngoingUsageActivity extends SettingsActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (!DashboardUtilsKt.shouldShowCameraMicIndicators()
- && !DashboardUtilsKt.shouldShowLocationIndicators()) {
+ if (!KotlinUtils.INSTANCE.shouldShowCameraMicIndicators()
+ && !KotlinUtils.INSTANCE.shouldShowLocationIndicators()) {
finishAfterTransition();
return;
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/UnusedAppsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/UnusedAppsFragment.kt
index 35fbf0768..68fb493eb 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/UnusedAppsFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/UnusedAppsFragment.kt
@@ -22,9 +22,15 @@ import android.app.AlertDialog
import android.app.Application
import android.app.Dialog
import android.content.Intent
+import android.icu.text.MessageFormat
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.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
@@ -38,15 +44,11 @@ import com.android.permissioncontroller.Constants.INVALID_SESSION_ID
import com.android.permissioncontroller.R
import com.android.permissioncontroller.hibernation.isHibernationEnabled
import com.android.permissioncontroller.permission.ui.model.UnusedAppsViewModel
-import com.android.permissioncontroller.permission.ui.model.UnusedAppsViewModel.Months
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.utils.IPC
import com.android.permissioncontroller.permission.utils.KotlinUtils
-import kotlinx.coroutines.Dispatchers.Main
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
import java.text.Collator
/**
@@ -54,8 +56,8 @@ import java.text.Collator
* and to open them.
*/
class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
- where PF : PreferenceFragmentCompat, PF : UnusedAppsFragment.Parent<UnusedAppPref>,
- UnusedAppPref : Preference, UnusedAppPref : RemovablePref {
+ where PF : PreferenceFragmentCompat, PF : UnusedAppsFragment.Parent<UnusedAppPref>,
+ UnusedAppPref : Preference, UnusedAppPref : RemovablePref {
private lateinit var viewModel: UnusedAppsViewModel
private lateinit var collator: Collator
@@ -63,7 +65,7 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
private var isFirstLoad = false
companion object {
- public const val INFO_MSG_CATEGORY = "info_msg_category"
+ const val INFO_MSG_CATEGORY = "info_msg_category"
private const val SHOW_LOAD_DELAY_MS = 200L
private const val INFO_MSG_KEY = "info_msg"
private const val ELEVATION_HIGH = 8f
@@ -71,8 +73,8 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
@JvmStatic
fun <PF, UnusedAppPref> newInstance(): UnusedAppsFragment<PF, UnusedAppPref>
- where PF : PreferenceFragmentCompat, PF : UnusedAppsFragment.Parent<UnusedAppPref>,
- UnusedAppPref : Preference, UnusedAppPref : RemovablePref {
+ where PF : PreferenceFragmentCompat, PF : UnusedAppsFragment.Parent<UnusedAppPref>,
+ UnusedAppPref : Preference, UnusedAppPref : RemovablePref {
return UnusedAppsFragment()
}
@@ -91,8 +93,11 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
}
}
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?,
+ ): View? {
val preferenceFragment: PF = requirePreferenceFragment()
isFirstLoad = true
@@ -111,21 +116,18 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
activity?.getActionBar()?.setDisplayHomeAsUpEnabled(true)
if (!viewModel.unusedPackageCategoriesLiveData.isInitialized) {
- GlobalScope.launch(IPC) {
- delay(SHOW_LOAD_DELAY_MS)
+ val handler = Handler(Looper.getMainLooper())
+ handler.postDelayed({
if (!viewModel.unusedPackageCategoriesLiveData.isInitialized) {
- GlobalScope.launch(Main) {
- preferenceFragment.setLoadingState(loading = true, animate = true)
- }
+ preferenceFragment.setLoadingState(loading = true, animate = true)
} else {
- GlobalScope.launch(Main) {
- updatePackages(viewModel.unusedPackageCategoriesLiveData.value!!)
- }
+ updatePackages(viewModel.unusedPackageCategoriesLiveData.value!!)
}
- }
+ }, SHOW_LOAD_DELAY_MS)
} else {
updatePackages(viewModel.unusedPackageCategoriesLiveData.value!!)
}
+ return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onStart() {
@@ -157,6 +159,13 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
context!!,
R.xml.unused_app_categories,
/* rootPreferences= */ null)
+
+ for (period in allPeriods) {
+ val periodCat = PreferenceCategory(context!!)
+ periodCat.key = period.name
+ periodCat.order = 0
+ preferenceScreen.addPreference(periodCat)
+ }
preferenceFragment.preferenceScreen = preferenceScreen
val infoMsgCategory = preferenceScreen.findPreference<PreferenceCategory>(INFO_MSG_CATEGORY)
@@ -166,22 +175,24 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
}
@Suppress("UNCHECKED_CAST")
- private fun updatePackages(categorizedPackages: Map<Months, List<UnusedPackageInfo>>) {
+ private fun updatePackages(categorizedPackages: Map<UnusedPeriod, List<UnusedPackageInfo>>) {
val preferenceFragment: PF = requirePreferenceFragment()
if (preferenceFragment.preferenceScreen == null) {
createPreferenceScreen()
}
val preferenceScreen: PreferenceScreen = preferenceFragment.preferenceScreen
+ // Remove stale preferences
val removedPrefs = mutableMapOf<String, UnusedAppPref>()
- for (month in Months.allMonths()) {
- val category = preferenceScreen.findPreference<PreferenceCategory>(month.value)!!
+ for (period in allPeriods) {
+ val category = preferenceScreen.findPreference<PreferenceCategory>(period.name)!!
for (i in 0 until category.preferenceCount) {
val pref = category.getPreference(i) as UnusedAppPref
- val contains = categorizedPackages[Months.THREE]?.any { (pkgName, user, _) ->
- val key = createKey(pkgName, user)
- pref.key == key
- }
+ val contains =
+ categorizedPackages[period]?.any { (pkgName, user, _) ->
+ val key = createKey(pkgName, user)
+ pref.key == key
+ }
if (contains != true) {
removedPrefs[pref.key] = pref
}
@@ -193,13 +204,12 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
}
var allCategoriesEmpty = true
- for ((month, packages) in categorizedPackages) {
- val category = preferenceScreen.findPreference<PreferenceCategory>(month.value)!!
- category.title = if (month == Months.THREE) {
- getString(R.string.last_opened_category_title, "3")
- } else {
- getString(R.string.last_opened_category_title, "6")
- }
+ for ((period, packages) in categorizedPackages) {
+ 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))
category.isVisible = packages.isNotEmpty()
if (packages.isNotEmpty()) {
allCategoriesEmpty = false
@@ -252,17 +262,16 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
preferenceFragment.setEmptyState(allCategoriesEmpty)
if (isFirstLoad) {
- if (categorizedPackages[Months.SIX]!!.isNotEmpty() ||
- categorizedPackages[Months.THREE]!!.isNotEmpty()) {
+ if (categorizedPackages.any { (_, packages) -> packages.isNotEmpty() }) {
isFirstLoad = false
}
Log.i(LOG_TAG, "sessionId: $sessionId Showed Auto Revoke Page")
- for (month in Months.values()) {
- Log.i(LOG_TAG, "sessionId: $sessionId $month unused: " +
- "${categorizedPackages[month]}")
- for (revokedPackageInfo in categorizedPackages[month]!!) {
+ 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 = month == Months.THREE
+ val isNewlyRevoked = period.isNewlyUnused()
viewModel.logAppView(revokedPackageInfo.packageName,
revokedPackageInfo.user, groupName, isNewlyRevoked)
}
@@ -331,7 +340,7 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
* Interface that the parent fragment must implement.
*/
interface Parent<UnusedAppPref> where UnusedAppPref : Preference,
- UnusedAppPref : RemovablePref {
+ UnusedAppPref : RemovablePref {
/**
* Set the title of the current settings page.
@@ -365,7 +374,7 @@ class UnusedAppsFragment<PF, UnusedAppPref> : Fragment()
fun createUnusedAppPref(
app: Application,
packageName: String,
- user: UserHandle
+ user: UserHandle,
): UnusedAppPref
/**
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAllAppPermissionsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAllAppPermissionsFragment.java
index e509d8a5b..e6cea80a0 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAllAppPermissionsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAllAppPermissionsFragment.java
@@ -48,6 +48,7 @@ import com.android.permissioncontroller.auto.AutoSettingsFrameFragment;
import com.android.permissioncontroller.permission.model.AppPermissionGroup;
import com.android.permissioncontroller.permission.model.Permission;
import com.android.permissioncontroller.permission.utils.ArrayUtils;
+import com.android.permissioncontroller.permission.utils.PermissionMapping;
import com.android.permissioncontroller.permission.utils.Utils;
import java.util.ArrayList;
@@ -158,7 +159,8 @@ public class AutoAllAppPermissionsFragment extends AutoSettingsFrameFragment {
if ((perm.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
== PermissionInfo.PROTECTION_DANGEROUS) {
- PackageItemInfo group = getGroup(Utils.getGroupOfPermission(perm), pm);
+ PackageItemInfo group =
+ getGroup(PermissionMapping.getGroupOfPermission(perm), pm);
if (group == null) {
group = perm;
}
@@ -192,9 +194,9 @@ public class AutoAllAppPermissionsFragment extends AutoSettingsFrameFragment {
return 1;
} else if (rKey.equals(KEY_OTHER)) {
return -1;
- } else if (Utils.isModernPermissionGroup(lKey)
- != Utils.isModernPermissionGroup(rKey)) {
- return Utils.isModernPermissionGroup(lKey) ? -1 : 1;
+ } else if (PermissionMapping.isPlatformPermissionGroup(lKey)
+ != PermissionMapping.isPlatformPermissionGroup(rKey)) {
+ return PermissionMapping.isPlatformPermissionGroup(lKey) ? -1 : 1;
}
return lhs.getTitle().toString().compareTo(rhs.getTitle().toString());
});
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 8500fadad..2de936469 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java
@@ -55,11 +55,11 @@ import androidx.preference.TwoStatePreference;
import com.android.car.ui.AlertDialogBuilder;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.auto.AutoSettingsFrameFragment;
-import com.android.permissioncontroller.permission.ui.AdvancedConfirmDialogArgs;
import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ChangeRequest;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModelFactory;
+import com.android.permissioncontroller.permission.ui.v33.AdvancedConfirmDialogArgs;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.PackageRemovalMonitor;
import com.android.settingslib.RestrictedLockUtils;
@@ -461,6 +461,9 @@ public class AutoAppPermissionFragment extends AutoSettingsFrameFragment
AlertDialog.Builder b = new AlertDialog.Builder(getContext())
.setIcon(args.getIconId())
.setMessage(args.getMessageId())
+ .setOnCancelListener((DialogInterface dialog) -> {
+ setRadioButtonsState(mViewModel.getButtonStateLiveData().getValue());
+ })
.setNegativeButton(args.getNegativeButtonTextId(),
(DialogInterface dialog, int which) -> {
setRadioButtonsState(mViewModel.getButtonStateLiveData().getValue());
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 0973d1dfe..cf58f1e17 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionsFragment.java
@@ -23,7 +23,6 @@ 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.permission.ui.ManagePermissionsActivity.EXTRA_CALLER_NAME;
-import static com.android.permissioncontroller.permission.ui.handheld.v31.DashboardUtilsKt.is7DayToggleEnabled;
import static java.util.concurrent.TimeUnit.DAYS;
@@ -146,7 +145,7 @@ public class AutoAppPermissionsFragment extends AutoSettingsFrameFragment implem
if (SdkLevel.isAtLeastS()) {
mPermissionUsages = new PermissionUsages(getContext());
- long aggregateDataFilterBeginDays = is7DayToggleEnabled()
+ long aggregateDataFilterBeginDays = KotlinUtils.INSTANCE.is7DayToggleEnabled()
? AppPermissionGroupsViewModel.AGGREGATE_DATA_FILTER_BEGIN_DAYS_7 :
AppPermissionGroupsViewModel.AGGREGATE_DATA_FILTER_BEGIN_DAYS_1;
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 da0d32533..92917a342 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoReviewPermissionDecisionsFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoReviewPermissionDecisionsFragment.kt
@@ -223,7 +223,7 @@ class AutoReviewPermissionDecisionsFragment : AutoSettingsFrameFragment() {
PermissionControllerStatsLog.RECENT_PERMISSION_DECISIONS_INTERACTED,
sessionId,
RECENT_PERMISSION_DECISIONS_INTERACTED__ACTION__SCREEN_VIEWED,
- null,
+ 0,
null)
}
@@ -232,7 +232,7 @@ class AutoReviewPermissionDecisionsFragment : AutoSettingsFrameFragment() {
PermissionControllerStatsLog.RECENT_PERMISSION_DECISIONS_INTERACTED,
sessionId,
RECENT_PERMISSION_DECISIONS_INTERACTED__ACTION__VIEW_ALL_CLICKED,
- null,
+ 0,
null)
}
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 194faff6f..6b09921cb 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/GrantPermissionsAutoViewHandler.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/GrantPermissionsAutoViewHandler.java
@@ -91,8 +91,11 @@ public class GrantPermissionsAutoViewHandler implements GrantPermissionsViewHand
@Override
public void updateUi(String groupName, int groupCount, int groupIndex, Icon icon,
- CharSequence message, CharSequence detailMessage, boolean[] buttonVisibilities,
+ CharSequence message, CharSequence detailMessage,
+ CharSequence permissionRationaleMessage, boolean[] buttonVisibilities,
boolean[] locationVisibilities) {
+ // permissionRationaleMessage ignored by auto
+
mGroupName = groupName;
mGroupCount = groupCount;
mGroupIndex = groupIndex;
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 76abab810..7ea400127 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
@@ -16,23 +16,21 @@
package com.android.permissioncontroller.permission.ui.auto.dashboard
-import android.Manifest
-import android.content.ComponentName
import android.content.Context
-import android.content.Intent
-import android.content.pm.PackageManager
+import android.os.Build
+import android.text.format.DateFormat
+import androidx.annotation.RequiresApi
import androidx.preference.Preference.OnPreferenceClickListener
import com.android.car.ui.preference.CarUiPreference
-import com.android.modules.utils.build.SdkLevel
import com.android.permissioncontroller.R
-import com.android.permissioncontroller.permission.compat.IntentCompat
import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel
-import java.util.Objects
+import com.android.permissioncontroller.permission.ui.legacy.PermissionUsageDetailsViewModelLegacy
/** Preference that displays a permission usage for an app. */
+@RequiresApi(Build.VERSION_CODES.S)
class AutoPermissionHistoryPreference(
- private val context: Context,
- private val historyPreferenceData: PermissionUsageDetailsViewModel.HistoryPreferenceData
+ context: Context,
+ historyPreferenceData: PermissionUsageDetailsViewModelLegacy.HistoryPreferenceData
) : CarUiPreference(context) {
init {
@@ -41,67 +39,29 @@ class AutoPermissionHistoryPreference(
if (historyPreferenceData.summaryText != null) {
context.getString(
R.string.auto_permission_usage_timeline_summary,
- historyPreferenceData.accessTime,
+ DateFormat.getTimeFormat(context).format(historyPreferenceData.accessEndTime),
historyPreferenceData.summaryText)
} else {
- historyPreferenceData.accessTime
+ DateFormat.getTimeFormat(context).format(historyPreferenceData.accessEndTime)
}
if (historyPreferenceData.appIcon != null) {
icon = historyPreferenceData.appIcon
}
- // TODO(b/268413649) this logic should be shared across form factors
- val intent = getManagePermissionUsageIntent() ?: getDefaultManageAppPermissionsIntent()
onPreferenceClickListener = OnPreferenceClickListener {
- context.startActivity(intent)
+ // This Intent should ideally be part of the preference data, and can be consolidated
+ // when the Legacy and New viewmodels are merged.
+ context.startActivity(
+ PermissionUsageDetailsViewModel.createHistoryPreferenceClickIntent(
+ context = context,
+ userHandle = historyPreferenceData.userHandle,
+ packageName = historyPreferenceData.pkgName,
+ permissionGroup = historyPreferenceData.permissionGroup,
+ accessEndTime = historyPreferenceData.accessEndTime,
+ accessStartTime = historyPreferenceData.accessStartTime,
+ showingAttribution = historyPreferenceData.showingAttribution,
+ attributionTags = historyPreferenceData.attributionTags))
true
}
}
-
- /** Creates the [Intent] for the click action of a privacy dashboard app usage event. */
- private fun getDefaultManageAppPermissionsIntent(): Intent {
- return Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS).apply {
- putExtra(Intent.EXTRA_USER, historyPreferenceData.userHandle)
- putExtra(Intent.EXTRA_PACKAGE_NAME, historyPreferenceData.pkgName)
- }
- }
-
- /**
- * Gets an [Intent.ACTION_MANAGE_PERMISSION_USAGE] intent, or null if attribution shouldn't be
- * shown or the intent can't be handled.
- */
- private fun getManagePermissionUsageIntent(): Intent? {
- // TODO(b/255992934) only location provider apps should be able to provide this intent
- if (!historyPreferenceData.showingAttribution || !SdkLevel.isAtLeastT()) {
- return null
- }
- val intent =
- Intent(Intent.ACTION_MANAGE_PERMISSION_USAGE).apply {
- setPackage(historyPreferenceData.pkgName)
- putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, historyPreferenceData.permissionGroup)
- putExtra(
- Intent.EXTRA_ATTRIBUTION_TAGS,
- historyPreferenceData.attributionTags.toTypedArray())
- putExtra(
- Intent.EXTRA_START_TIME,
- historyPreferenceData.accessTimeList[
- historyPreferenceData.accessTimeList.size - 1])
- putExtra(Intent.EXTRA_END_TIME, historyPreferenceData.accessTimeList[0])
- putExtra(
- IntentCompat.EXTRA_SHOWING_ATTRIBUTION,
- historyPreferenceData.showingAttribution)
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- }
- 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)) {
- return null
- }
- intent.component =
- ComponentName(historyPreferenceData.pkgName, resolveInfo.activityInfo.name)
- return intent
- }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageDetailsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageDetailsFragment.kt
index 0d95852e8..a16bc1ce4 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageDetailsFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageDetailsFragment.kt
@@ -18,14 +18,15 @@
package com.android.permissioncontroller.permission.ui.auto.dashboard
import android.app.role.RoleManager
-import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Bundle
+import android.text.format.DateFormat
import androidx.annotation.RequiresApi
import androidx.lifecycle.ViewModelProvider
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
+import androidx.preference.PreferenceScreen
import com.android.car.ui.preference.CarUiPreference
import com.android.permissioncontroller.Constants
import com.android.permissioncontroller.DumpableLog
@@ -35,47 +36,56 @@ import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__SHOW_SYSTEM_CLICKED
import com.android.permissioncontroller.R
import com.android.permissioncontroller.auto.AutoSettingsFrameFragment
+import com.android.permissioncontroller.permission.model.legacy.PermissionApps.AppDataLoader
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.model.legacy.PermissionApps.AppDataLoader
-import com.android.permissioncontroller.permission.model.legacy.PermissionApps.PermissionApp
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity
import com.android.permissioncontroller.permission.ui.auto.AutoDividerPreference
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.AppPermissionUsageEntry
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModelFactory
+import com.android.permissioncontroller.permission.ui.legacy.PermissionUsageDetailsViewModelFactoryLegacy
+import com.android.permissioncontroller.permission.ui.legacy.PermissionUsageDetailsViewModelLegacy
import com.android.permissioncontroller.permission.utils.KotlinUtils.getPermGroupLabel
import com.android.permissioncontroller.permission.utils.Utils
-import java.util.concurrent.atomic.AtomicBoolean
+import java.time.Clock
+import java.time.Instant
+import java.time.ZoneId
+import java.time.ZonedDateTime
+import java.time.temporal.ChronoUnit
import java.util.concurrent.atomic.AtomicReference
@RequiresApi(Build.VERSION_CODES.S)
-class AutoPermissionUsageDetailsFragment : AutoSettingsFrameFragment(),
- PermissionsUsagesChangeCallback {
+class AutoPermissionUsageDetailsFragment :
+ AutoSettingsFrameFragment(), PermissionsUsagesChangeCallback {
companion object {
private const val LOG_TAG = "AutoPermissionUsageDetailsFragment"
private const val KEY_SESSION_ID = "_session_id"
private const val FILTER_24_HOURS = 2
+ private val MIDNIGHT_TODAY =
+ ZonedDateTime.now(ZoneId.systemDefault()).truncatedTo(ChronoUnit.DAYS).toEpochSecond() *
+ 1000L
+ private val MIDNIGHT_YESTERDAY =
+ ZonedDateTime.now(ZoneId.systemDefault())
+ .minusDays(1)
+ .truncatedTo(ChronoUnit.DAYS)
+ .toEpochSecond() * 1000L
// Only show the last 24 hours on Auto right now
private const val SHOW_7_DAYS = false
- /**
- * Creates a new instance of [AutoPermissionUsageDetailsFragment].
- */
+ /** Creates a new instance of [AutoPermissionUsageDetailsFragment]. */
fun newInstance(
groupName: String?,
showSystem: Boolean,
sessionId: Long
): AutoPermissionUsageDetailsFragment {
return AutoPermissionUsageDetailsFragment().apply {
- arguments = Bundle().apply {
- putString(Intent.EXTRA_PERMISSION_GROUP_NAME, groupName)
- putLong(Constants.EXTRA_SESSION_ID, sessionId)
- putBoolean(ManagePermissionsActivity.EXTRA_SHOW_SYSTEM, showSystem)
- }
+ arguments =
+ Bundle().apply {
+ putString(Intent.EXTRA_PERMISSION_GROUP_NAME, groupName)
+ putLong(Constants.EXTRA_SESSION_ID, sessionId)
+ putBoolean(ManagePermissionsActivity.EXTRA_SHOW_SYSTEM, showSystem)
+ }
}
}
}
@@ -83,7 +93,7 @@ class AutoPermissionUsageDetailsFragment : AutoSettingsFrameFragment(),
private val SESSION_ID_KEY = (AutoPermissionUsageFragment::class.java.name + KEY_SESSION_ID)
private lateinit var permissionUsages: PermissionUsages
- private lateinit var usageViewModel: PermissionUsageDetailsViewModel
+ private lateinit var usageViewModel: PermissionUsageDetailsViewModelLegacy
private lateinit var filterGroup: String
private lateinit var roleManager: RoleManager
@@ -92,7 +102,7 @@ class AutoPermissionUsageDetailsFragment : AutoSettingsFrameFragment(),
private var finishedInitialLoad = false
private var hasSystemApps = false
- /** Unique Id of a request */
+ /** Unique Id of a request */
private var sessionId: Long = 0
override fun onCreate(savedInstanceState: Bundle?) {
@@ -109,25 +119,26 @@ class AutoPermissionUsageDetailsFragment : AutoSettingsFrameFragment(),
return
}
filterGroup = requireArguments().getString(Intent.EXTRA_PERMISSION_GROUP_NAME)!!
- showSystem = requireArguments().getBoolean(ManagePermissionsActivity.EXTRA_SHOW_SYSTEM,
- false)
- sessionId = savedInstanceState?.getLong(SESSION_ID_KEY)
- ?: (arguments?.getLong(Constants.EXTRA_SESSION_ID, Constants.INVALID_SESSION_ID)
- ?: Constants.INVALID_SESSION_ID)
- headerLabel = resources.getString(R.string.permission_group_usage_title,
- getPermGroupLabel(requireContext(), filterGroup))
+ showSystem =
+ requireArguments().getBoolean(ManagePermissionsActivity.EXTRA_SHOW_SYSTEM, false)
+ sessionId =
+ savedInstanceState?.getLong(SESSION_ID_KEY)
+ ?: (arguments?.getLong(Constants.EXTRA_SESSION_ID, Constants.INVALID_SESSION_ID)
+ ?: Constants.INVALID_SESSION_ID)
+ headerLabel =
+ resources.getString(
+ R.string.permission_group_usage_title,
+ getPermGroupLabel(requireContext(), filterGroup))
val context = preferenceManager.getContext()
- permissionUsages =
- PermissionUsages(
- context
- )
+ permissionUsages = PermissionUsages(context)
roleManager = Utils.getSystemServiceSafe(context, RoleManager::class.java)
- val usageViewModelFactory = PermissionUsageDetailsViewModelFactory(
- PermissionControllerApplication.get(), roleManager,
- filterGroup, sessionId)
- usageViewModel = ViewModelProvider(this,
- usageViewModelFactory)[PermissionUsageDetailsViewModel::class.java]
+ val usageViewModelFactory =
+ PermissionUsageDetailsViewModelFactoryLegacy(
+ PermissionControllerApplication.get(), roleManager, filterGroup, sessionId)
+ usageViewModel =
+ ViewModelProvider(this, usageViewModelFactory)[
+ PermissionUsageDetailsViewModelLegacy::class.java]
reloadData()
}
@@ -143,9 +154,7 @@ class AutoPermissionUsageDetailsFragment : AutoSettingsFrameFragment(),
preferenceScreen.addPreference(AutoDividerPreference(context))
}
- /**
- * Reloads the data to show.
- */
+ /** Reloads the data to show. */
private fun reloadData() {
usageViewModel.loadPermissionUsages(
requireActivity().getLoaderManager(), permissionUsages, this, FILTER_24_HOURS)
@@ -165,7 +174,8 @@ class AutoPermissionUsageDetailsFragment : AutoSettingsFrameFragment(),
private fun updateSystemToggle() {
if (!showSystem) {
PermissionControllerStatsLog.write(
- PERMISSION_USAGE_FRAGMENT_INTERACTION, sessionId,
+ PERMISSION_USAGE_FRAGMENT_INTERACTION,
+ sessionId,
PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__SHOW_SYSTEM_CLICKED)
}
showSystem = !showSystem
@@ -178,11 +188,12 @@ class AutoPermissionUsageDetailsFragment : AutoSettingsFrameFragment(),
setAction(null, null)
return
}
- val label = if (showSystem) {
- getString(R.string.menu_hide_system)
- } else {
- getString(R.string.menu_show_system)
- }
+ val label =
+ if (showSystem) {
+ getString(R.string.menu_hide_system)
+ } else {
+ getString(R.string.menu_show_system)
+ }
setAction(label) { updateSystemToggle() }
}
@@ -193,68 +204,99 @@ class AutoPermissionUsageDetailsFragment : AutoSettingsFrameFragment(),
preferenceScreen.removeAll()
setupHeaderPreferences()
- val permApps = arrayListOf<PermissionApp>()
- val exemptedPackages = Utils.getExemptedPackages(roleManager)
- val seenSystemApp = AtomicBoolean(false)
- val usages: List<AppPermissionUsageEntry> = usageViewModel.parseUsages(
- appPermissionUsages, exemptedPackages, permApps, seenSystemApp, showSystem,
- SHOW_7_DAYS)
+ val uiData =
+ usageViewModel.buildPermissionUsageDetailsUiData(
+ appPermissionUsages, showSystem, SHOW_7_DAYS)
- if (hasSystemApps != seenSystemApp.get()) {
- hasSystemApps = seenSystemApp.get()
+ if (hasSystemApps != uiData.shouldDisplayShowSystemToggle) {
+ hasSystemApps = uiData.shouldDisplayShowSystemToggle
updateAction()
}
- val preferenceFactory = PreferenceFactory(requireActivity())
- val category = AtomicReference(preferenceFactory.createDayCategoryPreference())
+ val category = AtomicReference(PreferenceCategory(context))
preferenceScreen.addPreference(category.get())
AppDataLoader(context) {
- usageViewModel.renderTimelinePreferences(usages, category, preferenceScreen,
- preferenceFactory)
+ renderHistoryPreferences(
+ uiData.getHistoryPreferenceDataList(), category, preferenceScreen)
- setLoading(false)
- finishedInitialLoad = true
- permissionUsages.stopLoader(requireActivity().getLoaderManager())
- }.execute(*permApps.toTypedArray())
+ setLoading(false)
+ finishedInitialLoad = true
+ permissionUsages.stopLoader(requireActivity().getLoaderManager())
+ }
+ .execute(*uiData.permissionApps.toTypedArray())
}
- private class PreferenceFactory(val context: Context) :
- PermissionUsageDetailsViewModel.HistoryPreferenceFactory {
-
- override fun createDayCategoryPreference(): PreferenceCategory {
- return PreferenceCategory(context)
- }
-
- override fun createPermissionHistoryPreference(
- historyPreferenceData: PermissionUsageDetailsViewModel.HistoryPreferenceData
- ): Preference {
- return AutoPermissionHistoryPreference(context, historyPreferenceData)
- }
+ fun createPermissionHistoryPreference(
+ historyPreferenceData: PermissionUsageDetailsViewModelLegacy.HistoryPreferenceData
+ ): Preference {
+ return AutoPermissionHistoryPreference(requireContext(), historyPreferenceData)
}
private fun addTimelineDescriptionPreference() {
- val preference = CarUiPreference(context).apply {
- summary = getString(R.string.permission_group_usage_subtitle_24h,
- getPermGroupLabel(requireContext(), filterGroup))
- isSelectable = false
- }
+ val preference =
+ CarUiPreference(context).apply {
+ summary =
+ getString(
+ R.string.permission_group_usage_subtitle_24h,
+ getPermGroupLabel(requireContext(), filterGroup))
+ isSelectable = false
+ }
preferenceScreen.addPreference(preference)
}
private fun addManagePermissionPreference() {
- val preference = CarUiPreference(context).apply {
- title = getString(R.string.manage_permission)
- summary = getString(R.string.manage_permission_summary,
- getPermGroupLabel(requireContext(), filterGroup))
- onPreferenceClickListener = Preference.OnPreferenceClickListener {
- val intent = Intent(Intent.ACTION_MANAGE_PERMISSION_APPS).apply {
- putExtra(Intent.EXTRA_PERMISSION_NAME, filterGroup)
+ val preference =
+ CarUiPreference(context).apply {
+ title = getString(R.string.manage_permission)
+ summary =
+ getString(
+ R.string.manage_permission_summary,
+ getPermGroupLabel(requireContext(), filterGroup))
+ onPreferenceClickListener =
+ Preference.OnPreferenceClickListener {
+ val intent =
+ Intent(Intent.ACTION_MANAGE_PERMISSION_APPS).apply {
+ putExtra(Intent.EXTRA_PERMISSION_NAME, filterGroup)
+ }
+ startActivity(intent)
+ true
+ }
+ }
+ preferenceScreen.addPreference(preference)
+ }
+
+ /** Render the provided [historyPreferenceDataList] into the [preferenceScreen] UI. */
+ fun renderHistoryPreferences(
+ historyPreferenceDataList:
+ List<PermissionUsageDetailsViewModelLegacy.HistoryPreferenceData>,
+ category: AtomicReference<PreferenceCategory>,
+ preferenceScreen: PreferenceScreen,
+ ) {
+ var previousDateMs = 0L
+ historyPreferenceDataList.forEach {
+ val usageTimestamp = it.accessEndTime
+ val currentDateMs =
+ ZonedDateTime.ofInstant(
+ Instant.ofEpochMilli(usageTimestamp),
+ Clock.system(ZoneId.systemDefault()).zone)
+ .truncatedTo(ChronoUnit.DAYS)
+ .toEpochSecond() * 1000L
+ if (currentDateMs != previousDateMs) {
+ if (previousDateMs != 0L) {
+ category.set(PreferenceCategory(context))
+ preferenceScreen.addPreference(category.get())
}
- startActivity(intent)
- true
+ if (usageTimestamp > MIDNIGHT_TODAY) {
+ category.get().setTitle(R.string.permission_history_category_today)
+ } else if (usageTimestamp > MIDNIGHT_YESTERDAY) {
+ category.get().setTitle(R.string.permission_history_category_yesterday)
+ } else {
+ category.get().setTitle(DateFormat.getDateFormat(context).format(currentDateMs))
+ }
+ previousDateMs = currentDateMs
}
+ category.get().addPreference(createPermissionHistoryPreference(it))
}
- preferenceScreen.addPreference(preference)
}
}
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 5b9d86d4b..d4a2a073e 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
@@ -32,16 +32,17 @@ import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__SHOW_SYSTEM_CLICKED
import com.android.permissioncontroller.R
import com.android.permissioncontroller.auto.AutoSettingsFrameFragment
-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.model.legacy.PermissionApps.AppDataLoader
import com.android.permissioncontroller.permission.model.legacy.PermissionApps.PermissionApp
import com.android.permissioncontroller.permission.model.livedatatypes.PermGroupPackagesUiInfo
+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.model.v31.PermissionUsageViewModel
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageViewModelFactory
+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.utils.Utils
@RequiresApi(Build.VERSION_CODES.S)
@@ -54,7 +55,7 @@ class AutoPermissionUsageFragment : AutoSettingsFrameFragment(), PermissionsUsag
private val SESSION_ID_KEY = (AutoPermissionUsageFragment::class.java.name + KEY_SESSION_ID)
private lateinit var permissionUsages: PermissionUsages
- private lateinit var usageViewModel: PermissionUsageViewModel
+ private lateinit var usageViewModel: PermissionUsageViewModelLegacy
private lateinit var managePermissionsViewModel: ManagePermissionsViewModel
private var appPermissionUsages: List<AppPermissionUsage> = listOf()
@@ -68,33 +69,33 @@ class AutoPermissionUsageFragment : AutoSettingsFrameFragment(), PermissionsUsag
private var finishedInitialLoad = false
private var hasSystemApps = false
- /** Unique Id of a request */
+ /** Unique Id of a request */
private var sessionId: Long = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
headerLabel = getString(R.string.permission_usage_title)
- sessionId = savedInstanceState?.getLong(SESSION_ID_KEY)
- ?: (arguments?.getLong(Constants.EXTRA_SESSION_ID, Constants.INVALID_SESSION_ID)
- ?: Constants.INVALID_SESSION_ID)
+ sessionId =
+ savedInstanceState?.getLong(SESSION_ID_KEY)
+ ?: (arguments?.getLong(Constants.EXTRA_SESSION_ID, Constants.INVALID_SESSION_ID)
+ ?: Constants.INVALID_SESSION_ID)
val context: Context = preferenceManager.getContext()
- permissionUsages =
- PermissionUsages(
- context
- )
+ permissionUsages = PermissionUsages(context)
val roleManager = Utils.getSystemServiceSafe(context, RoleManager::class.java)
val application: Application = requireActivity().getApplication()
- val managePermissionsViewModelFactory = ViewModelProvider.AndroidViewModelFactory
- .getInstance(application)
- managePermissionsViewModel = ViewModelProvider(this,
- managePermissionsViewModelFactory)[ManagePermissionsViewModel::class.java]
- val usageViewModelFactory = PermissionUsageViewModelFactory(roleManager)
- usageViewModel = ViewModelProvider(this,
- usageViewModelFactory)[PermissionUsageViewModel::class.java]
-
- managePermissionsViewModel.standardPermGroupsLiveData.observe(this,
- this::onPermissionGroupsChanged)
+ val managePermissionsViewModelFactory =
+ ViewModelProvider.AndroidViewModelFactory.getInstance(application)
+ managePermissionsViewModel =
+ ViewModelProvider(this, managePermissionsViewModelFactory)[
+ ManagePermissionsViewModel::class.java]
+ val usageViewModelFactory = PermissionUsageViewModelFactoryLegacy(roleManager)
+ usageViewModel =
+ ViewModelProvider(this, usageViewModelFactory)[
+ PermissionUsageViewModelLegacy::class.java]
+
+ managePermissionsViewModel.standardPermGroupsLiveData.observe(
+ this, this::onPermissionGroupsChanged)
setLoading(true)
reloadData()
}
@@ -115,7 +116,9 @@ class AutoPermissionUsageFragment : AutoSettingsFrameFragment(), PermissionsUsag
private fun updateSystemToggle() {
if (!showSystem) {
- PermissionControllerStatsLog.write(PERMISSION_USAGE_FRAGMENT_INTERACTION, sessionId,
+ PermissionControllerStatsLog.write(
+ PERMISSION_USAGE_FRAGMENT_INTERACTION,
+ sessionId,
PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__SHOW_SYSTEM_CLICKED)
}
showSystem = !showSystem
@@ -128,17 +131,16 @@ class AutoPermissionUsageFragment : AutoSettingsFrameFragment(), PermissionsUsag
setAction(null, null)
return
}
- val label = if (showSystem) {
- getString(R.string.menu_hide_system)
- } else {
- getString(R.string.menu_show_system)
- }
+ val label =
+ if (showSystem) {
+ getString(R.string.menu_hide_system)
+ } else {
+ getString(R.string.menu_show_system)
+ }
setAction(label) { updateSystemToggle() }
}
- /**
- * Reloads the data to show.
- */
+ /** Reloads the data to show. */
private fun reloadData() {
usageViewModel.loadPermissionUsages(
requireActivity().getLoaderManager(), permissionUsages, this)
@@ -161,56 +163,66 @@ class AutoPermissionUsageFragment : AutoSettingsFrameFragment(), PermissionsUsag
}
getPreferenceScreen().removeAll()
- val (usages, permApps, seenSystemApps) = usageViewModel.extractUsages(appPermissionUsages,
- show7Days, showSystem)
+ val permissionUsagesUiData =
+ usageViewModel.buildPermissionUsagesUiData(
+ appPermissionUsages, show7Days, showSystem, requireContext())
+ val permissionApps = permissionUsagesUiData.permissionApps
+ val displayShowSystemToggle = permissionUsagesUiData.displayShowSystemToggle
- if (hasSystemApps != seenSystemApps) {
- hasSystemApps = seenSystemApps
+ if (hasSystemApps != displayShowSystemToggle) {
+ hasSystemApps = displayShowSystemToggle
updateAction()
}
- val groupUsagesList: List<Map.Entry<String, Int>> = usageViewModel
- .createGroupUsagesList(requireContext(), usages)
+ val permissionGroupWithUsageCounts: List<PermissionGroupWithUsageCount> =
+ permissionUsagesUiData.orderedPermissionGroupsWithUsageCount
- addUIContent(groupUsagesList, permApps)
+ addUIContent(permissionGroupWithUsageCounts, permissionApps)
}
- /**
- * Use the usages and permApps that are previously constructed to add UI content to the page
- */
+ /** Use the usages and permApps that are previously constructed to add UI content to the page */
private fun addUIContent(
- usages: List<Map.Entry<String, Int>>,
+ permissionGroupWithUsageCounts: List<PermissionGroupWithUsageCount>,
permApps: java.util.ArrayList<PermissionApp>
) {
AppDataLoader(context) {
- // Show permission groups with permissions granted to an app, including groups
- // where the permission is only granted to a system app. This still excludes groups
- // that don't have grants from any apps. Showing the same groups regardless of
- // whether showSystem is selected avoids permission groups hiding and appearing,
- // which is a confusing user experience.
- val usedPermissionGroups = permissionGroups
- .filter {
- (it.nonSystemUserSetOrPreGranted > 0) or
- (it.systemUserSetOrPreGranted > 0)
+ // Show permission groups with permissions granted to an app, including groups
+ // where the permission is only granted to a system app. This still excludes groups
+ // that don't have grants from any apps. Showing the same groups regardless of
+ // whether showSystem is selected avoids permission groups hiding and appearing,
+ // which is a confusing user experience.
+ val usedPermissionGroups =
+ permissionGroups
+ .filter {
+ (it.nonSystemUserSetOrPreGranted > 0) or
+ (it.systemUserSetOrPreGranted > 0)
+ }
+ .filterNot { it.onlyShellPackageGranted }
+
+ for (i in permissionGroupWithUsageCounts.indices) {
+ val groupName = permissionGroupWithUsageCounts[i].permGroup
+ val count = permissionGroupWithUsageCounts[i].appCount
+ if ((usedPermissionGroups.filter { it.name == groupName }).isEmpty()) {
+ continue
+ }
+ val permissionUsagePreference = CarUiPreference(requireContext())
+ PermissionUsageControlPreferenceUtils.initPreference(
+ permissionUsagePreference,
+ requireContext(),
+ groupName,
+ count,
+ showSystem,
+ sessionId,
+ show7Days)
+ getPreferenceScreen().addPreference(permissionUsagePreference)
}
- .filterNot { it.onlyShellPackageGranted }
-
- for (i in usages.indices) {
- val (groupName, count) = usages[i]
- if ((usedPermissionGroups.filter { it.name == groupName }).isEmpty()) {
- continue
+ finishedInitialLoad = true
+ setLoading(false)
+ val activity: Activity? = activity
+ if (activity != null) {
+ permissionUsages.stopLoader(activity.loaderManager)
}
- val permissionUsagePreference = CarUiPreference(requireContext())
- PermissionUsageControlPreferenceUtils.initPreference(permissionUsagePreference,
- requireContext(), groupName, count, showSystem, sessionId, show7Days)
- getPreferenceScreen().addPreference(permissionUsagePreference)
- }
- finishedInitialLoad = true
- setLoading(false)
- val activity: Activity? = activity
- if (activity != null) {
- permissionUsages.stopLoader(activity.loaderManager)
}
- }.execute(*permApps.toTypedArray())
+ .execute(*permApps.toTypedArray())
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AllAppPermissionsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AllAppPermissionsFragment.java
index 9db2bb2dc..a09312a60 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AllAppPermissionsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AllAppPermissionsFragment.java
@@ -47,6 +47,7 @@ import com.android.permissioncontroller.permission.ui.model.AllAppPermissionsVie
import com.android.permissioncontroller.permission.ui.model.AllAppPermissionsViewModelFactory;
import com.android.permissioncontroller.permission.utils.ArrayUtils;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
+import com.android.permissioncontroller.permission.utils.PermissionMapping;
import com.android.permissioncontroller.permission.utils.Utils;
import java.text.Collator;
@@ -215,9 +216,9 @@ public final class AllAppPermissionsFragment extends SettingsWithLargeHeader {
} else if (rKey.equals(KEY_OTHER)) {
return -1;
}
- if (Utils.isModernPermissionGroup(lKey)
- != Utils.isModernPermissionGroup(rKey)) {
- return Utils.isModernPermissionGroup(lKey) ? -1 : 1;
+ if (PermissionMapping.isPlatformPermissionGroup(lKey)
+ != PermissionMapping.isPlatformPermissionGroup(rKey)) {
+ return PermissionMapping.isPlatformPermissionGroup(lKey) ? -1 : 1;
}
return mCollator.compare(lhs.getTitle().toString(), rhs.getTitle().toString());
}
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 dad64abbe..cab0de15e 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java
@@ -17,6 +17,7 @@
package com.android.permissioncontroller.permission.ui.handheld;
import static android.Manifest.permission_group.STORAGE;
+import static android.app.Activity.RESULT_OK;
import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
@@ -27,6 +28,7 @@ import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_
import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__DENY;
import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__DENY_FOREGROUND;
import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__GRANT_FINE_LOCATION;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__PHOTOS_SELECTED;
import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__REVOKE_FINE_LOCATION;
import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.DENIED;
import static com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.DENIED_DO_NOT_ASK_AGAIN;
@@ -38,7 +40,6 @@ import static com.android.permissioncontroller.permission.ui.ManagePermissionsAc
import static com.android.permissioncontroller.permission.ui.handheld.UtilsKt.pressBack;
import android.app.ActionBar;
-import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.role.RoleManager;
@@ -70,27 +71,29 @@ import androidx.core.widget.NestedScrollView;
import androidx.fragment.app.DialogFragment;
import androidx.lifecycle.ViewModelProvider;
+import com.android.modules.utils.build.SdkLevel;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.data.FullStoragePermissionAppsLiveData.FullStoragePackageState;
-import com.android.permissioncontroller.permission.ui.AdvancedConfirmDialogArgs;
import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler;
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.model.AppPermissionViewModel.ChangeRequest;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModelFactory;
+import com.android.permissioncontroller.permission.ui.v33.AdvancedConfirmDialogArgs;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.Utils;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.widget.ActionBarShadowController;
+import kotlin.Pair;
+
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
-import kotlin.Pair;
-
/**
* Show and manage a single permission group for an app.
*
@@ -104,11 +107,14 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
static final String GRANT_CATEGORY = "grant_category";
private @NonNull AppPermissionViewModel mViewModel;
+ private @NonNull ViewGroup mAppPermissionRationaleContainer;
+ private @NonNull ViewGroup mAppPermissionRationaleContent;
private @NonNull RadioButton mAllowButton;
private @NonNull RadioButton mAllowAlwaysButton;
private @NonNull RadioButton mAllowForegroundButton;
private @NonNull RadioButton mAskOneTimeButton;
private @NonNull RadioButton mAskButton;
+ private @NonNull RadioButton mSelectPhotosButton;
private @NonNull RadioButton mDenyButton;
private @NonNull RadioButton mDenyForegroundButton;
private @NonNull View mLocationAccuracy;
@@ -203,6 +209,7 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
if (mIsStorageGroup) {
mViewModel.getFullStorageStateLiveData().observe(this, this::setSpecialStorageState);
}
+ mViewModel.registerPhotoPickerResultIfNeeded(this);
mRoleManager = Utils.getSystemServiceSafe(getContext(), RoleManager.class);
}
@@ -251,6 +258,7 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
mAllowForegroundButton = root.requireViewById(R.id.allow_foreground_only_radio_button);
mAskOneTimeButton = root.requireViewById(R.id.ask_one_time_radio_button);
mAskButton = root.requireViewById(R.id.ask_radio_button);
+ 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);
@@ -280,14 +288,34 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
TextView storageFooter = root.requireViewById(R.id.footer_storage_special_app_access);
storageFooter.setVisibility(View.GONE);
}
+ mAppPermissionRationaleContainer =
+ root.requireViewById(R.id.app_permission_rationale_container);
+ mAppPermissionRationaleContent =
+ root.requireViewById(R.id.app_permission_rationale_content);
+ mViewModel.getShowPermissionRationaleLiveData().observe(this, show -> {
+ showPermissionRationaleDialog(Optional.ofNullable(show).orElse(false));
+ });
getActivity().setTitle(
getPreferenceManager().getContext().getString(R.string.app_permission_title,
mPermGroupLabel));
-
return root;
}
+ private void showPermissionRationaleDialog(boolean showPermissionRationale) {
+ if (!showPermissionRationale) {
+ mAppPermissionRationaleContainer.setVisibility(View.GONE);
+ } else {
+ mAppPermissionRationaleContainer.setVisibility(View.VISIBLE);
+ mAppPermissionRationaleContent.setOnClickListener((v) -> {
+ if (!SdkLevel.isAtLeastU()) {
+ return;
+ }
+ mViewModel.showPermissionRationaleActivity(getActivity(), mPermGroupName);
+ });
+ }
+ }
+
private void setBottomLinkState(TextView view, String caller, String action) {
if ((Objects.equals(caller, AppPermissionGroupsFragment.class.getName())
&& action.equals(Intent.ACTION_MANAGE_APP_PERMISSIONS))
@@ -334,7 +362,7 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
}
private void setRadioButtonsState(Map<ButtonType, ButtonState> states) {
- if (states == null && mViewModel.getButtonStateLiveData().isInitialized()) {
+ if (states == null && !mViewModel.getButtonStateLiveData().isStale()) {
pressBack(this);
Log.w(LOG_TAG, "invalid package " + mPackageName + " or perm group "
+ mPermGroupName);
@@ -378,8 +406,13 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__ASK_EVERY_TIME);
setResult(DENIED);
});
+ mSelectPhotosButton.setOnClickListener((v) -> {
+ int buttonPressed =
+ APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__PHOTOS_SELECTED;
+ mViewModel.requestChange(false, this, this, ChangeRequest.PHOTOS_SELECTED,
+ buttonPressed);
+ });
mDenyButton.setOnClickListener((v) -> {
-
if (mViewModel.getFullStorageStateLiveData().getValue() != null
&& !mViewModel.getFullStorageStateLiveData().getValue().isLegacy()) {
mViewModel.setAllFilesAccess(false);
@@ -416,6 +449,12 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
setButtonState(mAskButton, states.get(ButtonType.ASK));
setButtonState(mDenyButton, states.get(ButtonType.DENY));
setButtonState(mDenyForegroundButton, states.get(ButtonType.DENY_FOREGROUND));
+ setButtonState(mSelectPhotosButton, states.get(ButtonType.SELECT_PHOTOS));
+ if (mSelectPhotosButton.getVisibility() == View.VISIBLE) {
+ mAllowButton.setText(R.string.app_permission_button_always_allow_all);
+ } else {
+ mAllowButton.setText(R.string.app_permission_button_allow);
+ }
ButtonState locationAccuracyState = states.get(ButtonType.LOCATION_ACCURACY);
if (!locationAccuracyState.isShown()) {
@@ -485,7 +524,7 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
Intent intent = new Intent()
.putExtra(EXTRA_RESULT_PERMISSION_INTERACTED, mPermGroupName)
.putExtra(EXTRA_RESULT_PERMISSION_RESULT, result);
- getActivity().setResult(Activity.RESULT_OK, intent);
+ getActivity().setResult(RESULT_OK, intent);
}
private void setDetail(Pair<Integer, Integer> detailResIds) {
@@ -630,6 +669,9 @@ public class AppPermissionFragment extends SettingsWithLargeHeader
AlertDialog.Builder b = new AlertDialog.Builder(getContext())
.setIcon(args.getIconId())
.setMessage(args.getMessageId())
+ .setOnCancelListener((DialogInterface dialog) -> {
+ setRadioButtonsState(mViewModel.getButtonStateLiveData().getValue());
+ })
.setNegativeButton(args.getNegativeButtonTextId(),
(DialogInterface dialog, int which) -> {
setRadioButtonsState(mViewModel.getButtonStateLiveData().getValue());
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 31452a276..a8b79bfde 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java
@@ -24,7 +24,6 @@ import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_
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.handheld.UtilsKt.pressBack;
-import static com.android.permissioncontroller.permission.ui.handheld.v31.DashboardUtilsKt.is7DayToggleEnabled;
import static java.util.concurrent.TimeUnit.DAYS;
@@ -183,7 +182,7 @@ public final class AppPermissionGroupsFragment extends SettingsWithLargeHeader i
Context context = getPreferenceManager().getContext();
mPermissionUsages = new PermissionUsages(context);
- long aggregateDataFilterBeginDays = is7DayToggleEnabled()
+ long aggregateDataFilterBeginDays = KotlinUtils.INSTANCE.is7DayToggleEnabled()
? AppPermissionGroupsViewModel.AGGREGATE_DATA_FILTER_BEGIN_DAYS_7 :
AppPermissionGroupsViewModel.AGGREGATE_DATA_FILTER_BEGIN_DAYS_1;
@@ -291,7 +290,7 @@ public final class AppPermissionGroupsFragment extends SettingsWithLargeHeader i
}
private void updatePreferences(Map<Category, List<GroupUiInfo>> groupMap) {
- if (groupMap == null && mViewModel.getPackagePermGroupsLiveData().isInitialized()) {
+ if (groupMap == null && !mViewModel.getPackagePermGroupsLiveData().isStale()) {
// null because explicitly set to null
Toast.makeText(
getActivity(), R.string.app_not_found_dlg_title, Toast.LENGTH_LONG).show();
@@ -370,6 +369,8 @@ public final class AppPermissionGroupsFragment extends SettingsWithLargeHeader i
resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name));
preference.setRightIcon(
context.getDrawable(R.drawable.ic_info_outline),
+ context.getString(R.string.learn_more_content_description,
+ KotlinUtils.INSTANCE.getPermGroupLabel(context, groupName)),
v -> {
try {
startActivity(viewUsageIntent);
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 73cd4071d..decbfe590 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/GrantPermissionsViewHandlerImpl.kt
@@ -20,20 +20,9 @@ package com.android.permissioncontroller.permission.ui.handheld
import android.Manifest.permission.ACCESS_COARSE_LOCATION
import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.app.Activity
-import android.content.res.Configuration
-import android.graphics.Color
-import android.graphics.ImageDecoder
-import android.graphics.Paint
-import android.graphics.Path
-import android.graphics.PixelFormat
-import android.graphics.PorterDuff
-import android.graphics.PorterDuffXfermode
import android.graphics.Typeface
-import android.graphics.drawable.AnimatedImageDrawable
-import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
import android.os.Bundle
-import android.os.UserHandle
import android.text.method.LinkMovementMethod
import android.transition.ChangeBounds
import android.transition.TransitionManager
@@ -52,18 +41,24 @@ import android.widget.LinearLayout
import android.widget.RadioButton
import android.widget.RadioGroup
import android.widget.TextView
+import androidx.annotation.RawRes
+import com.airbnb.lottie.LottieCompositionFactory
+import com.airbnb.lottie.LottieDrawable
import com.android.modules.utils.build.SdkLevel
import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.ALLOW_ALL_BUTTON
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.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.LOCATION_ACCURACY_LAYOUT
import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.NEXT_BUTTON
@@ -76,22 +71,22 @@ import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandle
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
+import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.DENIED_MORE
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.GrantPermissionsViewHandler.GRANTED_ONE_TIME
+import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.GRANTED_USER_SELECTED
+import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.ResultListener
class GrantPermissionsViewHandlerImpl(
private val mActivity: Activity,
- private val mAppPackageName: String,
- private val mUserHandle: UserHandle
+ 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).toInt()
-
- private var resultListener: GrantPermissionsViewHandler.ResultListener? = null
+ R.dimen.location_accuracy_image_size)
// Configuration of the current dialog
private var groupName: String? = null
@@ -100,32 +95,28 @@ class GrantPermissionsViewHandlerImpl(
private var groupIcon: Icon? = null
private var groupMessage: CharSequence? = null
private var detailMessage: CharSequence? = null
+ private var permissionRationaleMessage: CharSequence? = null
private val buttonVisibilities = BooleanArray(NEXT_BUTTON) { false }
private val locationVisibilities = BooleanArray(NEXT_LOCATION_DIALOG) { false }
private var selectedPrecision: Int = 0
private var isLocationPermissionDialogActionClicked: Boolean = false
private var coarseRadioButton: RadioButton? = null
private var fineRadioButton: RadioButton? = null
- private var coarseOffDrawable: AnimatedImageDrawable? = null
- private var coarseOnDrawable: AnimatedImageDrawable? = null
- private var fineOffDrawable: AnimatedImageDrawable? = null
- private var fineOnDrawable: AnimatedImageDrawable? = null
+ private var coarseOffDrawable: LottieDrawable? = null
+ private var coarseOnDrawable: LottieDrawable? = null
+ private var fineOffDrawable: LottieDrawable? = null
+ private var fineOnDrawable: LottieDrawable? = null
// Views
private var iconView: ImageView? = null
private var messageView: TextView? = null
private var detailMessageView: TextView? = null
+ private var permissionRationaleView: View? = null
+ private var permissionRationaleMessageView: TextView? = null
private var buttons: Array<Button?> = arrayOfNulls(NEXT_BUTTON)
private var locationViews: Array<View?> = arrayOfNulls(NEXT_LOCATION_DIALOG)
private var rootView: ViewGroup? = null
- override fun setResultListener(
- listener: GrantPermissionsViewHandler.ResultListener
- ): GrantPermissionsViewHandlerImpl {
- resultListener = listener
- return this
- }
-
override fun saveInstanceState(arguments: Bundle) {
arguments.putString(ARG_GROUP_NAME, groupName)
arguments.putInt(ARG_GROUP_COUNT, groupCount)
@@ -133,6 +124,8 @@ 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.putBooleanArray(ARG_DIALOG_BUTTON_VISIBILITIES, buttonVisibilities)
arguments.putBooleanArray(ARG_DIALOG_LOCATION_VISIBILITIES, locationVisibilities)
arguments.putInt(ARG_DIALOG_SELECTED_PRECISION, selectedPrecision)
@@ -145,6 +138,8 @@ class GrantPermissionsViewHandlerImpl(
groupCount = savedInstanceState.getInt(ARG_GROUP_COUNT)
groupIndex = savedInstanceState.getInt(ARG_GROUP_INDEX)
detailMessage = savedInstanceState.getCharSequence(ARG_GROUP_DETAIL_MESSAGE)
+ permissionRationaleMessage =
+ savedInstanceState.getCharSequence(ARG_GROUP_PERMISSION_RATIONALE_MESSAGE)
setButtonVisibilities(savedInstanceState.getBooleanArray(ARG_DIALOG_BUTTON_VISIBILITIES))
setLocationVisibilities(savedInstanceState.getBooleanArray(
ARG_DIALOG_LOCATION_VISIBILITIES))
@@ -154,14 +149,15 @@ class GrantPermissionsViewHandlerImpl(
}
override fun updateUi(
- groupName: String,
+ groupName: String?,
groupCount: Int,
groupIndex: Int,
icon: Icon?,
message: CharSequence?,
detailMessage: CharSequence?,
- buttonVisibilities: BooleanArray,
- locationVisibilities: BooleanArray
+ permissionRationaleMessage: CharSequence?,
+ buttonVisibilities: BooleanArray?,
+ locationVisibilities: BooleanArray?
) {
this.groupName = groupName
@@ -170,6 +166,7 @@ class GrantPermissionsViewHandlerImpl(
groupIcon = icon
groupMessage = message
this.detailMessage = detailMessage
+ this.permissionRationaleMessage = permissionRationaleMessage
setButtonVisibilities(buttonVisibilities)
setLocationVisibilities(locationVisibilities)
@@ -182,11 +179,12 @@ class GrantPermissionsViewHandlerImpl(
private fun updateAll() {
updateDescription()
updateDetailDescription()
+ updatePermissionRationale()
updateButtons()
updateLocationVisibilities()
- // Animate change in size
- // Grow or shrink the content container to size of new content
+ // Animate change in size
+ // Grow or shrink the content container to size of new content
val growShrinkToNewContentSize = ChangeBounds()
growShrinkToNewContentSize.duration = ANIMATION_DURATION_MILLIS
growShrinkToNewContentSize.interpolator = AnimationUtils.loadInterpolator(mActivity,
@@ -195,9 +193,6 @@ class GrantPermissionsViewHandlerImpl(
}
override fun createView(): View {
- // Make this activity be Non-IME target to prevent hiding keyboard flicker when it show up.
- mActivity.window.addFlags(LayoutParams.FLAG_ALT_FOCUSABLE_IM)
-
val useMaterial3PermissionGrantDialog = mActivity.resources
.getBoolean(R.bool.config_useMaterial3PermissionGrantDialog)
val rootView = if (useMaterial3PermissionGrantDialog || SdkLevel.isAtLeastT()) {
@@ -224,6 +219,10 @@ class GrantPermissionsViewHandlerImpl(
detailMessageView!!.movementMethod = LinkMovementMethod.getInstance()
iconView = rootView.findViewById(R.id.permission_icon)
+ permissionRationaleView = rootView.findViewById(R.id.permission_rationale_container)
+ permissionRationaleMessageView = rootView.findViewById(R.id.permission_rationale_message)
+ permissionRationaleView!!.setOnClickListener(this)
+
val buttons = arrayOfNulls<Button>(NEXT_BUTTON)
val numButtons = BUTTON_RES_ID_TO_NUM.size()
for (i in 0 until numButtons) {
@@ -238,6 +237,7 @@ class GrantPermissionsViewHandlerImpl(
val locationView = rootView.findViewById<View>(LOCATION_RES_ID_TO_NUM.keyAt(i))
locationViews[LOCATION_RES_ID_TO_NUM.valueAt(i)] = locationView
}
+
initializeAnimatedImages()
// Set location accuracy radio buttons' click listeners
@@ -254,44 +254,26 @@ class GrantPermissionsViewHandlerImpl(
return rootView
}
- private fun initializeAnimatedImages() {
- val isDarkMode = (mActivity.resources.configuration.uiMode and
- Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
- val coarseOffDrawableId = if (isDarkMode) R.drawable.coarse_off_dark
- else R.drawable.coarse_off_light
- val coarseOnDrawableId = if (isDarkMode) R.drawable.coarse_on_dark
- else R.drawable.coarse_on_light
- val fineOffDrawableId = if (isDarkMode) R.drawable.fine_off_dark
- else R.drawable.fine_off_light
- val fineOnDrawableId = if (isDarkMode) R.drawable.fine_on_dark else R.drawable.fine_on_light
-
- coarseOffDrawable = getDrawableFromId(coarseOffDrawableId) as AnimatedImageDrawable
- coarseOnDrawable = getDrawableFromId(coarseOnDrawableId) as AnimatedImageDrawable
- fineOffDrawable = getDrawableFromId(fineOffDrawableId) as AnimatedImageDrawable
- fineOnDrawable = getDrawableFromId(fineOnDrawableId) as AnimatedImageDrawable
- }
-
- private fun getDrawableFromId(drawableId: Int): Drawable {
- val source = ImageDecoder.createSource(mActivity.resources, drawableId)
- return ImageDecoder.decodeDrawable(source) { decoder, _, _ ->
- decoder.setTargetSize(LOCATION_ACCURACY_IMAGE_DIAMETER,
- LOCATION_ACCURACY_IMAGE_DIAMETER)
- decoder.setPostProcessor { canvas ->
- // This will crop the image to circle image.
- val path = Path()
- path.fillType = Path.FillType.INVERSE_EVEN_ODD
- val width: Int = canvas.width
- val height: Int = canvas.height
- path.addRoundRect(0f, 0f, width.toFloat(), height.toFloat(),
- width.toFloat() / 2, height.toFloat() / 2, Path.Direction.CW)
- val paint = Paint()
- paint.isAntiAlias = true
- paint.color = Color.TRANSPARENT
- paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC)
- canvas.drawPath(path, paint)
- PixelFormat.TRANSLUCENT
+ 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()
}
}
+ drawable.composition = composition
+ return drawable
+ }
+
+ private fun initializeAnimatedImages() {
+ coarseOffDrawable = getLottieDrawable(R.raw.coarse_loc_off)
+ coarseOnDrawable = getLottieDrawable(R.raw.coarse_loc_on)
+ fineOffDrawable = getLottieDrawable(R.raw.fine_loc_off)
+ fineOnDrawable = getLottieDrawable(R.raw.fine_loc_on)
}
override fun updateWindowAttributes(outLayoutParams: LayoutParams) {
@@ -334,6 +316,16 @@ class GrantPermissionsViewHandlerImpl(
}
}
+ private fun updatePermissionRationale() {
+ val message = permissionRationaleMessage
+ if (message == null || message.isEmpty()) {
+ permissionRationaleView!!.visibility = View.GONE
+ } else {
+ permissionRationaleMessageView!!.text = message
+ permissionRationaleView!!.visibility = View.VISIBLE
+ }
+ }
+
private fun updateButtons() {
for (i in 0 until BUTTON_RES_ID_TO_NUM.size()) {
val pos = BUTTON_RES_ID_TO_NUM.valueAt(i)
@@ -431,8 +423,8 @@ class GrantPermissionsViewHandlerImpl(
null, null)
fineRadioButton?.setCompoundDrawablesWithIntrinsicBounds(null, fineOffDrawable,
null, null)
- coarseOnDrawable?.start()
fineOffDrawable?.start()
+ coarseOnDrawable?.start()
coarseRadioButton?.setTypeface(null, Typeface.BOLD)
fineRadioButton?.setTypeface(null, Typeface.NORMAL)
}
@@ -441,17 +433,26 @@ class GrantPermissionsViewHandlerImpl(
override fun onClick(view: View) {
val id = view.id
+ if (id == R.id.permission_rationale_container) {
+ resultListener.onPermissionRationaleClicked(groupName)
+ return
+ }
+
if (id == R.id.permission_location_accuracy_radio_fine) {
- (locationViews[FINE_RADIO_BUTTON] as RadioButton).isChecked = true
- selectedPrecision = FINE_RADIO_BUTTON
- runLocationAccuracyAnimation(true)
+ if (selectedPrecision != FINE_RADIO_BUTTON) {
+ (locationViews[FINE_RADIO_BUTTON] as RadioButton).isChecked = true
+ selectedPrecision = FINE_RADIO_BUTTON
+ runLocationAccuracyAnimation(true)
+ }
return
}
if (id == R.id.permission_location_accuracy_radio_coarse) {
- (locationViews[COARSE_RADIO_BUTTON] as RadioButton).isChecked = true
- selectedPrecision = COARSE_RADIO_BUTTON
- runLocationAccuracyAnimation(false)
+ if (selectedPrecision != COARSE_RADIO_BUTTON) {
+ (locationViews[COARSE_RADIO_BUTTON] as RadioButton).isChecked = true
+ selectedPrecision = COARSE_RADIO_BUTTON
+ runLocationAccuracyAnimation(false)
+ }
return
}
@@ -460,11 +461,7 @@ class GrantPermissionsViewHandlerImpl(
}
if (id == R.id.grant_singleton) {
- if (resultListener != null) {
- resultListener!!.onPermissionGrantResult(groupName, CANCELED)
- } else {
- mActivity.finishAfterTransition()
- }
+ resultListener.onPermissionGrantResult(groupName, CANCELED)
return
}
@@ -484,55 +481,70 @@ class GrantPermissionsViewHandlerImpl(
}
when (BUTTON_RES_ID_TO_NUM.get(id, -1)) {
- ALLOW_BUTTON -> if (resultListener != null) {
+ ALLOW_ALL_BUTTON, ALLOW_BUTTON -> {
view.performAccessibilityAction(
AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null)
- resultListener!!.onPermissionGrantResult(groupName, affectedForegroundPermissions,
+ resultListener.onPermissionGrantResult(groupName, affectedForegroundPermissions,
GRANTED_ALWAYS)
}
- ALLOW_FOREGROUND_BUTTON -> if (resultListener != null) {
+ ALLOW_FOREGROUND_BUTTON -> {
view.performAccessibilityAction(
AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null)
- resultListener!!.onPermissionGrantResult(groupName, affectedForegroundPermissions,
+ resultListener.onPermissionGrantResult(groupName, affectedForegroundPermissions,
GRANTED_FOREGROUND_ONLY)
}
- ALLOW_ALWAYS_BUTTON -> if (resultListener != null) {
+ ALLOW_ALWAYS_BUTTON -> {
view.performAccessibilityAction(
AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null)
- resultListener!!.onPermissionGrantResult(groupName, affectedForegroundPermissions,
+ resultListener.onPermissionGrantResult(groupName, affectedForegroundPermissions,
GRANTED_ALWAYS)
}
- ALLOW_ONE_TIME_BUTTON -> if (resultListener != null) {
+ ALLOW_ONE_TIME_BUTTON -> {
view.performAccessibilityAction(
AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null)
- resultListener!!.onPermissionGrantResult(groupName, affectedForegroundPermissions,
+ resultListener.onPermissionGrantResult(groupName, affectedForegroundPermissions,
GRANTED_ONE_TIME)
}
- DENY_BUTTON, NO_UPGRADE_BUTTON, NO_UPGRADE_OT_BUTTON -> if (resultListener != null) {
+ ALLOW_SELECTED_BUTTON -> {
+ view.performAccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null)
+ resultListener.onPermissionGrantResult(groupName, affectedForegroundPermissions,
+ GRANTED_USER_SELECTED)
+ }
+ DONT_ALLOW_MORE_SELECTED_BUTTON -> {
+ resultListener.onPermissionGrantResult(groupName, affectedForegroundPermissions,
+ DENIED_MORE)
+ }
+ DENY_BUTTON, NO_UPGRADE_BUTTON, NO_UPGRADE_OT_BUTTON -> {
view.performAccessibilityAction(
AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null)
- resultListener!!.onPermissionGrantResult(groupName, affectedForegroundPermissions,
+ resultListener.onPermissionGrantResult(groupName, affectedForegroundPermissions,
DENIED)
}
DENY_AND_DONT_ASK_AGAIN_BUTTON, NO_UPGRADE_AND_DONT_ASK_AGAIN_BUTTON,
- NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON -> if (resultListener != null) {
+ NO_UPGRADE_OT_AND_DONT_ASK_AGAIN_BUTTON -> {
view.performAccessibilityAction(
AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null)
- resultListener!!.onPermissionGrantResult(groupName, affectedForegroundPermissions,
+ resultListener.onPermissionGrantResult(groupName, affectedForegroundPermissions,
DENIED_DO_NOT_ASK_AGAIN)
}
}
}
override fun onBackPressed() {
- if (resultListener == null) {
- mActivity.finishAfterTransition()
- return
- }
- resultListener?.onPermissionGrantResult(groupName, CANCELED)
+ onCancelled()
+ }
+
+ override fun onCancelled() {
+ resultListener.onPermissionGrantResult(groupName, CANCELED)
+ }
+
+ override fun setResultListener(listener: ResultListener): GrantPermissionsViewHandler {
+ throw UnsupportedOperationException()
}
companion object {
+ private val TAG = GrantPermissionsViewHandlerImpl::class.java.simpleName
const val ARG_GROUP_NAME = "ARG_GROUP_NAME"
const val ARG_GROUP_COUNT = "ARG_GROUP_COUNT"
@@ -540,6 +552,8 @@ class GrantPermissionsViewHandlerImpl(
const val ARG_GROUP_ICON = "ARG_GROUP_ICON"
const val ARG_GROUP_MESSAGE = "ARG_GROUP_MESSAGE"
private const val ARG_GROUP_DETAIL_MESSAGE = "ARG_GROUP_DETAIL_MESSAGE"
+ private const val ARG_GROUP_PERMISSION_RATIONALE_MESSAGE =
+ "ARG_GROUP_PERMISSION_RATIONALE_MESSAGE"
private const val ARG_DIALOG_BUTTON_VISIBILITIES = "ARG_DIALOG_BUTTON_VISIBILITIES"
private const val ARG_DIALOG_LOCATION_VISIBILITIES = "ARG_DIALOG_LOCATION_VISIBILITIES"
private const val ARG_DIALOG_SELECTED_PRECISION = "ARG_DIALOG_SELECTED_PRECISION"
@@ -568,6 +582,12 @@ class GrantPermissionsViewHandlerImpl(
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,
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 879e6082a..8e3192eee 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ManageStandardPermissionsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ManageStandardPermissionsFragment.java
@@ -20,7 +20,6 @@ import static androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory;
import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
import static com.android.permissioncontroller.permission.ui.handheld.UtilsKt.pressBack;
-import static com.android.permissioncontroller.permission.ui.handheld.v31.DashboardUtilsKt.shouldShowPermissionsDashboard;
import android.app.Application;
import android.content.Intent;
@@ -39,6 +38,7 @@ 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;
@@ -77,6 +77,9 @@ public final class ManageStandardPermissionsFragment extends ManagePermissionsFr
mPermissionGroups = mViewModel.getUiDataLiveData().getValue();
mViewModel.getUiDataLiveData().observe(this, permissionGroups -> {
+ // Once we have loaded data for the first time, further loads should be staggered,
+ // for performance reasons.
+ mViewModel.getUiDataLiveData().setLoadStaggered(true);
if (permissionGroups != null) {
mPermissionGroups = permissionGroups;
updatePermissionsUi();
@@ -84,6 +87,11 @@ public final class ManageStandardPermissionsFragment extends ManagePermissionsFr
Log.e(LOG_TAG, "ViewModel returned null data, exiting");
getActivity().finishAfterTransition();
}
+
+ // If we've loaded all LiveDatas, no need to prioritize loading any particular one
+ if (!mViewModel.getUiDataLiveData().isStale()) {
+ mViewModel.getUiDataLiveData().setFirstLoadGroup(null);
+ }
});
mViewModel.getNumCustomPermGroups().observe(this, permNames -> updatePermissionsUi());
@@ -115,7 +123,7 @@ public final class ManageStandardPermissionsFragment extends ManagePermissionsFr
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
- if (shouldShowPermissionsDashboard()) {
+ if (KotlinUtils.INSTANCE.shouldShowPermissionsDashboard()) {
menu.add(Menu.NONE, MENU_PERMISSION_USAGE, Menu.NONE, R.string.permission_usage_title);
}
}
@@ -209,6 +217,9 @@ public final class ManageStandardPermissionsFragment extends ManagePermissionsFr
@Override
public void showPermissionApps(String permissionGroupName) {
+ // If we return to this page within a reasonable time, prioritize loading data from the
+ // permission group whose page we are going to, as that is group most likely to have changed
+ mViewModel.getUiDataLiveData().setFirstLoadGroup(permissionGroupName);
mViewModel.showPermissionApps(this, PermissionAppsFragment.createArgs(
permissionGroupName, getArguments().getLong(EXTRA_SESSION_ID)));
}
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 1d92a6e74..220507426 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java
@@ -22,7 +22,6 @@ import static com.android.permissioncontroller.permission.ui.Category.ALLOWED_FO
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.handheld.UtilsKt.pressBack;
-import static com.android.permissioncontroller.permission.ui.handheld.v31.DashboardUtilsKt.shouldShowPermissionsDashboard;
import android.Manifest;
import android.app.ActionBar;
@@ -54,6 +53,7 @@ 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;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
@@ -197,7 +197,7 @@ public final class PermissionAppsFragment extends SettingsWithLargeHeader implem
updateMenu(mViewModel.getShouldShowSystemLiveData().getValue());
}
- if (shouldShowPermissionsDashboard()) {
+ if (KotlinUtils.INSTANCE.shouldShowPermissionsDashboard()) {
menu.add(Menu.NONE, MENU_PERMISSION_USAGE, Menu.NONE, R.string.permission_usage_title);
}
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 8b6aa7576..318ebea06 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionControlPreference.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionControlPreference.java
@@ -16,6 +16,8 @@
package com.android.permissioncontroller.permission.ui.handheld;
+import static android.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP;
+
import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
import static com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_CALLER_NAME;
import static com.android.permissioncontroller.permission.ui.handheld.AppPermissionFragment.GRANT_CATEGORY;
@@ -54,6 +56,7 @@ import java.util.List;
public class PermissionControlPreference extends Preference {
private final @NonNull Context mContext;
private @Nullable Drawable mWidgetIcon;
+ private @Nullable String mWidgetIconContentDescription;
private @Nullable View.OnClickListener mWidgetIconOnClickListener;
private @Nullable String mGranted;
private boolean mUseSmallerIcon;
@@ -117,8 +120,10 @@ public class PermissionControlPreference extends Preference {
* @param widgetIcon the icon to use.
* @param listener the onClickListener attached to the icon.
*/
- public void setRightIcon(@NonNull Drawable widgetIcon, @NonNull View.OnClickListener listener) {
+ public void setRightIcon(@NonNull Drawable widgetIcon,
+ @NonNull String widgetIconContentDescription, @NonNull View.OnClickListener listener) {
mWidgetIcon = widgetIcon;
+ mWidgetIconContentDescription = widgetIconContentDescription;
setWidgetLayoutResource(R.layout.image_view_with_divider);
mWidgetIconOnClickListener = listener;
}
@@ -181,9 +186,16 @@ public class PermissionControlPreference extends Preference {
if (mWidgetIcon != null) {
View widgetFrame = holder.findViewById(android.R.id.widget_frame);
- ((ImageView) widgetFrame.findViewById(R.id.icon)).setImageDrawable(mWidgetIcon);
+ ImageView widgetIcon = widgetFrame.findViewById(R.id.icon);
+ widgetIcon.setImageDrawable(mWidgetIcon);
+ widgetIcon.setContentDescription(mWidgetIconContentDescription);
+
if (mWidgetIconOnClickListener != null) {
widgetFrame.findViewById(R.id.icon).setOnClickListener(mWidgetIconOnClickListener);
+ View preferenceRootView = holder.itemView;
+ preferenceRootView.setPaddingRelative(
+ preferenceRootView.getPaddingStart(), preferenceRootView.getPaddingTop(),
+ 0, preferenceRootView.getPaddingBottom());
}
}
@@ -211,6 +223,11 @@ public class PermissionControlPreference extends Preference {
Utils.navigateToAppNotificationSettings(mContext, mPackageName, mUser);
return true;
}
+ if (Utils.isHealthPermissionUiEnabled()
+ && mPermGroupName.equals(HEALTH_PERMISSION_GROUP)) {
+ Utils.navigateToAppHealthConnectSettings(mContext, mPackageName, mUser);
+ return true;
+ }
Bundle args = new Bundle();
args.putString(Intent.EXTRA_PACKAGE_NAME, mPackageName);
args.putString(Intent.EXTRA_PERMISSION_GROUP_NAME, mPermGroupName);
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 9569baeeb..658a82af5 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionPreference.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionPreference.java
@@ -36,10 +36,10 @@ import androidx.preference.PreferenceFragmentCompat;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup;
-import com.android.permissioncontroller.permission.ui.model.v33.ReviewPermissionsViewModel;
-import com.android.permissioncontroller.permission.ui.model.v33.ReviewPermissionsViewModel.PermissionSummary;
-import com.android.permissioncontroller.permission.ui.model.v33.ReviewPermissionsViewModel.PermissionTarget;
-import com.android.permissioncontroller.permission.ui.model.v33.ReviewPermissionsViewModel.SummaryMessage;
+import com.android.permissioncontroller.permission.ui.model.ReviewPermissionsViewModel;
+import com.android.permissioncontroller.permission.ui.model.ReviewPermissionsViewModel.PermissionSummary;
+import com.android.permissioncontroller.permission.ui.model.ReviewPermissionsViewModel.PermissionTarget;
+import com.android.permissioncontroller.permission.ui.model.ReviewPermissionsViewModel.SummaryMessage;
import com.android.permissioncontroller.permission.utils.LocationUtils;
import com.android.permissioncontroller.permission.utils.Utils;
import com.android.settingslib.RestrictedLockUtils;
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 a6f74c822..5e5c221ae 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ReviewPermissionsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/ReviewPermissionsFragment.java
@@ -57,9 +57,9 @@ import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup;
import com.android.permissioncontroller.permission.model.livedatatypes.LightPermission;
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity;
-import com.android.permissioncontroller.permission.ui.model.v33.ReviewPermissionViewModelFactory;
-import com.android.permissioncontroller.permission.ui.model.v33.ReviewPermissionsViewModel;
-import com.android.permissioncontroller.permission.ui.model.v33.ReviewPermissionsViewModel.PermissionTarget;
+import com.android.permissioncontroller.permission.ui.model.ReviewPermissionViewModelFactory;
+import com.android.permissioncontroller.permission.ui.model.ReviewPermissionsViewModel;
+import com.android.permissioncontroller.permission.ui.model.ReviewPermissionsViewModel.PermissionTarget;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.Utils;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/CardViewPreference.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/CardViewPreference.java
index 6c76d906b..008813a83 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/CardViewPreference.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/CardViewPreference.java
@@ -14,13 +14,15 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.ui.handheld;
+package com.android.permissioncontroller.permission.ui.handheld.v31;
import android.content.Context;
import android.content.Intent;
+import android.os.Build;
import android.view.View;
import android.widget.Button;
+import androidx.annotation.RequiresApi;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
@@ -30,6 +32,7 @@ import com.android.permissioncontroller.R;
/**
* A Preference representing a banner message represented as a CardView
*/
+@RequiresApi(Build.VERSION_CODES.S)
public class CardViewPreference extends Preference {
private String mAction;
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 fbb5164b4..5b92dd36d 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
@@ -19,7 +19,6 @@ package com.android.permissioncontroller.permission.ui.handheld.v31
import android.content.Context
import android.icu.util.Calendar
import android.os.Build
-import android.provider.DeviceConfig
import android.text.format.DateFormat.getMediumDateFormat
import android.text.format.DateFormat.getTimeFormat
import android.util.Pair
@@ -30,132 +29,18 @@ import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage.
import com.android.permissioncontroller.permission.utils.StringUtils
import java.util.Locale
-/** 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. */
-const val PROPERTY_CAMERA_MIC_ICONS_ENABLED = "camera_mic_icons_enabled"
-
-/** Whether to show the location indicators. */
-const val PROPERTY_LOCATION_INDICATORS_ENABLED = "location_indicators_enabled"
-
-/* Whether location accuracy feature is enabled */
-const val PROPERTY_LOCATION_ACCURACY_ENABLED = "location_accuracy_enabled"
-
-/** Whether subattribution is enabled in Permissions Hub. */
-const val PROPERTY_PERMISSIONS_HUB_SUBATTRIBUTION_ENABLED = "permissions_hub_subattribution_enabled"
-
-/** 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 */
-const val PROPERTY_LOCATION_PRECISION = "location_precision"
-
const val SECONDS = 1
const val MINUTES = 2
const val HOURS = 3
const val DAYS = 4
/**
- * Whether the Permissions Hub 2 flag is enabled
- *
- * @return whether the flag is enabled
- */
-fun isPermissionsHub2FlagEnabled(): Boolean {
- return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_PERMISSIONS_HUB_2_ENABLED, false)
-}
-/**
- * Whether to show the Permissions Dashboard
- *
- * @return whether to show the Permissions Dashboard.
- */
-fun shouldShowPermissionsDashboard(): Boolean {
- return isPermissionsHub2FlagEnabled()
-}
-
-/**
- * Whether we should enable the 7-day toggle in privacy dashboard
- *
- * @return whether the flag is enabled
- */
-fun is7DayToggleEnabled(): Boolean {
- return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PRIVACY_DASHBOARD_7_DAY_TOGGLE, false)
-}
-
-/**
- * Whether the Permissions Hub Subattribution flag is enabled
- *
- * @return whether the flag is enabled
- */
-fun isPermissionsHubSubattributionFlagEnabled(): Boolean {
- return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_PERMISSIONS_HUB_SUBATTRIBUTION_ENABLED, true)
-}
-/**
* Whether to show the subattribution in the Permissions Dashboard
*
* @return whether to show subattribution in the Permissions Dashboard.
*/
fun shouldShowSubattributionInPermissionsDashboard(): Boolean {
- return SdkLevel.isAtLeastS() && isPermissionsHubSubattributionFlagEnabled()
-}
-
-/**
- * Whether the Camera and Mic Icons are enabled by flag.
- *
- * @return whether the Camera and Mic Icons are enabled.
- */
-fun isCameraMicIconsFlagEnabled(): Boolean {
- return 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.
- *
- * @return whether to show the icons.
- */
-fun shouldShowCameraMicIndicators(): Boolean {
- return isCameraMicIconsFlagEnabled() || isPermissionsHub2FlagEnabled()
-}
-
-/**
- * Whether the location indicators are enabled by flag.
- *
- * @return whether the location indicators are enabled by flag.
- */
-fun isLocationIndicatorsFlagEnabled(): Boolean {
- return 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.
- */
-fun shouldShowLocationIndicators(): Boolean {
- return isLocationIndicatorsFlagEnabled() || isPermissionsHub2FlagEnabled()
-}
-
-/**
- * Whether the location accuracy feature is enabled
- */
-fun isLocationAccuracyEnabled(): Boolean {
- return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_LOCATION_ACCURACY_ENABLED, true)
-}
-
-/**
- * Default state of location precision
- * true: default is FINE.
- * false: default is COARSE.
- */
-fun getDefaultPrecision(): Boolean {
- return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_LOCATION_PRECISION, true)
+ return SdkLevel.isAtLeastS()
}
/**
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionDetailsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionDetailsFragment.java
deleted file mode 100644
index 58d0657cd..000000000
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionDetailsFragment.java
+++ /dev/null
@@ -1,396 +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.permissioncontroller.permission.ui.handheld.v31;
-
-import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
-import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
-import static com.android.permissioncontroller.permission.ui.handheld.v31.DashboardUtilsKt.is7DayToggleEnabled;
-
-import android.app.ActionBar;
-import android.app.Activity;
-import android.app.role.RoleManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.ColorStateList;
-import android.content.res.Configuration;
-import android.content.res.TypedArray;
-import android.os.Build;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
-import androidx.coordinatorlayout.widget.CoordinatorLayout;
-import androidx.lifecycle.ViewModelProvider;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceScreen;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.android.permissioncontroller.PermissionControllerApplication;
-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.model.legacy.PermissionApps;
-import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity;
-import com.android.permissioncontroller.permission.ui.handheld.SettingsWithLargeHeader;
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel;
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModelFactory;
-import com.android.permissioncontroller.permission.utils.KotlinUtils;
-import com.android.permissioncontroller.permission.utils.Utils;
-
-import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * The permission details page showing the history/timeline of a permission
- */
-@RequiresApi(Build.VERSION_CODES.S)
-public class PermissionDetailsFragment extends SettingsWithLargeHeader implements
- PermissionUsages.PermissionsUsagesChangeCallback {
-
- public static final int FILTER_7_DAYS = 1;
- private static final String KEY_SHOW_SYSTEM_PREFS = "_show_system";
- private static final String SHOW_SYSTEM_KEY = PermissionDetailsFragment.class.getName()
- + KEY_SHOW_SYSTEM_PREFS;
-
- private static final String KEY_SESSION_ID = "_session_id";
- private static final String SESSION_ID_KEY = PermissionDetailsFragment.class.getName()
- + KEY_SESSION_ID;
-
- private static final int MENU_SHOW_7_DAYS_DATA = Menu.FIRST + 4;
- private static final int MENU_SHOW_24_HOURS_DATA = Menu.FIRST + 5;
-
- private @Nullable String mFilterGroup;
- private int mFilterTimeIndex;
- private @Nullable List<AppPermissionUsage> mAppPermissionUsages = new ArrayList<>();
- private @NonNull PermissionUsages mPermissionUsages;
- private boolean mFinishedInitialLoad;
-
- private boolean mShowSystem;
- private boolean mHasSystemApps;
- private boolean mShow7Days;
-
- private MenuItem mShowSystemMenu;
- private MenuItem mHideSystemMenu;
- private MenuItem mShow7DaysDataMenu;
- private MenuItem mShow24HoursDataMenu;
- private @NonNull RoleManager mRoleManager;
-
- private PermissionUsageDetailsViewModel mViewModel;
-
- private long mSessionId;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- mFinishedInitialLoad = false;
- mFilterTimeIndex = FILTER_7_DAYS;
-
- if (savedInstanceState != null) {
- mShowSystem = savedInstanceState.getBoolean(SHOW_SYSTEM_KEY);
- mSessionId = savedInstanceState.getLong(SESSION_ID_KEY);
- } else {
- mShowSystem = getArguments().getBoolean(
- ManagePermissionsActivity.EXTRA_SHOW_SYSTEM, false);
- mShow7Days = is7DayToggleEnabled() && getArguments().getBoolean(
- ManagePermissionsActivity.EXTRA_SHOW_7_DAYS, false);
- mSessionId = getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID);
- }
-
- if (mFilterGroup == null) {
- mFilterGroup = getArguments().getString(Intent.EXTRA_PERMISSION_GROUP_NAME);
- }
-
- setHasOptionsMenu(true);
- ActionBar ab = getActivity().getActionBar();
- if (ab != null) {
- ab.setDisplayHomeAsUpEnabled(true);
- }
-
- Context context = getPreferenceManager().getContext();
-
- mPermissionUsages = new PermissionUsages(context);
- mRoleManager = Utils.getSystemServiceSafe(context, RoleManager.class);
-
- PermissionUsageDetailsViewModelFactory factory = new PermissionUsageDetailsViewModelFactory(
- PermissionControllerApplication.get(), mRoleManager, mFilterGroup, mSessionId);
- mViewModel = new ViewModelProvider(this, factory).get(
- PermissionUsageDetailsViewModel.class);
-
- reloadData();
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- ViewGroup rootView = (ViewGroup) super.onCreateView(inflater, container,
- savedInstanceState);
-
- PermissionDetailsWrapperFragment parentFragment = (PermissionDetailsWrapperFragment)
- requireParentFragment();
- CoordinatorLayout coordinatorLayout = parentFragment.getCoordinatorLayout();
- inflater.inflate(R.layout.permission_details_extended_fab, coordinatorLayout);
- ExtendedFloatingActionButton extendedFab = coordinatorLayout.requireViewById(
- R.id.extended_fab);
- // Load the background tint color from the application theme
- // rather than the Material Design theme
- Activity activity = getActivity();
- ColorStateList backgroundColor = activity.getColorStateList(
- android.R.color.system_accent3_100);
- extendedFab.setBackgroundTintList(backgroundColor);
- extendedFab.setText(R.string.manage_permission);
- boolean isUiModeNight = (activity.getResources().getConfiguration().uiMode
- & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
- int textColorAttr = isUiModeNight ? android.R.attr.textColorPrimaryInverse
- : android.R.attr.textColorPrimary;
- TypedArray typedArray = activity.obtainStyledAttributes(new int[] { textColorAttr });
- ColorStateList textColor = typedArray.getColorStateList(0);
- typedArray.recycle();
- extendedFab.setTextColor(textColor);
- extendedFab.setIcon(activity.getDrawable(R.drawable.ic_settings_outline));
- extendedFab.setVisibility(View.VISIBLE);
- extendedFab.setOnClickListener(view -> {
- Intent intent = new Intent(Intent.ACTION_MANAGE_PERMISSION_APPS)
- .putExtra(Intent.EXTRA_PERMISSION_NAME, mFilterGroup);
- startActivity(intent);
- });
- RecyclerView recyclerView = getListView();
- int bottomPadding = getResources()
- .getDimensionPixelSize(R.dimen.privhub_details_recycler_view_bottom_padding);
- recyclerView.setPadding(0, 0, 0, bottomPadding);
- recyclerView.setClipToPadding(false);
- recyclerView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);
-
- return rootView;
- }
-
- @Override
- public void onStart() {
- super.onStart();
- CharSequence title = getString(R.string.permission_history_title);
- if (mFilterGroup != null) {
- title = getResources().getString(R.string.permission_group_usage_title,
- KotlinUtils.INSTANCE.getPermGroupLabel(getActivity(), mFilterGroup));
- }
- getActivity().setTitle(title);
- }
-
- @Override
- public void onPermissionUsagesChanged() {
- if (mPermissionUsages.getUsages().isEmpty()) {
- return;
- }
- mAppPermissionUsages = new ArrayList<>(mPermissionUsages.getUsages());
-
- // Ensure the group name is valid.
- if (mViewModel.getGroup(mFilterGroup, mAppPermissionUsages) == null) {
- mFilterGroup = null;
- }
-
- updateUI();
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putBoolean(SHOW_SYSTEM_KEY, mShowSystem);
- outState.putLong(SESSION_ID_KEY, mSessionId);
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- mShowSystemMenu = menu.add(Menu.NONE, MENU_SHOW_SYSTEM, Menu.NONE,
- R.string.menu_show_system);
- mHideSystemMenu = menu.add(Menu.NONE, MENU_HIDE_SYSTEM, Menu.NONE,
- R.string.menu_hide_system);
- if (is7DayToggleEnabled()) {
- mShow7DaysDataMenu = menu.add(Menu.NONE, MENU_SHOW_7_DAYS_DATA, Menu.NONE,
- R.string.menu_show_7_days_data);
- mShow24HoursDataMenu = menu.add(Menu.NONE, MENU_SHOW_24_HOURS_DATA, Menu.NONE,
- R.string.menu_show_24_hours_data);
- }
-
- updateMenu();
- }
-
- private void updateMenu() {
- if (mHasSystemApps) {
- mShowSystemMenu.setVisible(!mShowSystem);
- mShowSystemMenu.setEnabled(true);
-
- mHideSystemMenu.setVisible(mShowSystem);
- mHideSystemMenu.setEnabled(true);
- } else {
- mShowSystemMenu.setVisible(true);
- mShowSystemMenu.setEnabled(false);
-
- mHideSystemMenu.setVisible(false);
- mHideSystemMenu.setEnabled(false);
- }
-
- if (mShow7DaysDataMenu != null) {
- mShow7DaysDataMenu.setVisible(!mShow7Days);
- }
-
- if (mShow24HoursDataMenu != null) {
- mShow24HoursDataMenu.setVisible(mShow7Days);
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- int itemId = item.getItemId();
- switch (itemId) {
- case android.R.id.home:
- getActivity().finishAfterTransition();
- return true;
- case MENU_SHOW_SYSTEM:
- case MENU_HIDE_SYSTEM:
- mShowSystem = itemId == MENU_SHOW_SYSTEM;
- // We already loaded all data, so don't reload
- updateUI();
- updateMenu();
- break;
- case MENU_SHOW_7_DAYS_DATA:
- case MENU_SHOW_24_HOURS_DATA:
- mShow7Days = is7DayToggleEnabled() && itemId == MENU_SHOW_7_DAYS_DATA;
- updateUI();
- updateMenu();
- break;
- }
-
- return super.onOptionsItemSelected(item);
- }
-
- private void updateUI() {
- if (mAppPermissionUsages.isEmpty() || getActivity() == null) {
- return;
- }
- Context context = getActivity();
- PreferenceScreen screen = getPreferenceScreen();
- if (screen == null) {
- screen = getPreferenceManager().createPreferenceScreen(context);
- setPreferenceScreen(screen);
- }
- screen.removeAll();
-
- Set<String> exemptedPackages = Utils.getExemptedPackages(mRoleManager);
-
- Preference subtitlePreference = new Preference(context);
-
- int usageSubtitle = mShow7Days
- ? R.string.permission_group_usage_subtitle_7d
- : R.string.permission_group_usage_subtitle_24h;
- subtitlePreference.setSummary(
- getResources().getString(usageSubtitle,
- KotlinUtils.INSTANCE.getPermGroupLabel(getActivity(), mFilterGroup)));
- subtitlePreference.setSelectable(false);
- screen.addPreference(subtitlePreference);
-
- AtomicBoolean seenSystemApp = new AtomicBoolean(false);
-
- ArrayList<PermissionApps.PermissionApp> permApps = new ArrayList<>();
- List<PermissionUsageDetailsViewModel.AppPermissionUsageEntry> usages =
- mViewModel.parseUsages(mAppPermissionUsages, exemptedPackages, permApps,
- seenSystemApp, mShowSystem, mShow7Days);
-
- if (mHasSystemApps != seenSystemApp.get()) {
- mHasSystemApps = seenSystemApp.get();
- getActivity().invalidateOptionsMenu();
- }
-
- // Make these variables effectively final so that
- // we can use these captured variables in the below lambda expression
- PreferenceFactory preferenceFactory = new PreferenceFactory(requireActivity());
- AtomicReference<PreferenceCategory> category = new AtomicReference<>(
- preferenceFactory.createDayCategoryPreference());
- screen.addPreference(category.get());
- PreferenceScreen finalScreen = screen;
-
- new PermissionApps.AppDataLoader(context, () -> {
- if (getActivity() == null) {
- // Fragment has no Activity, return.
- return;
- }
- mViewModel.renderTimelinePreferences(usages, category, finalScreen, preferenceFactory);
-
- setLoading(false, true);
- mFinishedInitialLoad = true;
- setProgressBarVisible(false);
- mPermissionUsages.stopLoader(getActivity().getLoaderManager());
-
- }).execute(permApps.toArray(new PermissionApps.PermissionApp[permApps.size()]));
- }
-
- private static class PreferenceFactory implements
- PermissionUsageDetailsViewModel.HistoryPreferenceFactory {
-
- private Context mContext;
-
- PreferenceFactory(Context context) {
- mContext = context;
- }
-
- @Override
- public PreferenceCategory createDayCategoryPreference() {
- PreferenceCategory category = new PreferenceCategory(mContext);
- // Do not reserve icon space, so that the text moves all the way left.
- category.setIconSpaceReserved(false);
- return category;
- }
-
- @Override
- public Preference createPermissionHistoryPreference(
- PermissionUsageDetailsViewModel.HistoryPreferenceData historyPreferenceData) {
- return new PermissionHistoryPreference(mContext,
- historyPreferenceData.getUserHandle(),
- historyPreferenceData.getPkgName(),
- historyPreferenceData.getAppIcon(),
- historyPreferenceData.getPreferenceTitle(),
- historyPreferenceData.getPermissionGroup(),
- historyPreferenceData.getAccessTime(),
- historyPreferenceData.getSummaryText(),
- historyPreferenceData.getShowingAttribution(),
- historyPreferenceData.getAccessTimeList(),
- historyPreferenceData.getAttributionTags(),
- historyPreferenceData.isLastUsage(),
- historyPreferenceData.getSessionId()
- );
- }
- }
-
- private void reloadData() {
- mViewModel.loadPermissionUsages(getActivity().getLoaderManager(),
- mPermissionUsages, this, mFilterTimeIndex);
- if (mFinishedInitialLoad) {
- setProgressBarVisible(true);
- }
- }
-}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionDetailsWrapperFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionDetailsWrapperFragment.java
index 5d7e5c9ee..a8315fd03 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionDetailsWrapperFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionDetailsWrapperFragment.java
@@ -38,7 +38,7 @@ public class PermissionDetailsWrapperFragment extends PermissionsCollapsingToolb
@NonNull
@Override
public PreferenceFragmentCompat createPreferenceFragment() {
- return new PermissionDetailsFragment();
+ return new PermissionUsageDetailsFragment();
}
/**
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 5128f8145..bcca75fcc 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
@@ -21,13 +21,13 @@ import static com.android.permissioncontroller.PermissionControllerStatsLog.PERM
import static com.android.permissioncontroller.PermissionControllerStatsLog.write;
import android.content.ActivityNotFoundException;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
+import android.text.format.DateFormat;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -42,12 +42,12 @@ import androidx.annotation.Nullable;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
-import com.android.modules.utils.build.SdkLevel;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.compat.IntentCompat;
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel;
+import com.android.permissioncontroller.permission.utils.Utils;
import java.util.ArrayList;
-import java.util.List;
import java.util.Objects;
/**
@@ -55,21 +55,21 @@ import java.util.Objects;
*/
public class PermissionHistoryPreference extends Preference {
- private static final String LOG_TAG = "PermissionHistoryPreference";
+ private static final String LOG_TAG = "PermissionHistoryPref";
private final Context mContext;
private final UserHandle mUserHandle;
private final String mPackageName;
private final String mPermissionGroup;
- private final String mAccessTime;
+ private final long mAccessStartTime;
+ private final long mAccessEndTime;
private final Drawable mAppIcon;
private final String mTitle;
- private final List<Long> mAccessTimeList;
private final ArrayList<String> mAttributionTags;
private final boolean mIsLastUsage;
private final Intent mIntent;
private final boolean mShowingAttribution;
- private final PackageManager mPackageManager;
+ private final PackageManager mUserPackageManager;
private final long mSessionId;
@@ -79,25 +79,27 @@ public class PermissionHistoryPreference extends Preference {
@NonNull UserHandle userHandle, @NonNull String pkgName,
@NonNull Drawable appIcon,
@NonNull String preferenceTitle,
- @NonNull String permissionGroup, @NonNull String accessTime,
+ @NonNull String permissionGroup,
+ @NonNull long accessStartTime,
+ @NonNull long accessEndTime,
@Nullable CharSequence summaryText, boolean showingAttribution,
- @NonNull List<Long> accessTimeList,
@NonNull ArrayList<String> attributionTags, boolean isLastUsage, long sessionId) {
super(context);
mContext = context;
+ Context userContext = Utils.getUserContext(context, userHandle);
+ mUserPackageManager = userContext.getPackageManager();
mUserHandle = userHandle;
mPackageName = pkgName;
mPermissionGroup = permissionGroup;
- mAccessTime = accessTime;
+ mAccessStartTime = accessStartTime;
+ mAccessEndTime = accessEndTime;
mAppIcon = appIcon;
mTitle = preferenceTitle;
mWidgetIcon = null;
- mAccessTimeList = accessTimeList;
mAttributionTags = attributionTags;
mIsLastUsage = isLastUsage;
mSessionId = sessionId;
mShowingAttribution = showingAttribution;
- mPackageManager = context.getPackageManager();
setTitle(mTitle);
if (summaryText != null) {
@@ -133,30 +135,37 @@ public class PermissionHistoryPreference extends Preference {
widgetFrameParent.setGravity(Gravity.TOP);
TextView permissionHistoryTime = widget.findViewById(R.id.permission_history_time);
- permissionHistoryTime.setText(mAccessTime);
+ permissionHistoryTime.setText(DateFormat.getTimeFormat(mContext).format(mAccessEndTime));
ImageView permissionIcon = widget.findViewById(R.id.permission_history_icon);
permissionIcon.setImageDrawable(mAppIcon);
ImageView widgetView = widgetFrame.findViewById(R.id.icon);
- setInfoIcon(widgetView);
+ setInfoIcon(holder, widgetView);
View dashLine = widget.findViewById(R.id.permission_history_dash_line);
dashLine.setVisibility(mIsLastUsage ? View.GONE : View.VISIBLE);
- Intent intent = getManagePermissionUsageIntent();
- if (intent == null) {
- intent = getDefaultManageAppPermissionsIntent();
- }
+ // This Intent should ideally be part of the constructor, passed in from the ViewModel.
+ // It's temporarily created via a static method due to ongoing ViewModel refactoring.
+ Intent intent =
+ PermissionUsageDetailsViewModel.Companion.createHistoryPreferenceClickIntent(
+ mContext,
+ mUserHandle,
+ mPackageName,
+ mPermissionGroup,
+ mAccessStartTime,
+ mAccessEndTime,
+ mShowingAttribution,
+ mAttributionTags);
- Intent finalIntent = intent;
setOnPreferenceClickListener((preference) -> {
- mContext.startActivity(finalIntent);
+ mContext.startActivityAsUser(intent, mUserHandle);
return true;
});
}
- private void setInfoIcon(ImageView widgetView) {
+ private void setInfoIcon(@NonNull PreferenceViewHolder holder, ImageView widgetView) {
if (mIntent != null) {
widgetView.setImageDrawable(mWidgetIcon);
widgetView.setOnClickListener(v -> {
@@ -166,56 +175,17 @@ public class PermissionHistoryPreference extends Preference {
mPackageName,
PERMISSION_DETAILS_INTERACTION__ACTION__INFO_ICON_CLICKED);
try {
- mContext.startActivity(mIntent);
+ mContext.startActivityAsUser(mIntent, mUserHandle);
} catch (ActivityNotFoundException e) {
Log.e(LOG_TAG, "No activity found for viewing permission usage.");
}
});
+ View preferenceRootView = holder.itemView;
+ preferenceRootView.setPaddingRelative(preferenceRootView.getPaddingStart(),
+ preferenceRootView.getPaddingTop(), 0, preferenceRootView.getPaddingBottom());
}
}
- private Intent getDefaultManageAppPermissionsIntent() {
- Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS);
- intent.putExtra(Intent.EXTRA_USER, mUserHandle);
- intent.putExtra(Intent.EXTRA_PACKAGE_NAME, mPackageName);
-
- return intent;
- }
-
- /**
- * Get a {@link Intent#ACTION_MANAGE_PERMISSION_USAGE} intent, or null if the intent
- * can't be handled.
- *
- * Suppressing the NewApi warning since we already have a isAtLeastT() check.
- */
- @Nullable
- @SuppressWarnings("NewApi")
- private Intent getManagePermissionUsageIntent() {
- if (!mShowingAttribution || !SdkLevel.isAtLeastT() || mPackageName == null) {
- return null;
- }
-
- Intent intent = new Intent(Intent.ACTION_MANAGE_PERMISSION_USAGE);
- intent.setPackage(mPackageName);
- intent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, mPermissionGroup);
- intent.putExtra(Intent.EXTRA_ATTRIBUTION_TAGS, mAttributionTags.toArray(new String[0]));
- intent.putExtra(Intent.EXTRA_START_TIME, mAccessTimeList.get(mAccessTimeList.size() - 1));
- intent.putExtra(Intent.EXTRA_END_TIME, mAccessTimeList.get(0));
- intent.putExtra(IntentCompat.EXTRA_SHOWING_ATTRIBUTION, mShowingAttribution);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- ResolveInfo resolveInfo = mPackageManager.resolveActivity(intent,
- PackageManager.ResolveInfoFlags.of(0));
- if (resolveInfo == null || resolveInfo.activityInfo == null || !Objects.equals(
- resolveInfo.activityInfo.permission,
- android.Manifest.permission.START_VIEW_PERMISSION_USAGE)) {
- return null;
- }
- intent.setComponent(new ComponentName(mPackageName, resolveInfo.activityInfo.name));
-
- return intent;
- }
-
/**
* Get a {@link Intent#ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD} intent, or null if the intent
* can't be handled.
@@ -229,12 +199,12 @@ public class PermissionHistoryPreference extends Preference {
viewUsageIntent.putExtra(Intent.EXTRA_ATTRIBUTION_TAGS,
mAttributionTags.toArray(new String[0]));
viewUsageIntent.putExtra(Intent.EXTRA_START_TIME,
- mAccessTimeList.get(mAccessTimeList.size() - 1));
- viewUsageIntent.putExtra(Intent.EXTRA_END_TIME, mAccessTimeList.get(0));
+ mAccessStartTime);
+ viewUsageIntent.putExtra(Intent.EXTRA_END_TIME, mAccessEndTime);
viewUsageIntent.putExtra(IntentCompat.EXTRA_SHOWING_ATTRIBUTION, showingAttribution);
viewUsageIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- ResolveInfo resolveInfo = mPackageManager.resolveActivity(viewUsageIntent,
+ ResolveInfo resolveInfo = mUserPackageManager.resolveActivity(viewUsageIntent,
PackageManager.MATCH_INSTANT);
if (resolveInfo != null && resolveInfo.activityInfo != null && Objects.equals(
resolveInfo.activityInfo.permission,
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageV2ControlPreference.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageControlPreference.java
index 7796ce623..3336d0c0f 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageV2ControlPreference.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageControlPreference.java
@@ -29,21 +29,24 @@ import androidx.preference.PreferenceViewHolder;
import com.android.modules.utils.build.SdkLevel;
import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageControlPreferenceUtils;
-/**
- * Preference for the top level privacy hub page
- */
+/** Preference for the top level privacy hub page */
@RequiresApi(Build.VERSION_CODES.S)
-public class PermissionUsageV2ControlPreference extends Preference {
+public class PermissionUsageControlPreference extends Preference {
private final Context mContext;
- public PermissionUsageV2ControlPreference(@NonNull Context context, @NonNull String groupName,
- int count, boolean showSystem, long sessionId, boolean show7Days) {
+ public PermissionUsageControlPreference(
+ @NonNull Context context,
+ @NonNull String groupName,
+ int count,
+ boolean showSystem,
+ long sessionId,
+ boolean show7Days) {
super(context);
mContext = context;
- PermissionUsageControlPreferenceUtils.initPreference(this, mContext, groupName,
- count, showSystem, sessionId, show7Days);
+ PermissionUsageControlPreferenceUtils.initPreference(
+ this, mContext, groupName, count, showSystem, sessionId, show7Days);
}
@Override
@@ -52,8 +55,9 @@ public class PermissionUsageV2ControlPreference extends Preference {
if (SdkLevel.isAtLeastS()) {
TextView titleView = (TextView) view.findViewById(android.R.id.title);
- TypedArray ta = mContext.obtainStyledAttributes(
- new int[]{android.R.attr.textAppearanceListItem});
+ TypedArray ta =
+ mContext.obtainStyledAttributes(
+ new int[] {android.R.attr.textAppearanceListItem});
int resId = ta.getResourceId(0, 0);
ta.recycle();
titleView.setTextAppearance(resId);
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
new file mode 100644
index 000000000..15ee31a54
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageDetailsFragment.java
@@ -0,0 +1,433 @@
+/*
+ * 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.permissioncontroller.permission.ui.handheld.v31;
+
+import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
+import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.os.Bundle;
+import android.text.format.DateFormat;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceScreen;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.permissioncontroller.PermissionControllerApplication;
+import com.android.permissioncontroller.R;
+import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity;
+import com.android.permissioncontroller.permission.ui.handheld.SettingsWithLargeHeader;
+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.model.v31.PermissionUsageDetailsViewModel.PermissionUsageDetailsUiInfo;
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.PermissionUsageDetailsViewModelFactory;
+import com.android.permissioncontroller.permission.utils.KotlinUtils;
+
+import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
+
+import java.time.Clock;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoUnit;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+/** The permission details page showing the history/timeline of a permission */
+@RequiresApi(Build.VERSION_CODES.S)
+public class PermissionUsageDetailsFragment extends SettingsWithLargeHeader {
+ private static final String KEY_SESSION_ID = "_session_id";
+ private static final String SESSION_ID_KEY =
+ PermissionUsageDetailsFragment.class.getName() + KEY_SESSION_ID;
+ private static final String TAG = PermissionUsageDetailsFragment.class.getName();
+
+ private static final int MENU_SHOW_7_DAYS_DATA = Menu.FIRST + 4;
+ private static final int MENU_SHOW_24_HOURS_DATA = Menu.FIRST + 5;
+ private @Nullable String mPermissionGroup;
+ private int mUsageSubtitle;
+ private boolean mHasSystemApps;
+
+ private MenuItem mShowSystemMenu;
+ private MenuItem mHideSystemMenu;
+ private MenuItem mShow7DaysDataMenu;
+ private MenuItem mShow24HoursDataMenu;
+
+ private PermissionUsageDetailsViewModel mViewModel;
+
+ private long mSessionId;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mPermissionGroup = getArguments().getString(Intent.EXTRA_PERMISSION_GROUP_NAME);
+
+ if (mPermissionGroup == null) {
+ Log.e(TAG, "No permission group was provided for PermissionDetailsFragment");
+ return;
+ }
+
+ PermissionUsageDetailsViewModelFactory factory =
+ new PermissionUsageDetailsViewModelFactory(
+ PermissionControllerApplication.get(), this, mPermissionGroup);
+ mViewModel =
+ new ViewModelProvider(this, factory).get(PermissionUsageDetailsViewModel.class);
+
+ if (savedInstanceState != null) {
+ mSessionId = savedInstanceState.getLong(SESSION_ID_KEY);
+ } else {
+ mSessionId = getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID);
+ }
+
+ mViewModel.updateShowSystemAppsToggle(
+ getArguments().getBoolean(ManagePermissionsActivity.EXTRA_SHOW_SYSTEM, false));
+ mViewModel.updateShow7DaysToggle(
+ KotlinUtils.INSTANCE.is7DayToggleEnabled()
+ && getArguments()
+ .getBoolean(ManagePermissionsActivity.EXTRA_SHOW_7_DAYS, false));
+
+ setHasOptionsMenu(true);
+ ActionBar ab = getActivity().getActionBar();
+ if (ab != null) {
+ ab.setDisplayHomeAsUpEnabled(true);
+ }
+ setLoading(true, false);
+
+ mViewModel.getPermissionUsagesDetailsInfoUiLiveData().observe(this, this::updateAllUI);
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ ViewGroup rootView =
+ (ViewGroup) super.onCreateView(inflater, container, savedInstanceState);
+
+ PermissionDetailsWrapperFragment parentFragment =
+ (PermissionDetailsWrapperFragment) requireParentFragment();
+ CoordinatorLayout coordinatorLayout = parentFragment.getCoordinatorLayout();
+ inflater.inflate(R.layout.permission_details_extended_fab, coordinatorLayout);
+ ExtendedFloatingActionButton extendedFab =
+ coordinatorLayout.requireViewById(R.id.extended_fab);
+ // Load the background tint color from the application theme
+ // rather than the Material Design theme
+ Activity activity = getActivity();
+ ColorStateList backgroundColor =
+ activity.getColorStateList(android.R.color.system_accent3_100);
+ extendedFab.setBackgroundTintList(backgroundColor);
+ extendedFab.setText(R.string.manage_permission);
+ boolean isUiModeNight =
+ (activity.getResources().getConfiguration().uiMode
+ & Configuration.UI_MODE_NIGHT_MASK)
+ == Configuration.UI_MODE_NIGHT_YES;
+ int textColorAttr =
+ isUiModeNight
+ ? android.R.attr.textColorPrimaryInverse
+ : android.R.attr.textColorPrimary;
+ TypedArray typedArray = activity.obtainStyledAttributes(new int[] {textColorAttr});
+ ColorStateList textColor = typedArray.getColorStateList(0);
+ typedArray.recycle();
+ extendedFab.setTextColor(textColor);
+ extendedFab.setIcon(activity.getDrawable(R.drawable.ic_settings_outline));
+ extendedFab.setVisibility(View.VISIBLE);
+ extendedFab.setOnClickListener(
+ view -> {
+ Intent intent =
+ new Intent(Intent.ACTION_MANAGE_PERMISSION_APPS)
+ .putExtra(Intent.EXTRA_PERMISSION_NAME, mPermissionGroup);
+ startActivity(intent);
+ });
+ RecyclerView recyclerView = getListView();
+ int bottomPadding =
+ getResources()
+ .getDimensionPixelSize(
+ R.dimen.privhub_details_recycler_view_bottom_padding);
+ recyclerView.setPadding(0, 0, 0, bottomPadding);
+ recyclerView.setClipToPadding(false);
+ recyclerView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);
+
+ return rootView;
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ CharSequence title = getString(R.string.permission_history_title);
+ if (mPermissionGroup != null) {
+ title =
+ getResources()
+ .getString(
+ R.string.permission_group_usage_title,
+ KotlinUtils.INSTANCE.getPermGroupLabel(
+ getActivity(), mPermissionGroup));
+ }
+ getActivity().setTitle(title);
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putLong(SESSION_ID_KEY, mSessionId);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ mShowSystemMenu =
+ menu.add(Menu.NONE, MENU_SHOW_SYSTEM, Menu.NONE, R.string.menu_show_system);
+ mHideSystemMenu =
+ menu.add(Menu.NONE, MENU_HIDE_SYSTEM, Menu.NONE, R.string.menu_hide_system);
+ boolean showSystem = false;
+ if (mViewModel.getShowSystemLiveData().getValue() != null) {
+ showSystem = mViewModel.getShowSystemLiveData().getValue();
+ }
+ updateShowSystemToggle(showSystem);
+
+ if (KotlinUtils.INSTANCE.is7DayToggleEnabled()) {
+ mShow7DaysDataMenu =
+ menu.add(
+ Menu.NONE,
+ MENU_SHOW_7_DAYS_DATA,
+ Menu.NONE,
+ R.string.menu_show_7_days_data);
+ mShow24HoursDataMenu =
+ menu.add(
+ Menu.NONE,
+ MENU_SHOW_24_HOURS_DATA,
+ Menu.NONE,
+ R.string.menu_show_24_hours_data);
+ boolean show7Days = false;
+ if (mViewModel.getShow7DaysLiveData().getValue() != null) {
+ show7Days = mViewModel.getShow7DaysLiveData().getValue();
+ }
+ updateShow7DaysToggle(show7Days);
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int itemId = item.getItemId();
+ switch (itemId) {
+ case android.R.id.home:
+ getActivity().finishAfterTransition();
+ return true;
+ case MENU_SHOW_SYSTEM:
+ mViewModel.updateShowSystemAppsToggle(true);
+ break;
+ case MENU_HIDE_SYSTEM:
+ mViewModel.updateShowSystemAppsToggle(false);
+ break;
+ case MENU_SHOW_7_DAYS_DATA:
+ mViewModel.updateShow7DaysToggle(KotlinUtils.INSTANCE.is7DayToggleEnabled());
+ break;
+ case MENU_SHOW_24_HOURS_DATA:
+ mViewModel.updateShow7DaysToggle(false);
+ break;
+ }
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ /** Updates page content and menu items. */
+ private void updateAllUI(PermissionUsageDetailsUiInfo uiData) {
+ if (getActivity() == null) {
+ return;
+ }
+ Context context = getActivity();
+ PreferenceScreen screen = getPreferenceScreen();
+ if (screen == null) {
+ screen = getPreferenceManager().createPreferenceScreen(context);
+ setPreferenceScreen(screen);
+ }
+ screen.removeAll();
+ boolean show7Days =
+ mViewModel.getShow7DaysLiveData().getValue() != null
+ ? mViewModel.getShow7DaysLiveData().getValue()
+ : false;
+
+ Preference subtitlePreference = new Preference(context);
+ updateShow7DaysToggle(show7Days);
+ mUsageSubtitle =
+ show7Days
+ ? R.string.permission_group_usage_subtitle_7d
+ : R.string.permission_group_usage_subtitle_24h;
+
+ subtitlePreference.setSummary(
+ getResources()
+ .getString(
+ mUsageSubtitle,
+ KotlinUtils.INSTANCE.getPermGroupLabel(
+ getActivity(), mPermissionGroup)));
+ subtitlePreference.setSelectable(false);
+ screen.addPreference(subtitlePreference);
+
+ boolean containsSystemAppAccesses = uiData.getContainsSystemAppAccesses();
+ if (mHasSystemApps != containsSystemAppAccesses) {
+ mHasSystemApps = containsSystemAppAccesses;
+ }
+ boolean showSystem =
+ mViewModel.getShowSystemLiveData().getValue() != null
+ ? mViewModel.getShowSystemLiveData().getValue()
+ : false;
+ updateShowSystemToggle(showSystem);
+
+ // Make these variables effectively final so that
+ // we can use these captured variables in the below lambda expression
+ AtomicReference<PreferenceCategory> category =
+ new AtomicReference<>(createDayCategoryPreference());
+ screen.addPreference(category.get());
+ PreferenceScreen finalScreen = screen;
+
+ if (getActivity() == null) {
+ // Fragment has no Activity, return.
+ return;
+ }
+ renderHistoryPreferences(uiData.getAppPermissionAccessUiInfoList(), category, finalScreen);
+
+ setLoading(false, true);
+ setProgressBarVisible(false);
+ }
+
+ /** Render the provided appPermissionAccessUiInfoList into the [preferenceScreen] UI. */
+ private void renderHistoryPreferences(
+ List<AppPermissionAccessUiInfo> appPermissionAccessUiInfoList,
+ AtomicReference<PreferenceCategory> category,
+ PreferenceScreen preferenceScreen) {
+ Context context = getContext();
+ long previousDateMs = 0L;
+ long midnightToday =
+ ZonedDateTime.now(ZoneId.systemDefault())
+ .truncatedTo(ChronoUnit.DAYS)
+ .toEpochSecond()
+ * 1000L;
+ long midnightYesterday =
+ ZonedDateTime.now(ZoneId.systemDefault())
+ .minusDays(1)
+ .truncatedTo(ChronoUnit.DAYS)
+ .toEpochSecond()
+ * 1000L;
+
+ for (int i = 0; i < appPermissionAccessUiInfoList.size(); i++) {
+ AppPermissionAccessUiInfo appPermissionAccessUiInfo =
+ appPermissionAccessUiInfoList.get(i);
+ long accessEndTime = appPermissionAccessUiInfo.getAccessEndTime();
+ long currentDateMs =
+ ZonedDateTime.ofInstant(
+ Instant.ofEpochMilli(accessEndTime),
+ Clock.system(ZoneId.systemDefault()).getZone())
+ .truncatedTo(ChronoUnit.DAYS)
+ .toEpochSecond()
+ * 1000L;
+ if (currentDateMs != previousDateMs) {
+ if (previousDateMs != 0L) {
+ category.set(createDayCategoryPreference());
+ preferenceScreen.addPreference(category.get());
+ }
+ if (accessEndTime > midnightToday) {
+ category.get().setTitle(R.string.permission_history_category_today);
+ } else if (accessEndTime > midnightYesterday) {
+ category.get().setTitle(R.string.permission_history_category_yesterday);
+ } else {
+ category.get()
+ .setTitle(DateFormat.getDateFormat(context).format(currentDateMs));
+ }
+ previousDateMs = currentDateMs;
+ }
+
+ Preference permissionUsagePreference =
+ 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.getPermissionGroup(),
+ appPermissionAccessUiInfo.getAccessStartTime(),
+ appPermissionAccessUiInfo.getAccessEndTime(),
+ appPermissionAccessUiInfo.getSummaryText(),
+ appPermissionAccessUiInfo.getShowingAttribution(),
+ appPermissionAccessUiInfo.getAttributionTags(),
+ i == appPermissionAccessUiInfoList.size() - 1,
+ mSessionId);
+
+ category.get().addPreference(permissionUsagePreference);
+ }
+ }
+
+ private void updateShowSystemToggle(boolean showSystem) {
+ if (mHasSystemApps) {
+ if (mShowSystemMenu != null) {
+ mShowSystemMenu.setVisible(!showSystem);
+ mShowSystemMenu.setEnabled(true);
+ }
+
+ if (mHideSystemMenu != null) {
+ mHideSystemMenu.setVisible(showSystem);
+ mHideSystemMenu.setEnabled(true);
+ }
+ } else {
+ if (mShowSystemMenu != null) {
+ mShowSystemMenu.setVisible(true);
+ mShowSystemMenu.setEnabled(false);
+ }
+
+ if (mHideSystemMenu != null) {
+ mHideSystemMenu.setVisible(false);
+ mHideSystemMenu.setEnabled(false);
+ }
+ }
+ }
+
+ private void updateShow7DaysToggle(boolean show7Days) {
+ if (mShow7DaysDataMenu != null) {
+ mShow7DaysDataMenu.setVisible(!show7Days);
+ }
+
+ if (mShow24HoursDataMenu != null) {
+ mShow24HoursDataMenu.setVisible(show7Days);
+ }
+ }
+
+ private PreferenceCategory createDayCategoryPreference() {
+ PreferenceCategory category = new PreferenceCategory(getContext());
+ // Do not reserve icon space, so that the text moves all the way left.
+ category.setIconSpaceReserved(false);
+ return category;
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageFragment.java
new file mode 100644
index 000000000..e28387f5b
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageFragment.java
@@ -0,0 +1,448 @@
+/*
+ * 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.permissioncontroller.permission.ui.handheld.v31;
+
+import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
+import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_USAGE_FRAGMENT_INTERACTION;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__SEE_OTHER_PERMISSIONS_CLICKED;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__SHOW_SYSTEM_CLICKED;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.write;
+
+import android.Manifest;
+import android.app.ActionBar;
+import android.content.Context;
+import android.os.Build;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+
+import androidx.annotation.RequiresApi;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceGroupAdapter;
+import androidx.preference.PreferenceScreen;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.permissioncontroller.R;
+import com.android.permissioncontroller.permission.ui.handheld.SettingsWithLargeHeader;
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageViewModel;
+import com.android.permissioncontroller.permission.utils.KotlinUtils;
+import com.android.settingslib.HelpUtils;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+/** The main page for the privacy dashboard. */
+@RequiresApi(Build.VERSION_CODES.S)
+public class PermissionUsageFragment extends SettingsWithLargeHeader {
+
+ private static final Map<String, Integer> PERMISSION_GROUP_ORDER =
+ Map.of(
+ Manifest.permission_group.LOCATION, 0,
+ Manifest.permission_group.CAMERA, 1,
+ Manifest.permission_group.MICROPHONE, 2);
+ private static final int DEFAULT_ORDER = 3;
+
+ // Pie chart in this screen will be the first child.
+ // Hence we use PERMISSION_GROUP_ORDER + 1 here.
+ private static final int PERMISSION_USAGE_INITIAL_EXPANDED_CHILDREN_COUNT =
+ PERMISSION_GROUP_ORDER.size() + 1;
+ private static final int EXPAND_BUTTON_ORDER = 999;
+ /** Map to represent ordering for permission groups in the permissions usage UI. */
+ private static final String KEY_SESSION_ID = "_session_id";
+
+ private static final String SESSION_ID_KEY =
+ PermissionUsageFragment.class.getName() + KEY_SESSION_ID;
+
+ private static final int MENU_SHOW_7_DAYS_DATA = Menu.FIRST + 4;
+ private static final int MENU_SHOW_24_HOURS_DATA = Menu.FIRST + 5;
+
+ private PermissionUsageViewModel mViewModel;
+
+ private boolean mHasSystemApps;
+ private MenuItem mShowSystemMenu;
+ private MenuItem mHideSystemMenu;
+ private MenuItem mShow7DaysDataMenu;
+ private MenuItem mShow24HoursDataMenu;
+ private boolean mOtherExpanded;
+
+ private PermissionUsageGraphicPreference mGraphic;
+
+ /** Unique Id of a request */
+ private long mSessionId;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (savedInstanceState != null) {
+ mSessionId = savedInstanceState.getLong(SESSION_ID_KEY);
+ } else {
+ mSessionId = getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID);
+ }
+
+ PermissionUsageViewModel.PermissionUsageViewModelFactory factory =
+ new PermissionUsageViewModel.PermissionUsageViewModelFactory(
+ getActivity().getApplication(), this, new Bundle());
+ mViewModel = new ViewModelProvider(this, factory).get(PermissionUsageViewModel.class);
+
+ // Start out with 'other' permissions not expanded.
+ mOtherExpanded = false;
+
+ setHasOptionsMenu(true);
+ ActionBar ab = getActivity().getActionBar();
+ if (ab != null) {
+ ab.setDisplayHomeAsUpEnabled(true);
+ }
+ setLoading(true, false);
+
+ mViewModel.getPermissionUsagesUiLiveData().observe(this, this::updateAllUI);
+ }
+
+ @Override
+ public RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
+ PreferenceGroupAdapter adapter =
+ (PreferenceGroupAdapter) super.onCreateAdapter(preferenceScreen);
+
+ adapter.registerAdapterDataObserver(
+ new RecyclerView.AdapterDataObserver() {
+ @Override
+ public void onChanged() {
+ updatePreferenceScreenAdvancedTitleAndSummary(preferenceScreen, adapter);
+ }
+
+ @Override
+ public void onItemRangeInserted(int positionStart, int itemCount) {
+ onChanged();
+ }
+
+ @Override
+ public void onItemRangeRemoved(int positionStart, int itemCount) {
+ onChanged();
+ }
+
+ @Override
+ public void onItemRangeChanged(int positionStart, int itemCount) {
+ onChanged();
+ }
+
+ @Override
+ public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+ onChanged();
+ }
+ });
+
+ updatePreferenceScreenAdvancedTitleAndSummary(preferenceScreen, adapter);
+ return adapter;
+ }
+
+ private void updatePreferenceScreenAdvancedTitleAndSummary(
+ PreferenceScreen preferenceScreen, PreferenceGroupAdapter adapter) {
+ int count = adapter.getItemCount();
+ if (count == 0) {
+ return;
+ }
+
+ Preference preference = adapter.getItem(count - 1);
+
+ // This is a hacky way of getting the expand button preference for advanced info
+ if (preference.getOrder() == EXPAND_BUTTON_ORDER) {
+ mOtherExpanded = false;
+ preference.setTitle(R.string.perm_usage_adv_info_title);
+ preference.setSummary(preferenceScreen.getSummary());
+ preference.setLayoutResource(R.layout.expand_button_with_large_title);
+ if (mGraphic != null) {
+ mGraphic.setShowOtherCategory(false);
+ }
+ } else {
+ mOtherExpanded = true;
+ if (mGraphic != null) {
+ mGraphic.setShowOtherCategory(true);
+ }
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ getActivity().setTitle(R.string.permission_usage_title);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ mShowSystemMenu =
+ menu.add(Menu.NONE, MENU_SHOW_SYSTEM, Menu.NONE, R.string.menu_show_system);
+ mHideSystemMenu =
+ menu.add(Menu.NONE, MENU_HIDE_SYSTEM, Menu.NONE, R.string.menu_hide_system);
+ boolean showSystem =
+ mViewModel.getShowSystemAppsLiveData().getValue() != null
+ ? mViewModel.getShowSystemAppsLiveData().getValue()
+ : false;
+ updateShowSystemToggle(showSystem);
+
+ if (KotlinUtils.INSTANCE.is7DayToggleEnabled()) {
+ mShow7DaysDataMenu =
+ menu.add(
+ Menu.NONE,
+ MENU_SHOW_7_DAYS_DATA,
+ Menu.NONE,
+ R.string.menu_show_7_days_data);
+ mShow24HoursDataMenu =
+ menu.add(
+ Menu.NONE,
+ MENU_SHOW_24_HOURS_DATA,
+ Menu.NONE,
+ R.string.menu_show_24_hours_data);
+ boolean show7Days =
+ mViewModel.getShow7DaysLiveData().getValue() != null
+ ? mViewModel.getShow7DaysLiveData().getValue()
+ : false;
+ updateShow7DaysToggle(show7Days);
+ }
+
+ HelpUtils.prepareHelpMenuItem(
+ getActivity(), menu, R.string.help_permission_usage, getClass().getName());
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int itemId = item.getItemId();
+ switch (itemId) {
+ case android.R.id.home:
+ getActivity().finishAfterTransition();
+ return true;
+ case MENU_SHOW_SYSTEM:
+ write(
+ PERMISSION_USAGE_FRAGMENT_INTERACTION,
+ mSessionId,
+ PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__SHOW_SYSTEM_CLICKED);
+ mViewModel.updateShowSystem(true);
+ break;
+ case MENU_HIDE_SYSTEM:
+ mViewModel.updateShowSystem(false);
+ break;
+ case MENU_SHOW_7_DAYS_DATA:
+ mViewModel.updateShow7Days(KotlinUtils.INSTANCE.is7DayToggleEnabled());
+ break;
+ case MENU_SHOW_24_HOURS_DATA:
+ mViewModel.updateShow7Days(false);
+ break;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public int getEmptyViewString() {
+ return R.string.no_permission_usages;
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ if (outState != null) {
+ outState.putLong(SESSION_ID_KEY, mSessionId);
+ }
+ }
+
+ private void updateShowSystemToggle(boolean showSystem) {
+ if (mHasSystemApps) {
+ if (mShowSystemMenu != null) {
+ mShowSystemMenu.setVisible(!showSystem);
+ }
+ if (mHideSystemMenu != null) {
+ mHideSystemMenu.setVisible(showSystem);
+ }
+ } else {
+ if (mShowSystemMenu != null) {
+ mShowSystemMenu.setVisible(false);
+ }
+ if (mHideSystemMenu != null) {
+ mHideSystemMenu.setVisible(false);
+ }
+ }
+ }
+
+ private void updateShow7DaysToggle(boolean show7Days) {
+ if (mShow7DaysDataMenu != null) {
+ mShow7DaysDataMenu.setVisible(!show7Days);
+ }
+
+ if (mShow24HoursDataMenu != null) {
+ mShow24HoursDataMenu.setVisible(show7Days);
+ }
+ }
+
+ /** Updates page content and menu items. */
+ private void updateAllUI(
+ PermissionUsageViewModel.PermissionUsagesUiData permissionUsagesUiData) {
+ if (getActivity() == null) {
+ return;
+ }
+ Context context = getActivity();
+
+ PreferenceScreen screen = getPreferenceScreen();
+ if (screen == null) {
+ screen = getPreferenceManager().createPreferenceScreen(context);
+ setPreferenceScreen(screen);
+ }
+ screen.removeAll();
+
+ if (mOtherExpanded) {
+ screen.setInitialExpandedChildrenCount(Integer.MAX_VALUE);
+ } else {
+ screen.setInitialExpandedChildrenCount(
+ PERMISSION_USAGE_INITIAL_EXPANDED_CHILDREN_COUNT);
+ }
+ screen.setOnExpandButtonClickListener(() -> {
+ write(
+ PERMISSION_USAGE_FRAGMENT_INTERACTION,
+ mSessionId,
+ PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__SEE_OTHER_PERMISSIONS_CLICKED);
+ });
+ boolean containsSystemAppUsages = permissionUsagesUiData.getContainsSystemAppUsages();
+ Map<String, Integer> permissionGroupWithUsageCounts =
+ permissionUsagesUiData.getPermissionGroupsWithUsageCount();
+ List<Map.Entry<String, Integer>> permissionGroupWithUsageCountsEntries =
+ new ArrayList(permissionGroupWithUsageCounts.entrySet());
+
+ permissionGroupWithUsageCountsEntries.sort(Comparator.comparing(
+ (Map.Entry<String, Integer> permissionGroupWithUsageCount) ->
+ PERMISSION_GROUP_ORDER.getOrDefault(
+ permissionGroupWithUsageCount.getKey(),
+ DEFAULT_ORDER))
+ .thenComparing(
+ (Map.Entry<String, Integer> permissionGroupWithUsageCount) ->
+ KotlinUtils.INSTANCE
+ .getPermGroupLabel(
+ context,
+ permissionGroupWithUsageCount
+ .getKey())
+ .toString()));
+
+ if (mHasSystemApps != containsSystemAppUsages) {
+ mHasSystemApps = containsSystemAppUsages;
+ }
+
+ boolean show7Days =
+ mViewModel.getShow7DaysLiveData().getValue() != null
+ ? mViewModel.getShow7DaysLiveData().getValue()
+ : false;
+ updateShow7DaysToggle(show7Days);
+ boolean showSystem =
+ mViewModel.getShowSystemAppsLiveData().getValue() != null
+ ? mViewModel.getShowSystemAppsLiveData().getValue()
+ : false;
+ updateShowSystemToggle(showSystem);
+
+ mGraphic = new PermissionUsageGraphicPreference(context, show7Days);
+ screen.addPreference(mGraphic);
+ mGraphic.setUsages(permissionGroupWithUsageCounts);
+
+ // Add the preference header.
+ PreferenceCategory category = new PreferenceCategory(context);
+ screen.addPreference(category);
+ CharSequence advancedInfoSummary =
+ getAdvancedInfoSummaryString(context, permissionGroupWithUsageCountsEntries);
+ screen.setSummary(advancedInfoSummary);
+
+ addUIContent(context, permissionGroupWithUsageCountsEntries, category);
+ }
+
+ private CharSequence getAdvancedInfoSummaryString(
+ Context context, List<Map.Entry<String, Integer>> permissionGroupWithUsageCounts) {
+ int size = permissionGroupWithUsageCounts.size();
+ if (size <= PERMISSION_USAGE_INITIAL_EXPANDED_CHILDREN_COUNT - 1) {
+ return "";
+ }
+
+ // case for 1 extra item in the advanced info
+ if (size == PERMISSION_USAGE_INITIAL_EXPANDED_CHILDREN_COUNT) {
+ String permGroupName =
+ permissionGroupWithUsageCounts
+ .get(PERMISSION_USAGE_INITIAL_EXPANDED_CHILDREN_COUNT - 1)
+ .getKey();
+ return KotlinUtils.INSTANCE.getPermGroupLabel(context, permGroupName);
+ }
+
+ String permGroupName1 =
+ permissionGroupWithUsageCounts
+ .get(PERMISSION_USAGE_INITIAL_EXPANDED_CHILDREN_COUNT - 1)
+ .getKey();
+ String permGroupName2 =
+ permissionGroupWithUsageCounts
+ .get(PERMISSION_USAGE_INITIAL_EXPANDED_CHILDREN_COUNT)
+ .getKey();
+ CharSequence permGroupLabel1 =
+ KotlinUtils.INSTANCE.getPermGroupLabel(context, permGroupName1);
+ CharSequence permGroupLabel2 =
+ KotlinUtils.INSTANCE.getPermGroupLabel(context, permGroupName2);
+
+ // case for 2 extra items in the advanced info
+ if (size == PERMISSION_USAGE_INITIAL_EXPANDED_CHILDREN_COUNT + 1) {
+ return context.getResources()
+ .getString(
+ R.string.perm_usage_adv_info_summary_2_items,
+ permGroupLabel1,
+ permGroupLabel2);
+ }
+
+ // case for 3 or more extra items in the advanced info
+ int numExtraItems = size - PERMISSION_USAGE_INITIAL_EXPANDED_CHILDREN_COUNT - 1;
+ return context.getResources()
+ .getString(
+ R.string.perm_usage_adv_info_summary_more_items,
+ permGroupLabel1,
+ permGroupLabel2,
+ numExtraItems);
+ }
+
+ /** Add preferences for permission usages. */
+ private void addUIContent(
+ Context context,
+ List<Map.Entry<String, Integer>> permissionGroupWithUsageCounts,
+ PreferenceCategory category) {
+ boolean showSystem =
+ mViewModel.getShowSystemAppsLiveData().getValue() != null
+ ? mViewModel.getShowSystemAppsLiveData().getValue()
+ : false;
+ boolean show7Days =
+ mViewModel.getShow7DaysLiveData().getValue() != null
+ ? mViewModel.getShow7DaysLiveData().getValue()
+ : false;
+ for (int i = 0; i < permissionGroupWithUsageCounts.size(); i++) {
+ Map.Entry<String, Integer> permissionGroupWithUsageCount =
+ permissionGroupWithUsageCounts.get(i);
+ PermissionUsageControlPreference permissionUsagePreference =
+ new PermissionUsageControlPreference(
+ context,
+ permissionGroupWithUsageCount.getKey(),
+ permissionGroupWithUsageCount.getValue(),
+ showSystem,
+ mSessionId,
+ show7Days);
+ category.addPreference(permissionUsagePreference);
+ }
+
+ setLoading(false, true);
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageV2Fragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageV2Fragment.java
deleted file mode 100644
index 46f016455..000000000
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageV2Fragment.java
+++ /dev/null
@@ -1,429 +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.permissioncontroller.permission.ui.handheld.v31;
-
-import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
-import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
-import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_USAGE_FRAGMENT_INTERACTION;
-import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__SEE_OTHER_PERMISSIONS_CLICKED;
-import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__SHOW_SYSTEM_CLICKED;
-import static com.android.permissioncontroller.PermissionControllerStatsLog.write;
-import static com.android.permissioncontroller.permission.ui.handheld.v31.DashboardUtilsKt.is7DayToggleEnabled;
-
-import android.app.ActionBar;
-import android.app.Activity;
-import android.app.role.RoleManager;
-import android.content.Context;
-import android.os.Build;
-import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
-import androidx.lifecycle.ViewModelProvider;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceGroupAdapter;
-import androidx.preference.PreferenceScreen;
-import androidx.recyclerview.widget.RecyclerView;
-
-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.model.legacy.PermissionApps;
-import com.android.permissioncontroller.permission.ui.handheld.SettingsWithLargeHeader;
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageViewModel;
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageViewModelFactory;
-import com.android.permissioncontroller.permission.utils.KotlinUtils;
-import com.android.permissioncontroller.permission.utils.Utils;
-import com.android.settingslib.HelpUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import kotlin.Triple;
-
-/**
- * The main page for the privacy dashboard.
- */
-@RequiresApi(Build.VERSION_CODES.S)
-public class PermissionUsageV2Fragment extends SettingsWithLargeHeader implements
- PermissionUsages.PermissionsUsagesChangeCallback {
-
- // Pie chart in this screen will be the first child.
- // Hence we use PERMISSION_GROUP_ORDER + 1 here.
- private static final int PERMISSION_USAGE_INITIAL_EXPANDED_CHILDREN_COUNT =
- PermissionUsageViewModel.Companion.getPERMISSION_GROUP_ORDER().size() + 1;
- private static final int EXPAND_BUTTON_ORDER = 999;
-
- private static final String KEY_SESSION_ID = "_session_id";
- private static final String SESSION_ID_KEY = PermissionUsageV2Fragment.class.getName()
- + KEY_SESSION_ID;
-
- private static final int MENU_SHOW_7_DAYS_DATA = Menu.FIRST + 4;
- private static final int MENU_SHOW_24_HOURS_DATA = Menu.FIRST + 5;
- private static final int MENU_REFRESH = Menu.FIRST + 6;
-
- private @NonNull PermissionUsages mPermissionUsages;
- private @Nullable List<AppPermissionUsage> mAppPermissionUsages = new ArrayList<>();
-
- private PermissionUsageViewModel mViewModel;
-
- private boolean mShowSystem;
- private boolean mHasSystemApps;
- private MenuItem mShowSystemMenu;
- private MenuItem mHideSystemMenu;
- private boolean mShow7Days;
- private MenuItem mShow7DaysDataMenu;
- private MenuItem mShow24HoursDataMenu;
- private boolean mOtherExpanded;
-
- private boolean mFinishedInitialLoad;
-
- private @NonNull RoleManager mRoleManager;
-
- private PermissionUsageGraphicPreference mGraphic;
-
- /** Unique Id of a request */
- private long mSessionId;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- if (savedInstanceState != null) {
- mSessionId = savedInstanceState.getLong(SESSION_ID_KEY);
- } else {
- mSessionId = getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID);
- }
-
- mFinishedInitialLoad = false;
-
- // By default, do not show system app usages.
- mShowSystem = false;
-
- // By default, show permission usages for the past 24 hours.
- mShow7Days = false;
-
- // Start out with 'other' permissions not expanded.
- mOtherExpanded = false;
-
- setLoading(true, false);
- setHasOptionsMenu(true);
- ActionBar ab = getActivity().getActionBar();
- if (ab != null) {
- ab.setDisplayHomeAsUpEnabled(true);
- }
-
- Context context = getPreferenceManager().getContext();
- mPermissionUsages = new PermissionUsages(context);
- mRoleManager = Utils.getSystemServiceSafe(context, RoleManager.class);
-
- PermissionUsageViewModelFactory factory = new PermissionUsageViewModelFactory(mRoleManager);
- mViewModel = new ViewModelProvider(this, factory).get(PermissionUsageViewModel.class);
-
- reloadData();
- }
-
- @Override
- public RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
- PreferenceGroupAdapter adapter =
- (PreferenceGroupAdapter) super.onCreateAdapter(preferenceScreen);
-
- adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
- @Override
- public void onChanged() {
- updatePreferenceScreenAdvancedTitleAndSummary(preferenceScreen, adapter);
- }
-
- @Override
- public void onItemRangeInserted(int positionStart, int itemCount) {
- onChanged();
- }
-
- @Override
- public void onItemRangeRemoved(int positionStart, int itemCount) {
- onChanged();
- }
-
- @Override
- public void onItemRangeChanged(int positionStart, int itemCount) {
- onChanged();
- }
-
- @Override
- public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
- onChanged();
- }
- });
-
- updatePreferenceScreenAdvancedTitleAndSummary(preferenceScreen, adapter);
- return adapter;
- }
-
- private void updatePreferenceScreenAdvancedTitleAndSummary(PreferenceScreen preferenceScreen,
- PreferenceGroupAdapter adapter) {
- int count = adapter.getItemCount();
- if (count == 0) {
- return;
- }
-
- Preference preference = adapter.getItem(count - 1);
-
- // This is a hacky way of getting the expand button preference for advanced info
- if (preference.getOrder() == EXPAND_BUTTON_ORDER) {
- mOtherExpanded = false;
- preference.setTitle(R.string.perm_usage_adv_info_title);
- preference.setSummary(preferenceScreen.getSummary());
- preference.setLayoutResource(R.layout.expand_button_with_large_title);
- if (mGraphic != null) {
- mGraphic.setShowOtherCategory(false);
- }
- } else {
- mOtherExpanded = true;
- if (mGraphic != null) {
- mGraphic.setShowOtherCategory(true);
- }
- }
- }
-
- @Override
- public void onStart() {
- super.onStart();
- getActivity().setTitle(R.string.permission_usage_title);
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- super.onCreateOptionsMenu(menu, inflater);
- if (mHasSystemApps) {
- mShowSystemMenu = menu.add(Menu.NONE, MENU_SHOW_SYSTEM, Menu.NONE,
- R.string.menu_show_system);
- mHideSystemMenu = menu.add(Menu.NONE, MENU_HIDE_SYSTEM, Menu.NONE,
- R.string.menu_hide_system);
- }
-
- if (is7DayToggleEnabled()) {
- mShow7DaysDataMenu = menu.add(Menu.NONE, MENU_SHOW_7_DAYS_DATA, Menu.NONE,
- R.string.menu_show_7_days_data);
- mShow24HoursDataMenu = menu.add(Menu.NONE, MENU_SHOW_24_HOURS_DATA, Menu.NONE,
- R.string.menu_show_24_hours_data);
- }
-
- HelpUtils.prepareHelpMenuItem(getActivity(), menu, R.string.help_permission_usage,
- getClass().getName());
- MenuItem refresh = menu.add(Menu.NONE, MENU_REFRESH, Menu.NONE,
- R.string.permission_usage_refresh);
- refresh.setIcon(R.drawable.ic_refresh);
- refresh.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
- updateMenu();
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- int itemId = item.getItemId();
- switch (itemId) {
- case android.R.id.home:
- getActivity().finishAfterTransition();
- return true;
- case MENU_SHOW_SYSTEM:
- write(PERMISSION_USAGE_FRAGMENT_INTERACTION, mSessionId,
- PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__SHOW_SYSTEM_CLICKED);
- // fall through
- case MENU_HIDE_SYSTEM:
- mShowSystem = itemId == MENU_SHOW_SYSTEM;
- // We already loaded all data, so don't reload
- updateUI();
- updateMenu();
- break;
- case MENU_SHOW_7_DAYS_DATA:
- case MENU_SHOW_24_HOURS_DATA:
- mShow7Days = is7DayToggleEnabled() && itemId == MENU_SHOW_7_DAYS_DATA;
- updateUI();
- updateMenu();
- break;
- case MENU_REFRESH:
- reloadData();
- break;
- }
- return super.onOptionsItemSelected(item);
- }
-
- private void updateMenu() {
- if (mHasSystemApps) {
- mShowSystemMenu.setVisible(!mShowSystem);
- mHideSystemMenu.setVisible(mShowSystem);
- }
-
- if (mShow7DaysDataMenu != null) {
- mShow7DaysDataMenu.setVisible(!mShow7Days);
- }
-
- if (mShow24HoursDataMenu != null) {
- mShow24HoursDataMenu.setVisible(mShow7Days);
- }
- }
-
- @Override
- public void onPermissionUsagesChanged() {
- if (mPermissionUsages.getUsages().isEmpty()) {
- return;
- }
- mAppPermissionUsages = new ArrayList<>(mPermissionUsages.getUsages());
- updateUI();
- }
-
- @Override
- public int getEmptyViewString() {
- return R.string.no_permission_usages;
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- if (outState != null) {
- outState.putLong(SESSION_ID_KEY, mSessionId);
- }
- }
-
- private void updateUI() {
- if (mAppPermissionUsages.isEmpty() || getActivity() == null) {
- return;
- }
- Context context = getActivity();
-
- PreferenceScreen screen = getPreferenceScreen();
- if (screen == null) {
- screen = getPreferenceManager().createPreferenceScreen(context);
- setPreferenceScreen(screen);
- }
- screen.removeAll();
-
- if (mOtherExpanded) {
- screen.setInitialExpandedChildrenCount(Integer.MAX_VALUE);
- } else {
- screen.setInitialExpandedChildrenCount(
- PERMISSION_USAGE_INITIAL_EXPANDED_CHILDREN_COUNT);
- }
- screen.setOnExpandButtonClickListener(() -> {
- write(PERMISSION_USAGE_FRAGMENT_INTERACTION, mSessionId,
- PERMISSION_USAGE_FRAGMENT_INTERACTION__ACTION__SEE_OTHER_PERMISSIONS_CLICKED);
- });
-
- Triple<Map<String, Integer>, ArrayList<PermissionApps.PermissionApp>, Boolean>
- triple = mViewModel.extractUsages(mAppPermissionUsages, mShow7Days, mShowSystem);
- Map<String, Integer> usages = triple.getFirst();
- ArrayList<PermissionApps.PermissionApp> permApps = triple.getSecond();
- boolean seenSystemApp = triple.getThird();
-
- if (mHasSystemApps != seenSystemApp) {
- mHasSystemApps = seenSystemApp;
- getActivity().invalidateOptionsMenu();
- }
-
- mGraphic = new PermissionUsageGraphicPreference(context, mShow7Days);
- screen.addPreference(mGraphic);
- mGraphic.setUsages(usages);
-
- // Add the preference header.
- PreferenceCategory category = new PreferenceCategory(context);
- screen.addPreference(category);
- List<Map.Entry<String, Integer>> groupUsagesList = mViewModel.createGroupUsagesList(
- getContext(), usages);
-
- CharSequence advancedInfoSummary = getAdvancedInfoSummaryString(context, groupUsagesList);
- screen.setSummary(advancedInfoSummary);
-
- addUIContent(context, groupUsagesList, permApps, category);
- }
-
- private CharSequence getAdvancedInfoSummaryString(Context context,
- List<Map.Entry<String, Integer>> groupUsagesList) {
- int size = groupUsagesList.size();
- if (size <= PERMISSION_USAGE_INITIAL_EXPANDED_CHILDREN_COUNT - 1) {
- return "";
- }
-
- // case for 1 extra item in the advanced info
- if (size == PERMISSION_USAGE_INITIAL_EXPANDED_CHILDREN_COUNT) {
- String permGroupName = groupUsagesList
- .get(PERMISSION_USAGE_INITIAL_EXPANDED_CHILDREN_COUNT - 1).getKey();
- return KotlinUtils.INSTANCE.getPermGroupLabel(context, permGroupName);
- }
-
- String permGroupName1 = groupUsagesList
- .get(PERMISSION_USAGE_INITIAL_EXPANDED_CHILDREN_COUNT - 1).getKey();
- String permGroupName2 = groupUsagesList
- .get(PERMISSION_USAGE_INITIAL_EXPANDED_CHILDREN_COUNT).getKey();
- CharSequence permGroupLabel1 = KotlinUtils
- .INSTANCE.getPermGroupLabel(context, permGroupName1);
- CharSequence permGroupLabel2 = KotlinUtils
- .INSTANCE.getPermGroupLabel(context, permGroupName2);
-
- // case for 2 extra items in the advanced info
- if (size == PERMISSION_USAGE_INITIAL_EXPANDED_CHILDREN_COUNT + 1) {
- return context.getResources().getString(R.string.perm_usage_adv_info_summary_2_items,
- permGroupLabel1, permGroupLabel2);
- }
-
- // case for 3 or more extra items in the advanced info
- int numExtraItems = size - PERMISSION_USAGE_INITIAL_EXPANDED_CHILDREN_COUNT - 1;
- return context.getResources().getString(R.string.perm_usage_adv_info_summary_more_items,
- permGroupLabel1, permGroupLabel2, numExtraItems);
- }
-
- /**
- * Use the usages and permApps that are previously constructed to add UI content to the page
- */
- private void addUIContent(Context context,
- List<Map.Entry<String, Integer>> usages,
- ArrayList<PermissionApps.PermissionApp> permApps,
- PreferenceCategory category) {
- new PermissionApps.AppDataLoader(context, () -> {
- for (int i = 0; i < usages.size(); i++) {
- Map.Entry<String, Integer> currentEntry = usages.get(i);
- PermissionUsageV2ControlPreference permissionUsagePreference =
- new PermissionUsageV2ControlPreference(context, currentEntry.getKey(),
- currentEntry.getValue(), mShowSystem, mSessionId, mShow7Days);
- category.addPreference(permissionUsagePreference);
- }
-
- setLoading(false, true);
- mFinishedInitialLoad = true;
- setProgressBarVisible(false);
-
- Activity activity = getActivity();
- if (activity != null) {
- mPermissionUsages.stopLoader(activity.getLoaderManager());
- }
- }).execute(permApps.toArray(new PermissionApps.PermissionApp[0]));
- }
-
- /**
- * Reloads the data to show.
- */
- private void reloadData() {
- mViewModel.loadPermissionUsages(getActivity().getLoaderManager(), mPermissionUsages, this);
- if (mFinishedInitialLoad) {
- setProgressBarVisible(true);
- }
- }
-}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageV2WrapperFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageWrapperFragment.java
index 25f156318..9bd8cea90 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageV2WrapperFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageWrapperFragment.java
@@ -28,23 +28,21 @@ import androidx.preference.PreferenceFragmentCompat;
import com.android.permissioncontroller.permission.ui.handheld.PermissionsCollapsingToolbarBaseFragment;
-/**
- * Wrapper over PermissionUsageV2Fragment
- */
+/** Wrapper over PermissionUsageFragment */
@RequiresApi(Build.VERSION_CODES.S)
-public class PermissionUsageV2WrapperFragment extends PermissionsCollapsingToolbarBaseFragment{
+public class PermissionUsageWrapperFragment extends PermissionsCollapsingToolbarBaseFragment {
@NonNull
@Override
public PreferenceFragmentCompat createPreferenceFragment() {
- return new PermissionUsageV2Fragment();
+ return new PermissionUsageFragment();
}
/**
* @return A new fragment
*/
- public static @NonNull PermissionUsageV2WrapperFragment newInstance(long numMillis,
- long sessionId) {
- PermissionUsageV2WrapperFragment fragment = new PermissionUsageV2WrapperFragment();
+ public static @NonNull PermissionUsageWrapperFragment newInstance(
+ long numMillis, long sessionId) {
+ PermissionUsageWrapperFragment fragment = new PermissionUsageWrapperFragment();
Bundle arguments = new Bundle();
arguments.putLong(Intent.EXTRA_DURATION_MILLIS, numMillis);
arguments.putLong(EXTRA_SESSION_ID, sessionId);
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/ReviewOngoingUsageFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/ReviewOngoingUsageFragment.java
index caf6a59f7..216d20877 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/ReviewOngoingUsageFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/ReviewOngoingUsageFragment.java
@@ -44,9 +44,9 @@ import androidx.preference.PreferenceFragmentCompat;
import com.android.permissioncontroller.PermissionControllerStatsLog;
import com.android.permissioncontroller.R;
-import com.android.permissioncontroller.permission.ui.model.ReviewOngoingUsageViewModel;
-import com.android.permissioncontroller.permission.ui.model.ReviewOngoingUsageViewModel.PackageAttribution;
-import com.android.permissioncontroller.permission.ui.model.ReviewOngoingUsageViewModelFactory;
+import com.android.permissioncontroller.permission.ui.model.v31.ReviewOngoingUsageViewModel;
+import com.android.permissioncontroller.permission.ui.model.v31.ReviewOngoingUsageViewModel.PackageAttribution;
+import com.android.permissioncontroller.permission.ui.model.v31.ReviewOngoingUsageViewModelFactory;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.Utils;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v33/SafetyCenterQsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v33/SafetyCenterQsFragment.java
deleted file mode 100644
index ee768c0aa..000000000
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v33/SafetyCenterQsFragment.java
+++ /dev/null
@@ -1,525 +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.permissioncontroller.permission.ui.handheld.v33;
-
-import static android.Manifest.permission_group.CAMERA;
-import static android.Manifest.permission_group.LOCATION;
-import static android.Manifest.permission_group.MICROPHONE;
-
-import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
-import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
-
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Color;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.permission.PermissionGroupUsage;
-import android.permission.PermissionManager;
-import android.util.ArrayMap;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
-
-import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
-import androidx.fragment.app.Fragment;
-import androidx.lifecycle.ViewModelProvider;
-import androidx.transition.AutoTransition;
-import androidx.transition.TransitionManager;
-
-import com.android.permissioncontroller.R;
-import com.android.permissioncontroller.permission.ui.model.v33.SafetyCenterQsViewModel;
-import com.android.permissioncontroller.permission.ui.model.v33.SafetyCenterQsViewModelFactory;
-import com.android.permissioncontroller.permission.utils.KotlinUtils;
-import com.android.permissioncontroller.permission.utils.Utils;
-
-import com.google.android.material.card.MaterialCardView;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * The Quick Settings fragment for the safety center. Displays information to the user about the
- * current safety and privacy status of their device, including showing mic/camera usage, and having
- * mic/camera/location toggles.
- */
-@RequiresApi(Build.VERSION_CODES.TIRAMISU)
-public class SafetyCenterQsFragment extends Fragment {
- private static final ArrayMap<String, Integer> sToggleButtons = new ArrayMap<>();
-
- private long mSessionId;
- private List<PermissionGroupUsage> mPermGroupUsages;
- private SafetyCenterQsViewModel mViewModel;
- private View mRootView;
-
- static {
- sToggleButtons.put(CAMERA, R.id.camera_toggle);
- sToggleButtons.put(MICROPHONE, R.id.mic_toggle);
- sToggleButtons.put(LOCATION, R.id.location_toggle);
- }
-
- /**
- * Create arguments for this package
- *
- * @param sessionId The current session Id
- * @return A bundle with the required arguments
- */
- public static SafetyCenterQsFragment newInstance(long sessionId,
- ArrayList<PermissionGroupUsage> usages) {
- Bundle args = new Bundle();
- args.putLong(EXTRA_SESSION_ID, sessionId);
- args.putParcelableArrayList(PermissionManager.EXTRA_PERMISSION_USAGES, usages);
- SafetyCenterQsFragment frag = new SafetyCenterQsFragment();
- frag.setArguments(args);
- return frag;
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- mSessionId = INVALID_SESSION_ID;
- if (getArguments() != null) {
- mSessionId = getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID);
- }
-
- mPermGroupUsages = getArguments()
- .getParcelableArrayList(PermissionManager.EXTRA_PERMISSION_USAGES);
- if (mPermGroupUsages == null) {
- mPermGroupUsages = new ArrayList<>();
- }
-
- getActivity().setTheme(R.style.SafetyCenter);
-
- SafetyCenterQsViewModelFactory factory = new SafetyCenterQsViewModelFactory(
- getActivity().getApplication(), mSessionId, mPermGroupUsages);
- mViewModel = new ViewModelProvider(this, factory).get(SafetyCenterQsViewModel.class);
- mViewModel.getSensorPrivacyLiveData()
- .observe(this, (v) -> setSensorToggleState(v, getView()));
- //LightAppPermGroupLiveDatas are kept track of in the view model,
- // we need to start observing them here
- if (!mPermGroupUsages.isEmpty()) {
- mViewModel.getPermDataLoadedLiveData().observe(this, this::onPermissionGroupsLoaded);
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- ViewGroup root = (ViewGroup) inflater.inflate(R.layout.safety_center_qs, container, false);
- root.findViewById(R.id.security_settings_button).setOnClickListener(
- (v) -> mViewModel.navigateToSecuritySettings(this));
- mRootView = root;
- if (mPermGroupUsages.isEmpty()) {
- mRootView.setVisibility(View.VISIBLE);
- setSensorToggleState(new ArrayMap<>(), mRootView);
- } else {
- mRootView.setVisibility(View.GONE);
- }
- return root;
- }
-
- private void onPermissionGroupsLoaded(boolean initialized) {
- if (initialized) {
- mRootView.setVisibility(View.VISIBLE);
- setSensorToggleState(new ArrayMap<>(), mRootView);
- addPermissionUsageInformation(mRootView);
- }
- }
-
- private void addPermissionUsageInformation(View rootView) {
- if (rootView == null) {
- return;
- }
- View permissionSectionTitleView = rootView.findViewById(R.id.permission_section_title);
- if (mPermGroupUsages == null || mPermGroupUsages.isEmpty()) {
- permissionSectionTitleView.setVisibility(View.GONE);
- return;
- }
- permissionSectionTitleView.setVisibility(View.VISIBLE);
- LinearLayout usageLayout = rootView.findViewById(R.id.permission_usage);
- for (PermissionGroupUsage usage : mPermGroupUsages) {
- View cardView = View.inflate(getContext(), R.layout.indicator_card, usageLayout);
- cardView.setId(View.generateViewId());
-
- RelativeLayout permissionParent = cardView.findViewById(R.id.permission_parent);
- permissionParent.setId(View.generateViewId());
- final int parentIconId = View.generateViewId();
- final int parentTitleId = View.generateViewId();
- final int parentLabelId = View.generateViewId();
- final int parentButtonId = View.generateViewId();
- populatePermissionParent(permissionParent, usage.getPermissionGroupName(),
- generateUsageLabel(usage), parentIconId, parentTitleId, parentLabelId,
- parentButtonId);
-
- if (usage.isPhoneCall()) {
- ImageButton expandButton = permissionParent.findViewById(parentButtonId);
- expandButton.setVisibility(View.GONE);
- continue;
- }
-
- LinearLayout cardViewGroup = cardView.findViewById(R.id.full_card);
- cardViewGroup.setId(View.generateViewId());
-
- View expandedView = cardView.findViewById(R.id.expanded_view);
- expandedView.setId(View.generateViewId());
-
- boolean shouldAllowRevoke = mViewModel.shouldAllowRevoke(usage);
- boolean isSubAttributionUsage = isSubAttributionUsage(usage.getAttributionLabel());
- Intent manageServiceIntent = null;
-
- if (isSubAttributionUsage) {
- manageServiceIntent = mViewModel.getStartViewPermissionUsageIntent(getContext(),
- usage);
- }
-
- boolean canHandleSubAttributionIntent = manageServiceIntent != null;
- int managePermissionIconResId =
- canHandleSubAttributionIntent || !shouldAllowRevoke ? R.drawable.ic_setting
- : R.drawable.ic_block;
-
- int managePermissionLabelResId = getManagePermissionLabel(canHandleSubAttributionIntent,
- shouldAllowRevoke,
- usage.getPermissionGroupName());
-
- RelativeLayout manageParent = populateExpandedPermission(cardView,
- R.id.manage_parent,
- managePermissionIconResId, managePermissionLabelResId);
-
- RelativeLayout usageParent = populateExpandedPermission(cardView, R.id.usage_parent,
- R.drawable.ic_history,
- getSeeUsageText(usage.getPermissionGroupName()));
-
- ImageButton expandButton = permissionParent.findViewById(parentButtonId);
-
- setExpansionClickListener(permissionParent, expandedView, cardViewGroup,
- manageParent,
- usageParent, expandButton);
- setExpansionClickListener(expandButton, expandedView, cardViewGroup, manageParent,
- usageParent, expandButton);
-
- MaterialCardView managePermission = cardView.findViewById(R.id.manage_permission);
- managePermission.setId(View.generateViewId());
-
- if (shouldAllowRevoke) {
- managePermission.setOnClickListener(l -> {
- permissionParent.callOnClick();
- permissionParent.setOnClickListener(null);
- permissionParent.setEnabled(false);
- expandButton.setEnabled(false);
- expandButton.setVisibility(View.GONE);
- revokePermission(permissionParent, parentIconId, parentLabelId, usage);
- });
- } else {
- setManagePermissionClickListener(managePermission, usage, manageServiceIntent);
- }
-
- MaterialCardView seeUsage = cardView.findViewById(R.id.see_usage);
- seeUsage.setId(View.generateViewId());
- seeUsage.setOnClickListener(l -> {
- mViewModel.navigateToSeeUsage(this, usage.getPermissionGroupName());
- });
- }
- }
-
- private void setManagePermissionClickListener(MaterialCardView managePermission,
- PermissionGroupUsage usage, Intent manageServiceIntent) {
- if (manageServiceIntent != null) {
- managePermission.setOnClickListener(l -> {
- mViewModel.navigateToManageService(this, manageServiceIntent);
- });
- } else {
- managePermission.setOnClickListener(l -> {
- mViewModel.navigateToManageAppPermissions(this, usage);
- });
- }
-
- }
-
- private int getManagePermissionLabel(boolean canHandleIntent,
- boolean shouldAllowRevoke,
- String permissionGroupName) {
- if (canHandleIntent) {
- return R.string.manage_service_qs;
- }
- if (!shouldAllowRevoke) {
- return R.string.manage_permissions_qs;
- }
- return getRemovePermissionText(permissionGroupName);
- }
-
- private boolean isSubAttributionUsage(@Nullable CharSequence attributionLabel) {
- if (attributionLabel == null || attributionLabel.length() == 0) {
- return false;
- }
- return true;
- }
-
- private void revokePermission(RelativeLayout permissionParent, int iconId, int labelId,
- PermissionGroupUsage usage) {
- mViewModel.revokePermission(usage);
- ImageView iconView = permissionParent.findViewById(iconId);
- Drawable background = getContext().getDrawable(
- R.drawable.indicator_background_circle).mutate();
- background.setTint(getContext().getColor(R.color.safety_center_done));
- Drawable icon = getContext().getDrawable(R.drawable.ic_check);
- iconView.setImageDrawable(constructIcon(icon, background));
- TextView labelView = permissionParent.findViewById(labelId);
- labelView.setText(R.string.permissions_removed_qs);
- }
-
- private void setExpansionClickListener(View parentView, View expandedView,
- LinearLayout cardViewGroup, RelativeLayout removeParent, RelativeLayout usageParent,
- ImageButton expandButton) {
- parentView.setOnClickListener(v -> {
- AutoTransition transition = new AutoTransition();
- if (expandedView.getVisibility() == View.VISIBLE) {
- TransitionManager.beginDelayedTransition(cardViewGroup, transition);
- expandedView.setVisibility(View.GONE);
- removeParent.setVisibility(View.GONE);
- usageParent.setVisibility(View.GONE);
- expandButton.setImageDrawable(
- getContext().getDrawable(R.drawable.ic_expand_more));
- } else {
- TransitionManager.beginDelayedTransition(cardViewGroup, transition);
- expandedView.setVisibility(View.VISIBLE);
- removeParent.setVisibility(View.VISIBLE);
- usageParent.setVisibility(View.VISIBLE);
- expandButton.setImageDrawable(
- getContext().getDrawable(R.drawable.ic_expand_less));
- }
- });
- }
-
- private String generateUsageLabel(PermissionGroupUsage usage) {
-
- Context context = getContext();
-
- if (usage.isPhoneCall() && usage.isActive()) {
- return context.getString(R.string.active_call_usage_qs);
- } else if (usage.isPhoneCall()) {
- return context.getString(R.string.recent_call_usage_qs);
- }
-
- return generateAttributionUsageLabel(usage);
- }
-
- private String generateAttributionUsageLabel(PermissionGroupUsage usage) {
-
- Context context = getContext();
- CharSequence appLabel = KotlinUtils.INSTANCE.getPackageLabel(
- getActivity().getApplication(), usage.getPackageName(),
- UserHandle.getUserHandleForUid(usage.getUid()));
-
- final int usageResId =
- usage.isActive() ? R.string.active_app_usage_qs : R.string.recent_app_usage_qs;
- final int singleUsageResId =
- usage.isActive() ? R.string.active_app_usage_1_qs : R.string.recent_app_usage_1_qs;
- final int doubleUsageResId =
- usage.isActive() ? R.string.active_app_usage_2_qs : R.string.recent_app_usage_2_qs;
-
- CharSequence attributionLabel = usage.getAttributionLabel();
- CharSequence proxyLabel = usage.getProxyLabel();
-
- if (attributionLabel == null && proxyLabel == null) {
- return context.getString(usageResId, appLabel);
- } else if (attributionLabel != null && proxyLabel != null) {
- return context.getString(doubleUsageResId, appLabel, attributionLabel, proxyLabel);
- } else {
- return context.getString(singleUsageResId, appLabel,
- attributionLabel == null ? proxyLabel : attributionLabel);
- }
- }
-
- private void populatePermissionParent(RelativeLayout permissionParent, String permGroupName,
- String usageText, int iconId, int titleId, int labelId, int buttonId) {
-
- CharSequence permGroupLabel = KotlinUtils.INSTANCE.getPermGroupLabel(getContext(),
- permGroupName);
- ImageView iconView = new ImageView(getContext());
- iconView.setId(iconId);
- RelativeLayout.LayoutParams iconParams = new RelativeLayout.LayoutParams(
- WindowManager.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.WRAP_CONTENT);
- iconParams.setMargins(0, 0, convertDpToPixel(10), 0);
- Drawable indicatorIcon = KotlinUtils.INSTANCE.getPermGroupIcon(getContext(),
- permGroupName, Color.BLACK);
- Drawable background = getContext().getDrawable(R.drawable.indicator_background_circle);
- Utils.applyTint(getContext(), background, android.R.attr.colorAccent);
- iconView.setImageDrawable(constructIcon(indicatorIcon, background));
- iconParams.addRule(RelativeLayout.CENTER_VERTICAL);
- permissionParent.addView(iconView, iconParams);
-
- TextView titleText = new TextView(getContext());
- titleText.setId(titleId);
- titleText.setText(permGroupLabel);
- titleText.setContentDescription(permGroupLabel);
- RelativeLayout.LayoutParams titleParams = new RelativeLayout.LayoutParams(
- WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);
- titleParams.setMargins(convertDpToPixel(10), 0, convertDpToPixel(4), convertDpToPixel(4));
- titleParams.addRule(RelativeLayout.RIGHT_OF, iconId);
- permissionParent.addView(titleText, titleParams);
-
- TextView labelText = new TextView(getContext());
- labelText.setId(labelId);
- labelText.setText(usageText);
- RelativeLayout.LayoutParams textParams = new RelativeLayout.LayoutParams(
- WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);
- textParams.addRule(RelativeLayout.BELOW, titleId);
- textParams.addRule(RelativeLayout.ALIGN_START, titleId);
- textParams.setMargins(0, 0, convertDpToPixel(20), 0);
- permissionParent.addView(labelText, textParams);
-
- ImageButton expandButton = new ImageButton(getContext());
- expandButton.setId(buttonId);
- expandButton.setBackgroundColor(Color.TRANSPARENT);
- expandButton.setImageDrawable(getContext().getDrawable(R.drawable.ic_expand_more));
- RelativeLayout.LayoutParams buttonParams = new RelativeLayout.LayoutParams(
- WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);
- buttonParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
- buttonParams.addRule(RelativeLayout.CENTER_VERTICAL);
- permissionParent.addView(expandButton, buttonParams);
- }
-
- private RelativeLayout populateExpandedPermission(View indicatorCardView, int expandedCardId,
- int iconId,
- int usageResId) {
-
- RelativeLayout parentLayout = indicatorCardView.findViewById(expandedCardId);
- parentLayout.setId(View.generateViewId());
- parentLayout.setPadding(convertDpToPixel(8), convertDpToPixel(8), 0, convertDpToPixel(8));
- parentLayout.setVisibility(View.GONE);
-
- ImageView iconView = new ImageView(getContext());
- iconView.setId(View.generateViewId());
- iconView.setImageResource(iconId);
- RelativeLayout.LayoutParams iconParams = new RelativeLayout.LayoutParams(
- convertDpToPixel(16), convertDpToPixel(16));
- iconParams.setMargins(convertDpToPixel(10), 0, 0, 0);
- iconParams.addRule(RelativeLayout.CENTER_VERTICAL);
- parentLayout.addView(iconView, iconParams);
-
- TextView labelView = new TextView(getContext());
- labelView.setId(View.generateViewId());
- labelView.setText(usageResId);
- RelativeLayout.LayoutParams labelParams = new RelativeLayout.LayoutParams(
- WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);
- labelParams.setMargins(convertDpToPixel(16), 0, 0, 0);
- labelParams.addRule(RelativeLayout.RIGHT_OF, iconView.getId());
- labelParams.addRule(RelativeLayout.CENTER_VERTICAL);
- parentLayout.addView(labelView, labelParams);
-
- return parentLayout;
- }
-
- //TODO: Any use of this method should eventually use dimensions defined in resources
- private int convertDpToPixel(float dp) {
- float density = getResources().getDisplayMetrics().density;
- return (int) (dp * density + 0.5f);
- }
-
- private Drawable constructIcon(Drawable icon, Drawable background) {
- LayerDrawable layered = new LayerDrawable(new Drawable[]{background, icon});
- final int bgLayerIndex = 0;
- final int iconLayerIndex = 1;
- int bgSize = (int) getResources().getDimension(R.dimen.ongoing_appops_dialog_circle_size);
- int iconSize = (int) getResources().getDimension(R.dimen.ongoing_appops_dialog_icon_size);
- layered.setLayerHeight(bgLayerIndex, bgSize);
- layered.setLayerWidth(bgLayerIndex, bgSize);
- layered.setLayerHeight(iconLayerIndex, iconSize);
- layered.setLayerWidth(iconLayerIndex, iconSize);
- layered.setLayerGravity(iconLayerIndex, Gravity.CENTER);
- return layered;
- }
-
-
- private void setSensorToggleState(Map<String, Boolean> sensorState, View rootView) {
- if (rootView == null) {
- if (getView() == null) {
- return;
- }
- rootView = getView();
- if (rootView == null) {
- return;
- }
- }
-
- for (int i = 0; i < sToggleButtons.size(); i++) {
- View toggle = rootView.findViewById(sToggleButtons.valueAt(i));
- String groupName = sToggleButtons.keyAt(i);
- if (!toggle.hasOnClickListeners()) {
- toggle.setOnClickListener((v) -> mViewModel.toggleSensor(groupName));
- }
-
- TextView groupLabel = toggle.findViewById(R.id.toggle_sensor_name);
- groupLabel.setText(KotlinUtils.INSTANCE.getPermGroupLabel(getContext(), groupName));
- TextView blockedStatus = toggle.findViewById(R.id.toggle_sensor_status);
- ImageView iconView = toggle.findViewById(R.id.toggle_sensor_icon);
- boolean sensorEnabled =
- !sensorState.containsKey(groupName) || sensorState.get(groupName);
-
- Drawable icon;
- if (sensorEnabled) {
- blockedStatus.setText(R.string.available);
- toggle.setBackgroundResource(R.drawable.safety_center_button_background);
- icon = KotlinUtils.INSTANCE.getPermGroupIcon(getContext(), groupName, Color.BLACK);
- groupLabel.setTextColor(Color.BLACK);
- } else {
- blockedStatus.setText(R.string.blocked);
- toggle.setBackgroundResource(R.drawable.safety_center_button_background_dark);
- icon = getContext().getDrawable(getBlockedIconResId(groupName));
- icon.setTint(Color.LTGRAY);
- groupLabel.setTextColor(Color.LTGRAY);
- }
- iconView.setImageDrawable(icon);
- }
- }
-
- private static int getRemovePermissionText(String permissionGroup) {
- return CAMERA.equals(permissionGroup) ? R.string.remove_camera_qs
- : R.string.remove_microphone_qs;
- }
-
- private static int getSeeUsageText(String permissionGroup) {
- return CAMERA.equals(permissionGroup) ? R.string.camera_usage_qs
- : R.string.microphone_usage_qs;
- }
-
- private static int getBlockedIconResId(String permissionGroup) {
- switch (permissionGroup) {
- case MICROPHONE:
- return R.drawable.ic_mic_blocked;
- case CAMERA:
- return R.drawable.ic_camera_blocked;
- case LOCATION:
- return R.drawable.ic_location_blocked;
- }
- return -1;
- }
-}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingDetailsPreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingDetailsPreference.kt
new file mode 100644
index 000000000..014627c3c
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingDetailsPreference.kt
@@ -0,0 +1,52 @@
+/*
+ * 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.handheld.v34
+
+import android.content.Context
+import android.os.Build
+import android.util.AttributeSet
+import androidx.annotation.RequiresApi
+import androidx.core.view.isVisible
+import androidx.preference.Preference
+import androidx.preference.PreferenceViewHolder
+import com.android.permissioncontroller.R
+
+/** A preference to show messaging below the page title in the [AppDataSharingUpdatesFragment]. */
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+class AppDataSharingDetailsPreference : 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)
+
+ init {
+ layoutResource = R.layout.app_data_sharing_details_preference
+ }
+
+ /** Whether to show the no updates message. */
+ var showNoUpdates: Boolean = false
+ set(value) {
+ field = value
+ notifyChanged()
+ }
+
+ override fun onBindViewHolder(holder: PreferenceViewHolder) {
+ val noUpdatesMessage = holder.findViewById(R.id.no_updates_message)
+ noUpdatesMessage.isVisible = showNoUpdates
+ super.onBindViewHolder(holder)
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatePreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatePreference.kt
new file mode 100644
index 000000000..95c99c353
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatePreference.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.permissioncontroller.permission.ui.handheld.v34
+
+import android.app.Application
+import android.content.Context
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import android.os.UserHandle
+import android.view.View
+import androidx.annotation.RequiresApi
+import androidx.preference.PreferenceViewHolder
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.ui.handheld.SmartIconLoadPackagePermissionPreference
+
+/**
+ * A preference with package label, summary, app icon and settings gear icon, to represent updates
+ * in data sharing for one app.
+ */
+@RequiresApi(UPSIDE_DOWN_CAKE)
+class AppDataSharingUpdatePreference(
+ app: Application,
+ packageName: String,
+ user: UserHandle,
+ context: Context
+) : SmartIconLoadPackagePermissionPreference(app, packageName, user, context) {
+
+ init {
+ layoutResource = R.layout.app_data_sharing_settings_preference
+ }
+
+ /** [View.OnClickListener] for the preference. */
+ var preferenceClick: View.OnClickListener? = null
+ set(value) {
+ field = value
+ notifyChanged()
+ }
+
+ override fun onBindViewHolder(holder: PreferenceViewHolder) {
+ super.onBindViewHolder(holder)
+
+ holder.itemView.setOnClickListener(preferenceClick)
+ }
+}
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
new file mode 100644
index 000000000..88b5ebe87
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFooterPreference.kt
@@ -0,0 +1,87 @@
+/*
+ * 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 com.android.permissioncontroller.permission.ui.handheld.v34
+
+import android.content.Context
+import android.text.SpannableString
+import android.text.style.ClickableSpan
+import android.util.AttributeSet
+import android.view.View
+import android.widget.TextView
+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 {
+ 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)
+
+ private var footerMessageView: TextView? = null
+ private var footerLinkView: TextView? = null
+
+ init {
+ layoutResource = R.layout.app_data_sharing_updates_footer_preference
+ }
+
+ /** Message for the footer. */
+ var footerMessage: CharSequence = ""
+ set(value) {
+ field = value
+ notifyChanged()
+ }
+
+ /** Clickable link for the footer. */
+ var footerLink: CharSequence = ""
+ set(value) {
+ field = value
+ notifyChanged()
+ }
+
+ /** [View.OnClickListener] for the footer link. */
+ var onFooterLinkClick: View.OnClickListener? = null
+ set(value) {
+ field = value
+ notifyChanged()
+ }
+
+ override fun onBindViewHolder(holder: PreferenceViewHolder) {
+ footerMessageView = holder.findViewById(R.id.footer_message) as TextView?
+ footerMessageView?.text = footerMessage
+
+ footerLinkView = holder.findViewById(R.id.footer_link) as TextView?
+ val footerLinkText = SpannableString(footerLink)
+ footerLinkText.setSpan(
+ object : ClickableSpan() {
+ override fun onClick(v: View) {
+ onFooterLinkClick?.onClick(v)
+ }
+ },
+ 0,
+ footerLink.length,
+ 0)
+ footerLinkView?.let {
+ it.visibility = if (onFooterLinkClick == null) View.GONE else View.VISIBLE
+ it.text = footerLinkText
+ it.movementMethod = LinkMovementMethodCompat.getInstance()
+ }
+ super.onBindViewHolder(holder)
+ }
+}
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
new file mode 100644
index 000000000..2db9bc4b4
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFragment.kt
@@ -0,0 +1,321 @@
+@file:Suppress("DEPRECATION")
+
+package com.android.permissioncontroller.permission.ui.handheld.v34
+
+import android.app.Application
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
+import android.graphics.drawable.Drawable
+import android.os.Build
+import android.os.Bundle
+import android.os.UserHandle
+import android.util.Log
+import android.view.MenuItem
+import android.view.View
+import androidx.annotation.RequiresApi
+import androidx.preference.Preference
+import androidx.preference.PreferenceCategory
+import com.android.permissioncontroller.Constants.EXTRA_SESSION_ID
+import com.android.permissioncontroller.Constants.INVALID_SESSION_ID
+import com.android.permissioncontroller.PermissionControllerStatsLog
+import com.android.permissioncontroller.PermissionControllerStatsLog.APP_DATA_SHARING_UPDATES_FRAGMENT_ACTION_REPORTED
+import com.android.permissioncontroller.PermissionControllerStatsLog.APP_DATA_SHARING_UPDATES_FRAGMENT_ACTION_REPORTED__DATA_SHARING_CHANGE__ADDS_ADVERTISING_PURPOSE
+import com.android.permissioncontroller.PermissionControllerStatsLog.APP_DATA_SHARING_UPDATES_FRAGMENT_ACTION_REPORTED__DATA_SHARING_CHANGE__ADDS_SHARING_WITHOUT_ADVERTISING_PURPOSE
+import com.android.permissioncontroller.PermissionControllerStatsLog.APP_DATA_SHARING_UPDATES_FRAGMENT_ACTION_REPORTED__DATA_SHARING_CHANGE__ADDS_SHARING_WITH_ADVERTISING_PURPOSE
+import com.android.permissioncontroller.PermissionControllerStatsLog.APP_DATA_SHARING_UPDATES_FRAGMENT_VIEWED
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.model.v34.DataSharingUpdateType
+import com.android.permissioncontroller.permission.ui.handheld.PermissionsFrameFragment
+import com.android.permissioncontroller.permission.ui.handheld.pressBack
+import com.android.permissioncontroller.permission.ui.model.v34.AppDataSharingUpdatesViewModel
+import com.android.permissioncontroller.permission.ui.model.v34.AppDataSharingUpdatesViewModel.AppLocationDataSharingUpdateUiInfo
+import com.android.permissioncontroller.permission.utils.KotlinUtils
+import com.android.permissioncontroller.permission.utils.StringUtils
+import java.text.Collator
+import java.util.Random
+
+/** Fragment to display data sharing updates for installed apps. */
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+class AppDataSharingUpdatesFragment : PermissionsFrameFragment() {
+ private lateinit var viewModel: AppDataSharingUpdatesViewModel
+ private lateinit var collator: Collator
+ private var sessionId: Long = INVALID_SESSION_ID
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ requireActivity().title = getString(R.string.data_sharing_updates_title)
+ setHasOptionsMenu(true)
+ collator = Collator.getInstance(requireContext().resources.configuration.locales[0])
+
+ val ab = activity?.actionBar
+ ab?.setDisplayHomeAsUpEnabled(true)
+
+ viewModel = AppDataSharingUpdatesViewModel(requireActivity().application)
+
+ if (preferenceScreen == null) {
+ addPreferencesFromResource(R.xml.app_data_sharing_updates)
+ setLoading(/* loading= */ true, /* animate= */ false)
+ }
+
+ viewModel.appLocationDataSharingUpdateUiInfoLiveData.observe(this, this::updatePreferences)
+ sessionId =
+ activity?.intent?.getLongExtra(EXTRA_SESSION_ID, INVALID_SESSION_ID)
+ ?: INVALID_SESSION_ID
+ while (sessionId == INVALID_SESSION_ID) {
+ sessionId = Random().nextLong()
+ }
+ }
+
+ override fun setDivider(divider: Drawable?) {
+ super.setDivider(ColorDrawable(Color.TRANSPARENT))
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == android.R.id.home) {
+ this.pressBack()
+ return true
+ }
+
+ return super.onOptionsItemSelected(item)
+ }
+
+ private fun updatePreferences(updateUiInfos: List<AppLocationDataSharingUpdateUiInfo>) {
+ setLoading(/* loading= */ false, /* animate= */ true)
+
+ logAppDataSharingUpdatesFragmentViewed(sessionId, updateUiInfos.size)
+
+ if (updateUiInfos.isNotEmpty()) {
+ showUpdatesPresentUi()
+ } else {
+ showNoUpdatesPresentUi()
+ }
+
+ val preferenceKeysToShow =
+ updateUiInfos.map {
+ createUpdatePreferenceKey(it.packageName, it.userHandle, it.dataSharingUpdateType)
+ }
+
+ val updatesCategory =
+ preferenceScreen.findPreference<PreferenceCategory>(
+ LAST_PERIOD_UPDATES_PREFERENCE_CATEGORY_ID
+ ) ?: return
+
+ val preferencesToRemove = mutableSetOf<Preference>()
+ for (i in 0 until (updatesCategory.preferenceCount)) {
+ if (!preferenceKeysToShow.contains(updatesCategory.getPreference(i).key)) {
+ preferencesToRemove.add(updatesCategory.getPreference(i))
+ }
+ }
+ // Remove preferences that no longer need to be shown.
+ preferencesToRemove.forEach { updatesCategory.removePreference(it) }
+
+ updateUiInfos.forEach { updateUiInfo ->
+ val key =
+ createUpdatePreferenceKey(
+ updateUiInfo.packageName,
+ updateUiInfo.userHandle,
+ updateUiInfo.dataSharingUpdateType
+ )
+ if (updatesCategory.findPreference<AppDataSharingUpdatePreference>(key) != null) {
+ // If a preference is already shown, don't recreate it.
+ return@forEach
+ }
+ val appDataSharingUpdatePreference =
+ AppDataSharingUpdatePreference(
+ requireActivity().application,
+ updateUiInfo.packageName,
+ updateUiInfo.userHandle,
+ requireActivity().applicationContext
+ )
+ appDataSharingUpdatePreference.apply {
+ this.key = key
+ title =
+ KotlinUtils.getPackageLabel(
+ requireActivity().application,
+ updateUiInfo.packageName,
+ updateUiInfo.userHandle
+ )
+ summary = getSummaryForLocationUpdateType(updateUiInfo.dataSharingUpdateType)
+ preferenceClick =
+ View.OnClickListener { _ ->
+ logAppDataSharingUpdatesFragmentActionReported(
+ sessionId,
+ requireActivity().application,
+ updateUiInfo
+ )
+ viewModel.startAppLocationPermissionPage(
+ requireActivity(),
+ sessionId,
+ updateUiInfo.packageName,
+ updateUiInfo.userHandle
+ )
+ }
+ updatesCategory.addPreference(this)
+ }
+ }
+ KotlinUtils.sortPreferenceGroup(updatesCategory, this::compareUpdatePreferences, false)
+ }
+
+ private fun getSummaryForLocationUpdateType(type: DataSharingUpdateType): String {
+ return when (type) {
+ DataSharingUpdateType.ADDS_ADVERTISING_PURPOSE ->
+ getString(R.string.shares_location_with_third_parties_for_advertising)
+ DataSharingUpdateType.ADDS_SHARING_WITHOUT_ADVERTISING_PURPOSE ->
+ getString(R.string.shares_location_with_third_parties)
+ DataSharingUpdateType.ADDS_SHARING_WITH_ADVERTISING_PURPOSE ->
+ getString(R.string.shares_location_with_third_parties_for_advertising)
+ }
+ }
+
+ private fun showUpdatesPresentUi() {
+ if (preferenceScreen == null) {
+ return
+ }
+ val detailsPreference =
+ preferenceScreen?.findPreference<AppDataSharingDetailsPreference>(DETAILS_PREFERENCE_ID)
+ val footerPreference =
+ preferenceScreen?.findPreference<AppDataSharingUpdatesFooterPreference>(
+ FOOTER_PREFERENCE_ID
+ )
+ val dataSharingUpdatesCategory =
+ preferenceScreen?.findPreference<PreferenceCategory>(
+ LAST_PERIOD_UPDATES_PREFERENCE_CATEGORY_ID
+ )
+
+ detailsPreference?.let {
+ it.showNoUpdates = false
+ it.isVisible = true
+ }
+ dataSharingUpdatesCategory?.let {
+ it.title =
+ StringUtils.getIcuPluralsString(requireContext(), R.string.updated_in_last_days, 30)
+ it.isVisible = true
+ }
+
+ 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)
+ it.onFooterLinkClick = onFooterLinkClick
+ it.isVisible = true
+ }
+ }
+
+ // TODO(b/261666772): Once spec is final, consider extracting common elements with
+ // showUpdatesPresentUi into a separate method.
+ private fun showNoUpdatesPresentUi() {
+ if (preferenceScreen == null) {
+ return
+ }
+ val detailsPreference =
+ preferenceScreen?.findPreference<AppDataSharingDetailsPreference>(DETAILS_PREFERENCE_ID)
+ val footerPreference =
+ preferenceScreen?.findPreference<AppDataSharingUpdatesFooterPreference>(
+ FOOTER_PREFERENCE_ID
+ )
+ val dataSharingUpdatesCategory =
+ preferenceScreen?.findPreference<PreferenceCategory>(
+ LAST_PERIOD_UPDATES_PREFERENCE_CATEGORY_ID
+ )
+
+ detailsPreference?.let {
+ it.showNoUpdates = true
+ it.isVisible = true
+ }
+ dataSharingUpdatesCategory?.let { it.isVisible = false }
+
+ 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.isVisible = true
+ }
+ }
+
+ /** Creates an identifier for a preference. */
+ private fun createUpdatePreferenceKey(
+ packageName: String,
+ user: UserHandle,
+ update: DataSharingUpdateType
+ ): String {
+ return "$packageName:${user.identifier}:${update.name}"
+ }
+
+ private fun compareUpdatePreferences(lhs: Preference, rhs: Preference): Int {
+ var result = collator.compare(lhs.title.toString(), rhs.title.toString())
+ if (result == 0) {
+ result = lhs.key.compareTo(rhs.key)
+ }
+ return result
+ }
+
+ /** Companion object for [AppDataSharingUpdatesFragment]. */
+ companion object {
+ /**
+ * Creates a [Bundle] with the arguments needed by this fragment.
+ *
+ * @param sessionId the current session ID
+ * @return a [Bundle] with all of the required args
+ */
+ fun createArgs(sessionId: Long) = Bundle().apply { putLong(EXTRA_SESSION_ID, sessionId) }
+
+ private val LOG_TAG = AppDataSharingUpdatesFragment::class.java.simpleName
+
+ private const val DETAILS_PREFERENCE_ID = "details"
+ private const val FOOTER_PREFERENCE_ID = "info_footer"
+ private const val LAST_PERIOD_UPDATES_PREFERENCE_CATEGORY_ID = "last_period_updates"
+
+ private fun logAppDataSharingUpdatesFragmentViewed(
+ sessionId: Long,
+ numberOfAppUpdates: Int
+ ) {
+ PermissionControllerStatsLog.write(
+ APP_DATA_SHARING_UPDATES_FRAGMENT_VIEWED,
+ sessionId,
+ numberOfAppUpdates
+ )
+ Log.v(
+ LOG_TAG,
+ "AppDataSharingUpdatesFragment viewed with" +
+ " sessionId=$sessionId" +
+ " numberOfAppUpdates=$numberOfAppUpdates"
+ )
+ }
+
+ private fun logAppDataSharingUpdatesFragmentActionReported(
+ sessionId: Long,
+ app: Application,
+ updateUiInfo: AppLocationDataSharingUpdateUiInfo
+ ) {
+ val uid: Int =
+ KotlinUtils.getPackageUid(app, updateUiInfo.packageName, updateUiInfo.userHandle)
+ ?: return
+ val dataSharingChangeValue: Int =
+ getStatsLogValueForLocationUpdateType(updateUiInfo.dataSharingUpdateType)
+ PermissionControllerStatsLog.write(
+ APP_DATA_SHARING_UPDATES_FRAGMENT_ACTION_REPORTED,
+ sessionId,
+ uid,
+ dataSharingChangeValue
+ )
+ }
+
+ private fun getStatsLogValueForLocationUpdateType(type: DataSharingUpdateType): Int =
+ when (type) {
+ DataSharingUpdateType.ADDS_ADVERTISING_PURPOSE ->
+ APP_DATA_SHARING_UPDATES_FRAGMENT_ACTION_REPORTED__DATA_SHARING_CHANGE__ADDS_ADVERTISING_PURPOSE
+ DataSharingUpdateType.ADDS_SHARING_WITHOUT_ADVERTISING_PURPOSE ->
+ APP_DATA_SHARING_UPDATES_FRAGMENT_ACTION_REPORTED__DATA_SHARING_CHANGE__ADDS_SHARING_WITHOUT_ADVERTISING_PURPOSE
+ DataSharingUpdateType.ADDS_SHARING_WITH_ADVERTISING_PURPOSE ->
+ APP_DATA_SHARING_UPDATES_FRAGMENT_ACTION_REPORTED__DATA_SHARING_CHANGE__ADDS_SHARING_WITH_ADVERTISING_PURPOSE
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesWrapperFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesWrapperFragment.kt
new file mode 100644
index 000000000..ad092cd9d
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesWrapperFragment.kt
@@ -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 com.android.permissioncontroller.permission.ui.handheld.v34
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.preference.PreferenceFragmentCompat
+import com.android.permissioncontroller.permission.ui.handheld.PermissionsCollapsingToolbarBaseFragment
+
+/** Wrapper class over [AppDataSharingUpdatesFragment]. */
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+class AppDataSharingUpdatesWrapperFragment : PermissionsCollapsingToolbarBaseFragment() {
+ override fun createPreferenceFragment(): PreferenceFragmentCompat {
+ return AppDataSharingUpdatesFragment()
+ }
+
+ companion object {
+ /** Returns a new instance of [AppDataSharingUpdatesWrapperFragment] with arguments. */
+ fun newInstance(sessionId: Long): AppDataSharingUpdatesWrapperFragment {
+ val instance = AppDataSharingUpdatesWrapperFragment()
+ instance.arguments = AppDataSharingUpdatesFragment.createArgs(sessionId)
+ return instance
+ }
+ }
+}
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
new file mode 100644
index 000000000..3998ca141
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/PermissionRationaleViewHandlerImpl.kt
@@ -0,0 +1,277 @@
+/*
+ * 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.permissioncontroller.permission.ui.handheld.v34
+
+import android.app.Activity
+import android.content.Context
+import android.content.res.ColorStateList
+import android.os.Build
+import android.os.Bundle
+import android.transition.ChangeBounds
+import android.transition.TransitionManager
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.View
+import android.view.View.OnClickListener
+import android.view.ViewGroup
+import android.view.animation.AnimationUtils
+import android.widget.Button
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.annotation.RequiresApi
+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
+
+/**
+ * Handheld implementation of [PermissionRationaleViewHandler]. Used for managing the presentation
+ * and user interaction of the "permission rationale" user interface.
+ */
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+class PermissionRationaleViewHandlerImpl(
+ private val mActivity: Activity,
+ private val resultListener: PermissionRationaleViewHandler.ResultListener,
+ private val shouldShowSettingsSection: Boolean
+) : PermissionRationaleViewHandler, OnClickListener {
+
+ private var groupName: String? = null
+ private var title: CharSequence? = null
+ private var dataSharingSourceMessage: CharSequence? = null
+ private var purposeTitle: CharSequence? = null
+ private var purposeMessage: CharSequence? = null
+ private var learnMoreMessage: CharSequence? = null
+ private var settingsMessage: CharSequence? = null
+
+ private var rootView: ViewGroup? = null
+ private var titleView: TextView? = null
+ private var dataSharingSourceMessageView: TextView? = null
+ private var purposeTitleView: TextView? = null
+ private var purposeMessageView: TextView? = null
+ private var learnMoreMessageView: TextView? = null
+ private var settingsMessageView: TextView? = null
+ private var backButton: Button? = null
+
+ override fun saveInstanceState(outState: Bundle) {
+ outState.putString(ARG_GROUP_NAME, groupName)
+ outState.putCharSequence(ARG_TITLE, title)
+ outState.putCharSequence(ARG_DATA_SHARING_SOURCE_MESSAGE, dataSharingSourceMessage)
+ outState.putCharSequence(ARG_PURPOSE_TITLE, purposeTitle)
+ outState.putCharSequence(ARG_PURPOSE_MESSAGE, purposeMessage)
+ outState.putCharSequence(ARG_LEARN_MORE_MESSAGE, learnMoreMessage)
+ outState.putCharSequence(ARG_SETTINGS_MESSAGE, settingsMessage)
+ }
+
+ override fun loadInstanceState(savedInstanceState: Bundle) {
+ groupName = savedInstanceState.getString(ARG_GROUP_NAME)
+ title = savedInstanceState.getCharSequence(ARG_TITLE)
+ dataSharingSourceMessage =
+ savedInstanceState.getCharSequence(ARG_DATA_SHARING_SOURCE_MESSAGE)
+ purposeTitle = savedInstanceState.getCharSequence(ARG_PURPOSE_TITLE)
+ purposeMessage = savedInstanceState.getCharSequence(ARG_PURPOSE_MESSAGE)
+ learnMoreMessage = savedInstanceState.getCharSequence(ARG_LEARN_MORE_MESSAGE)
+ settingsMessage = savedInstanceState.getCharSequence(ARG_SETTINGS_MESSAGE)
+ }
+
+ override fun updateUi(
+ groupName: String,
+ title: CharSequence,
+ dataSharingSourceMessage: CharSequence,
+ purposeTitle: CharSequence,
+ purposeMessage: CharSequence,
+ learnMoreMessage: CharSequence,
+ settingsMessage: CharSequence
+ ) {
+ this.groupName = groupName
+ this.title = title
+ this.dataSharingSourceMessage = dataSharingSourceMessage
+ this.purposeTitle = purposeTitle
+ this.purposeMessage = purposeMessage
+ this.learnMoreMessage = learnMoreMessage
+ this.settingsMessage = settingsMessage
+
+ // If view already created, update all children
+ if (rootView != null) {
+ updateAll()
+ }
+ }
+
+ private fun updateAll() {
+ updateTitle()
+ updateDataSharingSourceMessage()
+ updatePurposeTitle()
+ updatePurposeMessage()
+ updateLearnMoreMessage()
+ updateSettingsMessage()
+
+ // Animate change in size
+ // 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)
+ TransitionManager.beginDelayedTransition(rootView, growShrinkToNewContentSize)
+ }
+
+ override fun createView(): View {
+ 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 =
+ rootView.requireViewById<LinearLayout>(R.id.permission_rationale_singleton).gravity
+ val verticalGravity = Gravity.VERTICAL_GRAVITY_MASK and gravity
+ mActivity.window.setGravity(Gravity.CENTER_HORIZONTAL or verticalGravity)
+
+ // Cancel dialog
+ rootView.findViewById<View>(R.id.permission_rationale_singleton)!!.setOnClickListener(this)
+ // Swallow click event
+ rootView.findViewById<View>(R.id.permission_rationale_dialog)!!.setOnClickListener(this)
+
+ titleView = rootView.findViewById(R.id.permission_rationale_title)
+
+ dataSharingSourceMessageView = rootView.findViewById(R.id.data_sharing_source_message)
+ dataSharingSourceMessageView!!.movementMethod = LinkMovementMethodCompat.getInstance()
+
+ purposeTitleView = rootView.findViewById(R.id.purpose_title)
+ purposeMessageView = rootView.findViewById(R.id.purpose_message)
+
+ learnMoreMessageView = rootView.findViewById(R.id.learn_more_message)
+ learnMoreMessageView!!.movementMethod = LinkMovementMethodCompat.getInstance()
+
+ settingsMessageView = rootView.findViewById(R.id.settings_message)
+ settingsMessageView!!.movementMethod = LinkMovementMethodCompat.getInstance()
+
+ if (!shouldShowSettingsSection) {
+ 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)
+ }
+
+ this.rootView = rootView
+
+ // If ui model present, update all children
+ if (groupName != null) {
+ updateAll()
+ }
+
+ return rootView
+ }
+
+ override fun onClick(view: View) {
+ val id = view.id
+
+ if (id == R.id.permission_rationale_singleton) {
+ onCancelled()
+ return
+ }
+
+ if (id == R.id.back_button) {
+ onCancelled()
+ }
+ }
+
+ override fun onBackPressed() {
+ onCancelled()
+ }
+
+ override fun onCancelled() {
+ resultListener.onPermissionRationaleResult(groupName, CANCELLED)
+ }
+
+ private fun updateTitle() {
+ if (title == null) {
+ titleView!!.visibility = View.GONE
+ } else {
+ titleView!!.text = title
+ titleView!!.visibility = View.VISIBLE
+ }
+ }
+
+ private fun updateDataSharingSourceMessage() {
+ if (dataSharingSourceMessage == null) {
+ dataSharingSourceMessageView!!.visibility = View.GONE
+ } else {
+ dataSharingSourceMessageView!!.text = dataSharingSourceMessage
+ dataSharingSourceMessageView!!.visibility = View.VISIBLE
+ }
+ }
+
+ private fun updatePurposeTitle() {
+ if (purposeTitle == null) {
+ purposeTitleView!!.visibility = View.GONE
+ } else {
+ purposeTitleView!!.text = purposeTitle
+ purposeTitleView!!.visibility = View.VISIBLE
+ }
+ }
+
+ private fun updatePurposeMessage() {
+ if (purposeMessage == null) {
+ purposeMessageView!!.visibility = View.GONE
+ } else {
+ purposeMessageView!!.text = purposeMessage
+ purposeMessageView!!.visibility = View.VISIBLE
+ }
+ }
+
+ private fun updateLearnMoreMessage() {
+ if (learnMoreMessage == null) {
+ learnMoreMessageView!!.visibility = View.GONE
+ } else {
+ learnMoreMessageView!!.text = learnMoreMessage
+ learnMoreMessageView!!.visibility = View.VISIBLE
+ }
+ }
+
+ private fun updateSettingsMessage() {
+ if (settingsMessage == null) {
+ settingsMessageView!!.visibility = View.GONE
+ } else {
+ settingsMessageView!!.text = settingsMessage
+ settingsMessageView!!.visibility = View.VISIBLE
+ }
+ }
+
+ companion object {
+ private val TAG = PermissionRationaleViewHandlerImpl::class.java.simpleName
+
+ const val ARG_GROUP_NAME = "ARG_GROUP_NAME"
+ const val ARG_TITLE = "ARG_TITLE"
+ const val ARG_DATA_SHARING_SOURCE_MESSAGE = "ARG_DATA_SHARING_SOURCE_MESSAGE"
+ const val ARG_PURPOSE_TITLE = "ARG_PURPOSE_TITLE"
+ const val ARG_PURPOSE_MESSAGE = "ARG_PURPOSE_MESSAGE"
+ const val ARG_LEARN_MORE_MESSAGE = "ARG_LEARN_MORE_MESSAGE"
+ const val ARG_SETTINGS_MESSAGE = "ARG_SETTINGS_MESSAGE"
+
+ // Animation parameters.
+ private const val ANIMATION_DURATION_MILLIS: Long = 200
+
+ fun getColorStateListForAttr(context: Context, attr: Int): ColorStateList? {
+ val typedArray = context.obtainStyledAttributes(intArrayOf(attr))
+ val colorStateList = typedArray.getColorStateList(0)
+ typedArray.recycle()
+ return colorStateList
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v33/package-info.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/package-info.java
index 686989269..48eb8661a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v33/package-info.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/package-info.java
@@ -14,5 +14,5 @@
* limitations under the License.
*/
-@androidx.annotation.RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU)
-package com.android.permissioncontroller.permission.ui.handheld.v33;
+@androidx.annotation.RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+package com.android.permissioncontroller.permission.ui.handheld.v34;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/AppPermissionActivity.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/AppPermissionActivity.java
index 6386e5150..0ec003cb1 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/AppPermissionActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/AppPermissionActivity.java
@@ -36,12 +36,12 @@ import androidx.fragment.app.FragmentActivity;
import com.android.permissioncontroller.DeviceUtils;
import com.android.permissioncontroller.R;
-import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler;
import com.android.permissioncontroller.permission.ui.LocationProviderInterceptDialog;
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity;
import com.android.permissioncontroller.permission.ui.auto.AutoAppPermissionFragment;
import com.android.permissioncontroller.permission.ui.television.AppPermissionFragment;
import com.android.permissioncontroller.permission.utils.LocationUtils;
+import com.android.permissioncontroller.permission.utils.PermissionMapping;
import com.android.permissioncontroller.permission.utils.Utils;
import java.util.List;
@@ -104,7 +104,7 @@ public final class AppPermissionActivity extends FragmentActivity {
return;
}
if (groupName == null) {
- groupName = Utils.getGroupOfPlatformPermission(permissionName);
+ groupName = PermissionMapping.getGroupOfPlatformPermission(permissionName);
PermissionInfo permission;
try {
permission = getPackageManager().getPermissionInfo(permissionName, 0);
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageDetailsViewModelLegacy.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageDetailsViewModelLegacy.kt
new file mode 100644
index 000000000..e219153f3
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageDetailsViewModelLegacy.kt
@@ -0,0 +1,560 @@
+/*
+ * 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.
+ */
+@file:Suppress("DEPRECATION")
+
+package com.android.permissioncontroller.permission.ui.legacy
+
+import android.Manifest
+import android.app.AppOpsManager
+import android.app.Application
+import android.app.LoaderManager
+import android.app.role.RoleManager
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.content.res.Resources
+import android.graphics.drawable.Drawable
+import android.os.Build
+import android.os.UserHandle
+import androidx.annotation.RequiresApi
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.android.permissioncontroller.PermissionControllerApplication
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.model.AppPermissionGroup
+import com.android.permissioncontroller.permission.model.legacy.PermissionApps.PermissionApp
+import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage
+import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage.TimelineUsage
+import com.android.permissioncontroller.permission.model.v31.PermissionUsages
+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.StringUtils
+import com.android.permissioncontroller.permission.utils.v31.SubattributionUtils
+import com.android.permissioncontroller.permission.utils.Utils
+import java.time.Instant
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.TimeUnit.DAYS
+import kotlin.math.max
+
+/** View model for the permission details fragment. */
+@RequiresApi(Build.VERSION_CODES.S)
+class PermissionUsageDetailsViewModelLegacy(
+ val application: Application,
+ val roleManager: RoleManager,
+ private val permissionGroup: String,
+ val sessionId: Long
+) : ViewModel() {
+
+ companion object {
+ private const val ONE_HOUR_MS = 3_600_000
+ private const val ONE_MINUTE_MS = 60_000
+ private const val CLUSTER_SPACING_MINUTES: Long = 1L
+ private val TIME_7_DAYS_DURATION: Long = DAYS.toMillis(7)
+ private val TIME_24_HOURS_DURATION: Long = DAYS.toMillis(1)
+ }
+
+ private val mTimeFilterItemMs = mutableListOf<TimeFilterItemMs>()
+
+ init {
+ initializeTimeFilterItems(application)
+ }
+
+ /** Loads permission usages using [PermissionUsages]. Response is returned to the [callback]. */
+ fun loadPermissionUsages(
+ loaderManager: LoaderManager,
+ permissionUsages: PermissionUsages,
+ callback: PermissionUsages.PermissionsUsagesChangeCallback,
+ filterTimesIndex: Int
+ ) {
+ val timeFilterItemMs: TimeFilterItemMs = mTimeFilterItemMs[filterTimesIndex]
+ val filterTimeBeginMillis = max(System.currentTimeMillis() - timeFilterItemMs.timeMs, 0)
+ permissionUsages.load(
+ /* filterPackageName= */ null,
+ /* filterPermissionGroups= */ null,
+ filterTimeBeginMillis,
+ Long.MAX_VALUE,
+ PermissionUsages.USAGE_FLAG_LAST or PermissionUsages.USAGE_FLAG_HISTORICAL,
+ loaderManager,
+ /* getUiInfo= */ false,
+ /* getNonPlatformPermissions= */ false,
+ /* callback= */ callback,
+ /* sync= */ false)
+ }
+
+ /**
+ * Create a [PermissionUsageDetailsUiData] based on the provided data.
+ *
+ * @param appPermissionUsages data about app permission usages
+ * @param showSystem whether system apps should be shown
+ * @param show7Days whether the last 7 days of history should be shown
+ */
+ fun buildPermissionUsageDetailsUiData(
+ appPermissionUsages: List<AppPermissionUsage>,
+ showSystem: Boolean,
+ show7Days: Boolean
+ ): PermissionUsageDetailsUiData {
+ val showPermissionUsagesDuration =
+ if (KotlinUtils.is7DayToggleEnabled() && show7Days) {
+ TIME_7_DAYS_DURATION
+ } else {
+ TIME_24_HOURS_DURATION
+ }
+ val startTime =
+ (System.currentTimeMillis() - showPermissionUsagesDuration).coerceAtLeast(
+ Instant.EPOCH.toEpochMilli())
+ val appPermissionTimelineUsages: List<AppPermissionTimelineUsage> =
+ extractAppPermissionTimelineUsagesForGroup(appPermissionUsages, permissionGroup)
+ val shouldDisplayShowSystemToggle =
+ shouldDisplayShowSystemToggle(appPermissionTimelineUsages)
+ val permissionApps: List<PermissionApp> =
+ getPermissionAppsWithRecentDiscreteUsage(
+ appPermissionTimelineUsages, showSystem, startTime)
+ val appPermissionUsageEntries =
+ buildDiscreteAccessClusterData(appPermissionTimelineUsages, showSystem, startTime)
+
+ return PermissionUsageDetailsUiData(
+ permissionApps, shouldDisplayShowSystemToggle, appPermissionUsageEntries)
+ }
+
+ private fun getHistoryPreferenceData(
+ discreteAccessClusterData: DiscreteAccessClusterData,
+ ): HistoryPreferenceData {
+ val context = application
+ val accessTimeList =
+ discreteAccessClusterData.discreteAccessDataList.map { p -> p.accessTimeMs }
+ val durationSummaryLabel =
+ getDurationSummary(discreteAccessClusterData, accessTimeList, context)
+ val proxyLabel = getProxyPackageLabel(discreteAccessClusterData)
+ val subattributionLabel = getSubattributionLabel(discreteAccessClusterData)
+ val showingSubattribution =
+ subattributionLabel != null && subattributionLabel.isNotEmpty()
+ val summary =
+ buildUsageSummary(durationSummaryLabel, proxyLabel, subattributionLabel, context)
+
+ return HistoryPreferenceData(
+ UserHandle.getUserHandleForUid(
+ discreteAccessClusterData.appPermissionTimelineUsage.permissionApp.uid),
+ discreteAccessClusterData.appPermissionTimelineUsage.permissionApp.packageName,
+ discreteAccessClusterData.appPermissionTimelineUsage.permissionApp.icon,
+ discreteAccessClusterData.appPermissionTimelineUsage.permissionApp.label,
+ permissionGroup,
+ discreteAccessClusterData.discreteAccessDataList.last().accessTimeMs,
+ discreteAccessClusterData.discreteAccessDataList.first().accessTimeMs,
+ summary,
+ showingSubattribution,
+ discreteAccessClusterData.appPermissionTimelineUsage.attributionTags,
+ sessionId)
+ }
+
+ /**
+ * Returns whether the provided [AppPermissionUsage] instances contains the provided platform
+ * permission group.
+ */
+ fun containsPlatformAppPermissionGroup(
+ appPermissionUsages: List<AppPermissionUsage>,
+ groupName: String,
+ ) = appPermissionUsages.extractAllPlatformAppPermissionGroups().any { it.name == groupName }
+
+ /** Extracts a list of [AppPermissionTimelineUsage] for a particular permission group. */
+ private fun extractAppPermissionTimelineUsagesForGroup(
+ appPermissionUsages: List<AppPermissionUsage>,
+ group: String
+ ): List<AppPermissionTimelineUsage> =
+ appPermissionUsages
+ .filter { !Utils.getExemptedPackages(roleManager).contains(it.packageName) }
+ .map { appPermissionUsage ->
+ getAppPermissionTimelineUsages(
+ appPermissionUsage.app,
+ appPermissionUsage.groupUsages.firstOrNull { it.group.name == group })
+ }
+ .flatten()
+
+ /** Returns whether the show/hide system toggle should be displayed in the UI. */
+ private fun shouldDisplayShowSystemToggle(
+ appPermissionTimelineUsages: List<AppPermissionTimelineUsage>,
+ ): Boolean =
+ appPermissionTimelineUsages
+ .map { it.timelineUsage }
+ .filter { it.hasDiscreteData() }
+ .any { it.group.isSystem() }
+
+ /**
+ * Returns a list of [PermissionApp] instances which had recent discrete permission usage
+ * (recent here refers to usages occurring after the provided start time).
+ */
+ private fun getPermissionAppsWithRecentDiscreteUsage(
+ appPermissionTimelineUsageList: List<AppPermissionTimelineUsage>,
+ showSystem: Boolean,
+ startTime: Long,
+ ): List<PermissionApp> =
+ appPermissionTimelineUsageList
+ .filter { it.timelineUsage.hasDiscreteData() }
+ .filter { showSystem || !it.timelineUsage.group.isSystem() }
+ .filter { it.timelineUsage.allDiscreteAccessTime.any { it.first >= startTime } }
+ .map { it.permissionApp }
+
+ /**
+ * Builds a list of [DiscreteAccessClusterData] from the provided list of
+ * [AppPermissionTimelineUsage].
+ */
+ private fun buildDiscreteAccessClusterData(
+ appPermissionTimelineUsageList: List<AppPermissionTimelineUsage>,
+ showSystem: Boolean,
+ startTime: Long,
+ ): List<DiscreteAccessClusterData> =
+ appPermissionTimelineUsageList
+ .map { appPermissionTimelineUsages ->
+ val accessDataList =
+ extractRecentDiscreteAccessData(
+ appPermissionTimelineUsages.timelineUsage, showSystem, startTime)
+
+ if (accessDataList.size <= 1) {
+ return@map accessDataList.map {
+ DiscreteAccessClusterData(appPermissionTimelineUsages, listOf(it))
+ }
+ }
+
+ clusterDiscreteAccessData(appPermissionTimelineUsages, accessDataList)
+ }
+ .flatten()
+ .sortedWith(
+ compareBy(
+ { -it.discreteAccessDataList.first().accessTimeMs },
+ { it.appPermissionTimelineUsage.permissionApp.label }))
+ .toList()
+
+ /**
+ * Clusters a list of [DiscreteAccessData] into a list of [DiscreteAccessClusterData] instances.
+ *
+ * [DiscreteAccessData] which have accesses sufficiently close together in time will be places
+ * in the same cluster.
+ */
+ private fun clusterDiscreteAccessData(
+ appPermissionTimelineUsage: AppPermissionTimelineUsage,
+ discreteAccessDataList: List<DiscreteAccessData>
+ ): List<DiscreteAccessClusterData> {
+ val clusterDataList = mutableListOf<DiscreteAccessClusterData>()
+ val currentDiscreteAccessDataList: MutableList<DiscreteAccessData> = mutableListOf()
+ for (discreteAccessData in discreteAccessDataList) {
+ if (currentDiscreteAccessDataList.isEmpty()) {
+ currentDiscreteAccessDataList.add(discreteAccessData)
+ } else if (!canAccessBeAddedToCluster(
+ discreteAccessData, currentDiscreteAccessDataList)) {
+ clusterDataList.add(
+ DiscreteAccessClusterData(
+ appPermissionTimelineUsage, currentDiscreteAccessDataList.toMutableList()))
+ currentDiscreteAccessDataList.clear()
+ currentDiscreteAccessDataList.add(discreteAccessData)
+ } else {
+ currentDiscreteAccessDataList.add(discreteAccessData)
+ }
+ }
+ if (currentDiscreteAccessDataList.isNotEmpty()) {
+ clusterDataList.add(
+ DiscreteAccessClusterData(
+ appPermissionTimelineUsage, currentDiscreteAccessDataList))
+ }
+ return clusterDataList
+ }
+
+ /**
+ * Extract recent [DiscreteAccessData] from a list of [TimelineUsage] instances, and return them
+ * ordered descending by access time (recent here refers to accesses occurring after the
+ * provided start time).
+ */
+ private fun extractRecentDiscreteAccessData(
+ timelineUsages: TimelineUsage,
+ showSystem: Boolean,
+ startTime: Long
+ ): List<DiscreteAccessData> {
+ return if (timelineUsages.hasDiscreteData() &&
+ (showSystem || !timelineUsages.group.isSystem())) {
+ getRecentDiscreteAccessData(timelineUsages, startTime)
+ .sortedWith(compareBy { -it.accessTimeMs })
+ .toList()
+ } else {
+ listOf()
+ }
+ }
+
+ /**
+ * Extract recent [DiscreteAccessData] from a [TimelineUsage]. (recent here refers to accesses
+ * occurring after the provided start time).
+ */
+ private fun getRecentDiscreteAccessData(
+ timelineUsage: TimelineUsage,
+ startTime: Long
+ ): List<DiscreteAccessData> {
+ return timelineUsage.allDiscreteAccessTime
+ .filter { it.first >= startTime }
+ .map {
+ DiscreteAccessData(
+ it.first,
+ it.second,
+ it.third,
+ )
+ }
+ }
+
+ /**
+ * Returns whether the provided [DiscreteAccessData] occurred close enough to those in the
+ * clustered list that it can be added to the cluster
+ */
+ private fun canAccessBeAddedToCluster(
+ accessData: DiscreteAccessData,
+ clusteredAccessDataList: List<DiscreteAccessData>
+ ): Boolean =
+ accessData.accessTimeMs / ONE_HOUR_MS ==
+ clusteredAccessDataList.first().accessTimeMs / ONE_HOUR_MS &&
+ clusteredAccessDataList.last().accessTimeMs / ONE_MINUTE_MS -
+ accessData.accessTimeMs / ONE_MINUTE_MS > CLUSTER_SPACING_MINUTES
+
+ /**
+ * Returns whether the provided [AppPermissionGroup] is considered a system group.
+ *
+ * For the purpose of Permissions Hub UI, non user-sensitive [AppPermissionGroup]s are
+ * considered "system" and should be hidden from the main page unless requested by the user
+ * through the "show/hide system" toggle.
+ */
+ private fun AppPermissionGroup.isSystem() = !Utils.isGroupOrBgGroupUserSensitive(this)
+
+ /** Returns whether app subattribution should be shown. */
+ private fun shouldShowSubattributionForApp(appInfo: ApplicationInfo): Boolean {
+ return shouldShowSubattributionInPermissionsDashboard() &&
+ SubattributionUtils.isSubattributionSupported(application, appInfo)
+ }
+
+ /** Returns a summary of the duration the permission was accessed for. */
+ private fun getDurationSummary(
+ usage: DiscreteAccessClusterData,
+ accessTimeList: List<Long>,
+ context: Context
+ ): String? {
+ if (accessTimeList.isEmpty()) {
+ return null
+ }
+
+ var durationMs: Long
+
+ // Since Location accesses are atomic, we manually calculate the access duration
+ // by comparing the first and last access within the cluster.
+ if (permissionGroup == Manifest.permission_group.LOCATION) {
+ durationMs = accessTimeList[0] - accessTimeList[accessTimeList.size - 1]
+ } else {
+ durationMs =
+ usage.discreteAccessDataList.map { it.accessDurationMs }.filter { it > 0 }.sum()
+ }
+ // Only show the duration summary if it is at least (CLUSTER_SPACING_MINUTES + 1) minutes.
+ // Displaying a time that is shorter than the cluster granularity
+ // (CLUSTER_SPACING_MINUTES) will not convey useful information.
+ if (durationMs >= TimeUnit.MINUTES.toMillis(CLUSTER_SPACING_MINUTES + 1)) {
+ return getDurationUsedStr(context, durationMs)
+ }
+
+ return null
+ }
+
+ /** Returns the proxied package label if the permission access was proxied. */
+ private fun getProxyPackageLabel(usage: DiscreteAccessClusterData): String? =
+ usage.discreteAccessDataList
+ .firstOrNull { it.proxy?.packageName != null }
+ ?.let {
+ getPackageLabel(
+ PermissionControllerApplication.get(),
+ it.proxy!!.packageName!!,
+ UserHandle.getUserHandleForUid(it.proxy.uid))
+ }
+
+ /** Returns the attribution label for the permission access, if any. */
+ private fun getSubattributionLabel(usage: DiscreteAccessClusterData): String? =
+ if (usage.appPermissionTimelineUsage.label == Resources.ID_NULL) null
+ else
+ usage.appPermissionTimelineUsage.permissionApp.attributionLabels?.let {
+ it[usage.appPermissionTimelineUsage.label]
+ }
+
+ /** Builds a summary of the permission access. */
+ private fun buildUsageSummary(
+ subattributionLabel: String?,
+ proxyPackageLabel: String?,
+ durationSummary: String?,
+ context: Context
+ ): String? {
+ val subTextStrings: MutableList<String?> = mutableListOf()
+
+ subattributionLabel?.let { subTextStrings.add(subattributionLabel) }
+ proxyPackageLabel?.let { subTextStrings.add(it) }
+ durationSummary?.let { subTextStrings.add(it) }
+ return when (subTextStrings.size) {
+ 3 ->
+ context.getString(
+ R.string.history_preference_subtext_3,
+ subTextStrings[0],
+ subTextStrings[1],
+ subTextStrings[2])
+ 2 ->
+ context.getString(
+ R.string.history_preference_subtext_2, subTextStrings[0], subTextStrings[1])
+ 1 -> subTextStrings[0]
+ else -> null
+ }
+ }
+
+ /**
+ * Builds a list of [AppPermissionTimelineUsage] from the provided
+ * [AppPermissionUsage.GroupUsage].
+ */
+ private fun getAppPermissionTimelineUsages(
+ app: PermissionApp,
+ groupUsage: AppPermissionUsage.GroupUsage?
+ ): List<AppPermissionTimelineUsage> {
+ if (groupUsage == null) {
+ return listOf()
+ }
+
+ if (shouldShowSubattributionForApp(app.appInfo)) {
+ return groupUsage.attributionLabelledGroupUsages.map {
+ AppPermissionTimelineUsage(permissionGroup, app, it, it.label)
+ }
+ }
+
+ return listOf(
+ AppPermissionTimelineUsage(permissionGroup, app, groupUsage, Resources.ID_NULL))
+ }
+
+ /** Extracts to a set all the permission groups declared by the platform. */
+ private fun List<AppPermissionUsage>.extractAllPlatformAppPermissionGroups():
+ Set<AppPermissionGroup> =
+ this.flatMap { it.groupUsages }
+ .map { it.group }
+ .filter { PermissionMapping.isPlatformPermissionGroup(it.name) }
+ .toSet()
+
+ /** Initialize all relevant [TimeFilterItemMs] values. */
+ private fun initializeTimeFilterItems(context: Context) {
+ mTimeFilterItemMs.add(
+ 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)))
+ mTimeFilterItemMs.add(
+ TimeFilterItemMs(
+ DAYS.toMillis(1),
+ StringUtils.getIcuPluralsString(context, R.string.permission_usage_last_n_days, 1)))
+
+ // TODO: theianchen add code for filtering by time here.
+ }
+
+ /** Data used to create a preference for an app's permission usage. */
+ data class HistoryPreferenceData(
+ val userHandle: UserHandle,
+ val pkgName: String,
+ val appIcon: Drawable?,
+ val preferenceTitle: String,
+ val permissionGroup: String,
+ val accessStartTime: Long,
+ val accessEndTime: Long,
+ val summaryText: CharSequence?,
+ val showingAttribution: Boolean,
+ val attributionTags: ArrayList<String>,
+ val sessionId: Long
+ )
+
+ /**
+ * A class representing a given time, e.g., "in the last hour".
+ *
+ * @param timeMs the time represented by this object in milliseconds.
+ * @param label the label to describe the timeframe
+ */
+ data class TimeFilterItemMs(val timeMs: Long, val label: String)
+
+ /**
+ * Class containing all the information needed by the permission usage details fragments to
+ * render UI.
+ */
+ inner class PermissionUsageDetailsUiData(
+ /** List of [PermissionApp] instances */
+ // Note that these are used only to cache app data for the permission usage details
+ // fragment, and have no bearing on the UI on the main permission usage page.
+ val permissionApps: List<PermissionApp>,
+ /** Whether to show the "show/hide system" toggle. */
+ val shouldDisplayShowSystemToggle: Boolean,
+ /** [DiscreteAccessClusterData] instances ordered for display in UI */
+ private val discreteAccessClusterDataList: List<DiscreteAccessClusterData>,
+ ) {
+ // Note that the HistoryPreferenceData are not initialized within the
+ // PermissionUsageDetailsUiData instance as the need to be constructed only after the
+ // calling fragment loads the necessary PermissionApp instances. We will attempt to remove
+ // this dependency in b/240978905.
+ /** Builds a list of [HistoryPreferenceData] to be displayed in the UI. */
+ fun getHistoryPreferenceDataList(): List<HistoryPreferenceData> {
+ return discreteAccessClusterDataList.map {
+ this@PermissionUsageDetailsViewModelLegacy.getHistoryPreferenceData(it)
+ }
+ }
+ }
+
+ /**
+ * Data class representing a cluster of accesses, to be represented as a single entry in the UI.
+ */
+ data class DiscreteAccessClusterData(
+ val appPermissionTimelineUsage: AppPermissionTimelineUsage,
+ val discreteAccessDataList: List<DiscreteAccessData>
+ )
+
+ /** Data class representing a discrete permission access. */
+ data class DiscreteAccessData(
+ val accessTimeMs: Long,
+ val accessDurationMs: Long,
+ val proxy: AppOpsManager.OpEventProxyInfo?
+ )
+
+ /** Data class representing an app's permissions usages for a particular permission group. */
+ data class AppPermissionTimelineUsage(
+ /** Permission group whose usage is being tracked. */
+ val permissionGroup: String,
+ // we need a PermissionApp because the loader takes the PermissionApp
+ // object and loads the icon and label information asynchronously
+ /** App whose permissions are being tracked. */
+ val permissionApp: PermissionApp,
+ /** Timeline usage for the given app and permission. */
+ val timelineUsage: TimelineUsage,
+ val label: Int
+ ) {
+ val attributionTags: java.util.ArrayList<String>
+ get() = ArrayList(timelineUsage.attributionTags)
+ }
+}
+
+/** Factory for an [PermissionUsageDetailsViewModelLegacy] */
+@RequiresApi(Build.VERSION_CODES.S)
+class PermissionUsageDetailsViewModelFactoryLegacy(
+ private val application: Application,
+ private val roleManager: RoleManager,
+ private val filterGroup: String,
+ private val sessionId: Long
+) : ViewModelProvider.Factory {
+
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ @Suppress("UNCHECKED_CAST")
+ return PermissionUsageDetailsViewModelLegacy(
+ 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
new file mode 100644
index 000000000..d0e751f7d
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageViewModelLegacy.kt
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ */
+@file:Suppress("DEPRECATION")
+
+package com.android.permissioncontroller.permission.ui.legacy
+
+import android.Manifest
+import android.app.LoaderManager
+import android.app.role.RoleManager
+import android.content.Context
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.android.permissioncontroller.permission.model.AppPermissionGroup
+import com.android.permissioncontroller.permission.model.legacy.PermissionApps.PermissionApp
+import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage
+import com.android.permissioncontroller.permission.model.v31.PermissionUsages
+import com.android.permissioncontroller.permission.utils.KotlinUtils
+import com.android.permissioncontroller.permission.utils.KotlinUtils.getPermGroupLabel
+import com.android.permissioncontroller.permission.utils.PermissionMapping
+import com.android.permissioncontroller.permission.utils.Utils
+import java.time.Instant
+import java.util.concurrent.TimeUnit
+import kotlin.math.max
+
+/** [ViewModel] for Permission Usage fragments. */
+@RequiresApi(Build.VERSION_CODES.S)
+class PermissionUsageViewModelLegacy(val roleManager: RoleManager) : ViewModel() {
+
+ private val exemptedPackages: Set<String> = Utils.getExemptedPackages(roleManager)
+
+ /** Companion object for [PermissionUsageViewModelLegacy]. */
+ companion object {
+ /** TODO(ewol): Use the config setting to determine amount of time to show. */
+ private val TIME_FILTER_MILLIS = TimeUnit.DAYS.toMillis(7)
+ private val TIME_7_DAYS_DURATION = TimeUnit.DAYS.toMillis(7)
+ private val TIME_24_HOURS_DURATION = TimeUnit.DAYS.toMillis(1)
+ /** Permission groups that should be hidden from the permissions usage UI. */
+ private val EXEMPTED_PERMISSION_GROUPS = setOf(Manifest.permission_group.NOTIFICATIONS)
+ @JvmStatic
+ /** Map to represent ordering for permission groups in the permissions usage UI. */
+ val PERMISSION_GROUP_ORDER: Map<String, Int> =
+ mapOf(
+ Manifest.permission_group.LOCATION to 0,
+ Manifest.permission_group.CAMERA to 1,
+ Manifest.permission_group.MICROPHONE to 2)
+ private const val DEFAULT_ORDER = 3
+ }
+
+ /** Loads data from [PermissionUsages] using the [LoaderManager] pattern. */
+ fun loadPermissionUsages(
+ loaderManager: LoaderManager,
+ permissionUsages: PermissionUsages,
+ callback: PermissionUsages.PermissionsUsagesChangeCallback
+ ) {
+ val filterTimeBeginMillis =
+ max(System.currentTimeMillis() - TIME_FILTER_MILLIS, Instant.EPOCH.toEpochMilli())
+ permissionUsages.load(
+ null /*filterPackageName*/,
+ null /*filterPermissionGroups*/,
+ filterTimeBeginMillis,
+ Long.MAX_VALUE,
+ PermissionUsages.USAGE_FLAG_LAST or PermissionUsages.USAGE_FLAG_HISTORICAL,
+ loaderManager,
+ false /*getUiInfo*/,
+ false /*getNonPlatformPermissions*/,
+ callback /*callback*/,
+ false /*sync*/)
+ }
+
+ /**
+ * Parses the provided list of [AppPermissionUsage] instances to build data for the UI to
+ * display.
+ */
+ fun buildPermissionUsagesUiData(
+ appPermissionUsages: List<AppPermissionUsage>,
+ show7Days: Boolean,
+ showSystem: Boolean,
+ context: Context,
+ ): PermissionUsagesUiData {
+ val curTime = System.currentTimeMillis()
+ val showPermissionUsagesDuration =
+ if (KotlinUtils.is7DayToggleEnabled() && show7Days) {
+ TIME_7_DAYS_DURATION
+ } else {
+ TIME_24_HOURS_DURATION
+ }
+ val startTime = max(curTime - showPermissionUsagesDuration, Instant.EPOCH.toEpochMilli())
+
+ val filteredAppPermissionUsages =
+ appPermissionUsages.filter { !exemptedPackages.contains(it.packageName) }
+ val displayShowSystemToggle: Boolean =
+ filteredAppPermissionUsages.displayShowSystemToggle(startTime)
+ val permissionApps = filteredAppPermissionUsages.getRecentPermissionApps(startTime)
+ val orderedPermissionGroupsWithUsage =
+ filteredAppPermissionUsages.buildOrderedPermissionGroupsWithUsageCount(
+ context, startTime, showSystem)
+
+ return PermissionUsagesUiData(
+ permissionApps, displayShowSystemToggle, orderedPermissionGroupsWithUsage)
+ }
+
+ /**
+ * Creates an ordered list of [PermissionGroupWithUsageCount] instances to show in the UI,
+ * representing a mapping of permission groups to the number of apps that recently accessed
+ * them.
+ *
+ * The list is ordered as follows:
+ * 1. Location
+ * 2. Camera
+ * 3. Microphone
+ * 4. Remaining permission groups, ordered alphabetically
+ */
+ private fun List<AppPermissionUsage>.buildOrderedPermissionGroupsWithUsageCount(
+ context: Context,
+ startTime: Long,
+ showSystem: Boolean
+ ): List<PermissionGroupWithUsageCount> {
+ val permissionGroupsUsageCountMap: MutableMap<String, Int> = HashMap()
+ extractPlatformAppPermissionGroupsToDisplay().forEach {
+ permissionGroupsUsageCountMap[it] = 0
+ }
+
+ for (appUsage in this) {
+ appUsage.groupUsages
+ .filter { showSystem || !it.group.isSystem() }
+ .filter { !EXEMPTED_PERMISSION_GROUPS.contains(it.group.name) }
+ .filter { it.lastAccessTime >= startTime }
+ .forEach {
+ permissionGroupsUsageCountMap[it.group.name] =
+ permissionGroupsUsageCountMap.getOrDefault(it.group.name, 0) + 1
+ }
+ }
+ return permissionGroupsUsageCountMap.entries
+ .map { PermissionGroupWithUsageCount(it.key, it.value) }
+ .sortedWith(
+ compareBy(
+ { PERMISSION_GROUP_ORDER.getOrDefault(it.permGroup, DEFAULT_ORDER) },
+ { getPermGroupLabel(context, it.permGroup).toString() }))
+ }
+
+ /** Extracts [PermissionApp] where there has been recent permission usage. */
+ private fun List<AppPermissionUsage>.getRecentPermissionApps(
+ startTime: Long,
+ ): java.util.ArrayList<PermissionApp> {
+ return ArrayList(
+ filter { appPermissionUsage ->
+ appPermissionUsage.groupUsages
+ .filter { !EXEMPTED_PERMISSION_GROUPS.contains(it.group.name) }
+ .any { it.lastAccessTime >= startTime || it.lastAccessTime == 0L }
+ }
+ .map { it.app })
+ }
+
+ /**
+ * Returns whether there are any user-sensitive app permission groups with recent usage, and
+ * therefore if the "show/hide system" toggle needs to be displayed in the UI
+ */
+ private fun List<AppPermissionUsage>.displayShowSystemToggle(
+ startTime: Long,
+ ): Boolean {
+ return flatMap { it.groupUsages }
+ .filter { !EXEMPTED_PERMISSION_GROUPS.contains(it.group.name) }
+ .filter { it.lastAccessTime > startTime && it.lastAccessTime > 0L }
+ .any { it.group.isSystem() }
+ }
+
+ /**
+ * Extracts to a set all the permission groups declared by the platform that should be displayed
+ * in the UI.
+ */
+ private fun List<AppPermissionUsage>.extractPlatformAppPermissionGroupsToDisplay():
+ Set<String> =
+ this.flatMap { it.groupUsages }
+ .map { it.group.name }
+ .filter { PermissionMapping.isPlatformPermissionGroup(it) }
+ .filter { !EXEMPTED_PERMISSION_GROUPS.contains(it) }
+ .toSet()
+
+ /**
+ * Returns whether the [AppPermissionGroup] is considered a system group.
+ *
+ * For the purpose of Permissions Hub UI, non user-sensitive [AppPermissionGroup]s are
+ * considered "system" and should be hidden from the main page unless requested by the user
+ * through the "show/hide system" toggle.
+ */
+ private fun AppPermissionGroup.isSystem() = !Utils.isGroupOrBgGroupUserSensitive(this)
+
+ /** Data class to hold all the information required to configure the UI. */
+ data class PermissionUsagesUiData(
+ /** List of [PermissionApp] instances */
+ // Note that these are used only to cache app data for the permission usage details
+ // fragment, and have no bearing on the UI on the main permission usage page.
+ val permissionApps: ArrayList<PermissionApp>,
+ /** Whether to show the "show/hide system" toggle. */
+ val displayShowSystemToggle: Boolean,
+ // TODO(b/243970988): Consider moving ordering logic to fragment.
+ /** [PermissionGroupWithUsageCount] instances ordered for display in UI */
+ val orderedPermissionGroupsWithUsageCount: List<PermissionGroupWithUsageCount>,
+ )
+
+ /**
+ * Data class to associate permission groups with the number of apps that recently accessed
+ * them.
+ */
+ data class PermissionGroupWithUsageCount(val permGroup: String, val appCount: Int)
+}
+
+/** Factory for [PermissionUsageViewModelLegacy]. */
+@RequiresApi(Build.VERSION_CODES.S)
+class PermissionUsageViewModelFactoryLegacy(private val roleManager: RoleManager) :
+ ViewModelProvider.Factory {
+
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ @Suppress("UNCHECKED_CAST") return PermissionUsageViewModelLegacy(roleManager) as T
+ }
+}
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 007945819..741c93aab 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionGroupsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionGroupsViewModel.kt
@@ -46,19 +46,20 @@ import com.android.permissioncontroller.permission.data.PackagePermissionsLiveDa
import com.android.permissioncontroller.permission.data.PackagePermissionsLiveData.Companion.NON_RUNTIME_NORMAL_PERMS
import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData
import com.android.permissioncontroller.permission.data.get
-import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage
import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGroupUiInfo.PermGrantState
+import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage
import com.android.permissioncontroller.permission.ui.Category
-import com.android.permissioncontroller.permission.ui.handheld.v31.is7DayToggleEnabled
import com.android.permissioncontroller.permission.utils.IPC
+import com.android.permissioncontroller.permission.utils.KotlinUtils
+import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.utils.Utils
import com.android.permissioncontroller.permission.utils.Utils.AppPermsLastAccessType
import com.android.permissioncontroller.permission.utils.navigateSafe
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.launch
import java.time.Instant
import java.util.concurrent.TimeUnit
import kotlin.math.max
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
/**
* ViewModel for the AppPermissionGroupsFragment. Has a liveData with the UI information for all
@@ -158,7 +159,7 @@ class AppPermissionGroupsViewModel(
}
for (groupName in groups) {
- val isSystem = Utils.getPlatformPermissionGroups().contains(groupName)
+ val isSystem = PermissionMapping.getPlatformPermissionGroups().contains(groupName)
appPermGroupUiInfoLiveDatas[groupName]?.value?.let { uiInfo ->
if (SdkLevel.isAtLeastT() && !uiInfo.shouldShow) {
return@let
@@ -280,7 +281,7 @@ class AppPermissionGroupsViewModel(
return
}
- val aggregateDataFilterBeginDays = if (is7DayToggleEnabled())
+ val aggregateDataFilterBeginDays = if (KotlinUtils.is7DayToggleEnabled())
AGGREGATE_DATA_FILTER_BEGIN_DAYS_7 else AGGREGATE_DATA_FILTER_BEGIN_DAYS_1
accessTime.clear()
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 e42e619e8..99b40d8a7 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt
@@ -20,42 +20,50 @@ 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_group.LOCATION
+import android.Manifest.permission_group.READ_MEDIA_VISUAL
import android.annotation.SuppressLint
+import android.app.Activity
import android.app.AppOpsManager
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
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import com.android.modules.utils.build.SdkLevel
+import com.android.permissioncontroller.Constants
import com.android.permissioncontroller.PermissionControllerStatsLog
import com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_FRAGMENT_ACTION_REPORTED
+import com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__PERMISSION_RATIONALE
import com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_FRAGMENT_VIEWED
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.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.AdvancedConfirmDialogArgs
-
-import com.android.permissioncontroller.permission.ui.handheld.v31.getDefaultPrecision
-import com.android.permissioncontroller.permission.ui.handheld.v31.isLocationAccuracyEnabled
+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
@@ -64,11 +72,20 @@ import com.android.permissioncontroller.permission.ui.model.AppPermissionViewMod
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType.DENY
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.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.LocationUtils
+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.navigateSafe
+import com.android.permissioncontroller.permission.utils.v34.SafetyLabelUtils
import com.android.settingslib.RestrictedLockUtils
import java.util.Random
import kotlin.collections.component1
@@ -94,8 +111,8 @@ 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 {
@@ -110,21 +127,22 @@ class AppPermissionViewModel(
}
enum class ChangeRequest(val value: Int) {
- GRANT_FOREGROUND(1),
- REVOKE_FOREGROUND(2),
- GRANT_BACKGROUND(4),
- REVOKE_BACKGROUND(8),
+ GRANT_FOREGROUND(1 shl 0),
+ REVOKE_FOREGROUND(1 shl 1),
+ GRANT_BACKGROUND(1 shl 2),
+ REVOKE_BACKGROUND(1 shl 3),
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(16),
- GRANT_FINE_LOCATION(32),
- REVOKE_FINE_LOCATION(64),
- GRANT_STORAGE_SUPERGROUP(128),
- REVOKE_STORAGE_SUPERGROUP(256),
+ 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),
- REVOKE_STORAGE_SUPERGROUP_CONFIRMED(REVOKE_STORAGE_SUPERGROUP.value or REVOKE_BOTH.value);
+ REVOKE_STORAGE_SUPERGROUP_CONFIRMED(REVOKE_STORAGE_SUPERGROUP.value or REVOKE_BOTH.value),
+ PHOTOS_SELECTED( 1 shl 9);
infix fun andValue(other: ChangeRequest): Int {
return value and other.value
@@ -139,13 +157,16 @@ class AppPermissionViewModel(
ASK(4),
DENY(5),
DENY_FOREGROUND(6),
- LOCATION_ACCURACY(7);
+ LOCATION_ACCURACY(7),
+ 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>()
@@ -162,6 +183,41 @@ class AppPermissionViewModel(
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
+ }
+
+ init {
+ if (safetyLabelInfoLiveData != null &&
+ PermissionMapping.isSafetyLabelAwarePermissionGroup(permGroupName)) {
+ addSource(safetyLabelInfoLiveData) { update() }
+ } else {
+ value = false
+ }
+ }
+
+ override fun onUpdate() {
+ if (safetyLabelInfoLiveData != null && safetyLabelInfoLiveData.isStale) {
+ return
+ }
+
+ val safetyLabel = safetyLabelInfoLiveData?.value?.safetyLabel
+ if (safetyLabel == null) {
+ value = false
+ return
+ }
+
+ value = SafetyLabelUtils.getSafetyLabelSharingPurposesForGroup(
+ safetyLabel, permGroupName).any()
+ }
+ }
+
+ /**
* A livedata which determines which detail string, if any, should be shown
*/
val fullStorageStateLiveData = object : SmartUpdateMediatorLiveData<FullStoragePackageState>() {
@@ -198,8 +254,8 @@ class AppPermissionViewModel(
/**
* A livedata which computes the state of the radio buttons
*/
- val buttonStateLiveData = object
- : SmartUpdateMediatorLiveData<@JvmSuppressWildcards Map<ButtonType, ButtonState>>() {
+ val buttonStateLiveData = object :
+ SmartUpdateMediatorLiveData<@JvmSuppressWildcards Map<ButtonType, ButtonState>>() {
private val appPermGroupLiveData = LightAppPermGroupLiveData[packageName, permGroupName,
user]
@@ -210,7 +266,7 @@ class AppPermissionViewModel(
addSource(appPermGroupLiveData) { appPermGroup ->
lightAppPermGroup = appPermGroup
- if (permGroupName in Utils.STORAGE_SUPERGROUP_PERMISSIONS) {
+ if (permGroupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS) {
onMediaPermGroupUpdate(permGroupName, appPermGroup)
}
if (appPermGroupLiveData.isInitialized && appPermGroup == null) {
@@ -219,9 +275,6 @@ class AppPermissionViewModel(
if (isStorageAndLessThanT && !fullStorageStateLiveData.isInitialized) {
return@addSource
}
- if (value == null) {
- logAppPermissionFragmentViewed()
- }
update()
}
}
@@ -232,8 +285,8 @@ class AppPermissionViewModel(
}
}
- if (permGroupName in Utils.STORAGE_SUPERGROUP_PERMISSIONS) {
- for (permGroupName in Utils.STORAGE_SUPERGROUP_PERMISSIONS) {
+ if (permGroupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS) {
+ for (permGroupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS) {
val liveData = LightAppPermGroupLiveData[packageName, permGroupName, user]
mediaStorageSupergroupLiveData[permGroupName] = liveData
}
@@ -244,6 +297,10 @@ class AppPermissionViewModel(
}
}
}
+
+ addSource(showPermissionRationaleLiveData) {
+ update()
+ }
}
private fun onMediaPermGroupUpdate(permGroupName: String, permGroup: LightAppPermGroup?) {
@@ -264,6 +321,10 @@ class AppPermissionViewModel(
}
}
+ if (!showPermissionRationaleLiveData.isInitialized) {
+ return
+ }
+
val admin = RestrictedLockUtils.getProfileOrDeviceOwner(app, user)
val allowedState = ButtonState()
@@ -273,9 +334,10 @@ class AppPermissionViewModel(
val askState = ButtonState()
val deniedState = ButtonState()
val deniedForegroundState = ButtonState()
+ val selectState = ButtonState()
askOneTimeState.isShown = group.foreground.isGranted && group.isOneTime
- askState.isShown = Utils.supportsOneTimeGrant(permGroupName) &&
+ askState.isShown = PermissionMapping.supportsOneTimeGrant(permGroupName) &&
!(group.foreground.isGranted && group.isOneTime)
deniedState.isShown = true
@@ -313,6 +375,17 @@ class AppPermissionViewModel(
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
@@ -374,9 +447,8 @@ class AppPermissionViewModel(
}
if (shouldShowLocationAccuracy == null) {
- shouldShowLocationAccuracy = group.permGroupName == LOCATION &&
- group.permissions.containsKey(ACCESS_FINE_LOCATION) &&
- isLocationAccuracyEnabled()
+ shouldShowLocationAccuracy = isLocationAccuracyEnabled() &&
+ group.permissions.containsKey(ACCESS_FINE_LOCATION)
}
val locationAccuracyState = ButtonState(isFineLocationChecked(group),
true, false, null)
@@ -387,11 +459,36 @@ class AppPermissionViewModel(
locationAccuracyState.isEnabled = false
}
+ 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)
+ LOCATION_ACCURACY to locationAccuracyState, SELECT_PHOTOS to selectState)
+ }
+ }
+
+ fun registerPhotoPickerResultIfNeeded(fragment: Fragment) {
+ if (permGroupName != READ_MEDIA_VISUAL) {
+ return
+ }
+ 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)
}
}
@@ -400,14 +497,18 @@ class AppPermissionViewModel(
val coarseLocation = group.permissions[ACCESS_COARSE_LOCATION]!!
val fineLocation = group.permissions[ACCESS_FINE_LOCATION]!!
// Steps to decide location accuracy toggle state
- // 1. If none of the FINE and COARSE isSelectedLocationAccuracy flags is set,
- // then use default precision from device config.
- // 2. Otherwise return if FINE isSelectedLocationAccuracy is set to true.
- return if ((!fineLocation.isSelectedLocationAccuracy &&
- !coarseLocation.isSelectedLocationAccuracy)) {
- getDefaultPrecision()
- } else {
+ // 1. If FINE or COARSE are granted, then return true if FINE is granted.
+ // 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) {
+ fineLocation.isGrantedIncludingAppOp
+ } else if (fineLocation.isSelectedLocationAccuracy ||
+ coarseLocation.isSelectedLocationAccuracy) {
fineLocation.isSelectedLocationAccuracy
+ } else {
+ getDefaultPrecision()
}
}
return false
@@ -490,6 +591,36 @@ class AppPermissionViewModel(
}
/**
+ * 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
+ }
+
+ // logPermissionChanges logs the button clicks for settings and any associated permission
+ // change that occurred. Since no permission change takes place, just pass the current
+ // permission state.
+ lightAppPermGroup?.let { group ->
+ logAppPermissionFragmentActionReportedForPermissionGroup(
+ /* changeId= */ Random().nextLong(),
+ group,
+ APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__PERMISSION_RATIONALE)
+ }
+
+ 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)
+ putExtra(EXTRA_SHOULD_SHOW_SETTINGS_SECTION, false)
+ }
+ activity.startActivity(intent)
+ }
+
+ /**
* 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
@@ -545,7 +676,8 @@ class AppPermissionViewModel(
if (changeRequest == ChangeRequest.GRANT_FINE_LOCATION) {
if (!group.isOneTime) {
- KotlinUtils.grantForegroundRuntimePermissions(app, group)
+ val newGroup = KotlinUtils.grantForegroundRuntimePermissions(app, group)
+ logPermissionChanges(group, newGroup, buttonClicked)
}
KotlinUtils.setFlagsWhenLocationAccuracyChanged(app, group, true)
return
@@ -553,13 +685,25 @@ class AppPermissionViewModel(
if (changeRequest == ChangeRequest.REVOKE_FINE_LOCATION) {
if (!group.isOneTime) {
- KotlinUtils.revokeForegroundRuntimePermissions(app, group,
+ val newGroup = KotlinUtils.revokeForegroundRuntimePermissions(app, group,
filterPermissions = listOf(ACCESS_FINE_LOCATION))
+ logPermissionChanges(group, newGroup, buttonClicked)
}
KotlinUtils.setFlagsWhenLocationAccuracyChanged(app, group, false)
return
}
+ 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())
+ logPermissionChanges(group, newGroup, buttonClicked)
+ return
+ }
+
val shouldGrantForeground = changeRequest andValue ChangeRequest.GRANT_FOREGROUND != 0
val shouldGrantBackground = changeRequest andValue ChangeRequest.GRANT_BACKGROUND != 0
val shouldRevokeForeground = changeRequest andValue ChangeRequest.REVOKE_FOREGROUND != 0
@@ -640,7 +784,8 @@ class AppPermissionViewModel(
(wasBackgroundGranted || group2.background.isUserFixed ||
group2.isOneTime != setOneTime)) {
newGroup = KotlinUtils
- .revokeBackgroundRuntimePermissions(app, newGroup, oneTime = setOneTime)
+ .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
@@ -652,7 +797,9 @@ class AppPermissionViewModel(
if (shouldRevokeForeground &&
(wasForegroundGranted || group2.isOneTime != setOneTime)) {
newGroup = KotlinUtils
- .revokeForegroundRuntimePermissions(app, newGroup, false, setOneTime)
+ .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
@@ -662,11 +809,12 @@ class AppPermissionViewModel(
}
if (shouldGrantForeground) {
- if (shouldShowLocationAccuracy == true && !isFineLocationChecked(newGroup)) {
- newGroup = KotlinUtils.grantForegroundRuntimePermissions(app, newGroup,
- filterPermissions = listOf(ACCESS_COARSE_LOCATION))
+ newGroup = if (shouldShowLocationAccuracy == true &&
+ !isFineLocationChecked(newGroup)) {
+ KotlinUtils.grantForegroundRuntimePermissions(app, newGroup,
+ filterPermissions = listOf(ACCESS_COARSE_LOCATION))
} else {
- newGroup = KotlinUtils.grantForegroundRuntimePermissions(app, newGroup)
+ KotlinUtils.grantForegroundRuntimePermissions(app, newGroup)
}
if (!wasForegroundGranted) {
@@ -690,13 +838,19 @@ class AppPermissionViewModel(
}
}
+ private fun shouldClearOneTimeRevokedCompat(group: LightAppPermGroup): Boolean {
+ return isPhotoPickerPromptEnabled() && permGroupName == READ_MEDIA_VISUAL &&
+ group.permissions.values.any { it.isCompatRevoked && it.isOneTime }
+ }
+
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
private fun expandsToStorageSupergroup(group: LightAppPermGroup): Boolean {
return group.packageInfo.targetSdkVersion <= Build.VERSION_CODES.S_V2 &&
- group.permGroupName in Utils.STORAGE_SUPERGROUP_PERMISSIONS
+ group.permGroupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS
}
private fun expandToSupergroup(group: LightAppPermGroup): List<LightAppPermGroup> {
- val mediaSupergroup = Utils.STORAGE_SUPERGROUP_PERMISSIONS
+ val mediaSupergroup = PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS
.mapNotNull { mediaStorageSupergroupPermGroups[it] }
return if (expandsToStorageSupergroup(group)) {
mediaSupergroup
@@ -705,7 +859,24 @@ class AppPermissionViewModel(
}
}
- @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
+ private fun getPermGroupIcon(permGroup: String) =
+ 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 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(
setOneTime: Boolean,
confirmDialog: ConfirmDialogShowingFragment,
@@ -723,42 +894,42 @@ class AppPermissionViewModel(
val (iconId, titleId, messageId) = when {
targetSdk < Build.VERSION_CODES.Q && aural && allow ->
Triple(
- R.drawable.perm_group_storage,
+ 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(
- R.drawable.perm_group_storage,
+ 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(
- R.drawable.perm_group_storage,
+ 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(
- R.drawable.perm_group_storage,
+ 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(
- R.drawable.perm_group_visual,
+ 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(
- R.drawable.perm_group_visual,
+ 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(
- R.drawable.perm_group_aural,
+ 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(
- R.drawable.perm_group_aural,
+ auralPermGroupIcon,
R.string.media_confirm_dialog_title_q_to_s_visual_deny,
R.string.media_confirm_dialog_message_q_to_s_visual_deny)
else ->
@@ -944,10 +1115,21 @@ class AppPermissionViewModel(
logAppPermissionFragmentActionReported(changeId, newPermission, buttonPressed)
PermissionDecisionStorageImpl.recordPermissionDecision(app.applicationContext,
packageName, permGroupName, newPermission.isGrantedIncludingAppOp)
+ PermissionChangeStorageImpl.recordPermissionChange(packageName)
}
}
}
+ private fun logAppPermissionFragmentActionReportedForPermissionGroup(
+ changeId: Long,
+ group: LightAppPermGroup,
+ buttonPressed: Int
+ ) {
+ group.permissions.forEach { (_, permission) ->
+ logAppPermissionFragmentActionReported(changeId, permission, buttonPressed)
+ }
+ }
+
private fun logAppPermissionFragmentActionReported(
changeId: Long,
permission: LightPermission,
@@ -963,16 +1145,41 @@ class AppPermissionViewModel(
permission.flags + " buttonPressed=$buttonPressed")
}
- /**
- * Logs information about this AppPermissionGroup and view session
- */
+ /** Logs information about this AppPermissionGroup and view session */
fun logAppPermissionFragmentViewed() {
val uid = KotlinUtils.getPackageUid(app, packageName, user) ?: return
- PermissionControllerStatsLog.write(APP_PERMISSION_FRAGMENT_VIEWED, sessionId,
- uid, packageName, permGroupName)
- Log.v(LOG_TAG, "AppPermission fragment viewed with sessionId=$sessionId uid=" +
- "$uid packageName=$packageName" +
- "permGroupName=$permGroupName")
+
+ val permissionRationaleShown = showPermissionRationaleLiveData.value ?: false
+ PermissionControllerStatsLog.write(
+ APP_PERMISSION_FRAGMENT_VIEWED,
+ sessionId,
+ uid,
+ packageName,
+ permGroupName,
+ permissionRationaleShown)
+ Log.v(
+ LOG_TAG,
+ "AppPermission fragment viewed with sessionId=$sessionId uid=$uid " +
+ "packageName=$packageName permGroupName=$permGroupName " +
+ "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
+ */
+ private fun isPartialStorageGrant(group: LightAppPermGroup): Boolean {
+ if (!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)
+ }
}
}
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 d52f5ca57..0680ffcd2 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt
@@ -15,13 +15,15 @@
*/
@file:Suppress("DEPRECATION")
-package com.android.permissioncontroller.permission.ui.model.v31
+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.READ_MEDIA_VISUAL
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Application
@@ -31,26 +33,34 @@ import android.content.pm.PackageManager
import android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED
import android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED
import android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET
+import android.health.connect.HealthConnectManager.ACTION_REQUEST_HEALTH_PERMISSIONS
+import android.health.connect.HealthConnectManager.isHealthPermission
+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
import com.android.modules.utils.build.SdkLevel
+import com.android.permission.safetylabel.SafetyLabel
import com.android.permissioncontroller.Constants
import com.android.permissioncontroller.DeviceUtils
-import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.PermissionControllerStatsLog
import com.android.permissioncontroller.PermissionControllerStatsLog.GRANT_PERMISSIONS_ACTIVITY_BUTTON_ACTIONS
+import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_RESTRICTED_PERMISSION
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED
+import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__PHOTOS_SELECTED
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_IN_SETTINGS
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE
@@ -63,24 +73,32 @@ 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.model.AppPermissionGroup
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.service.PermissionChangeStorageImpl
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
@@ -89,21 +107,31 @@ import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity.N
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.GrantPermissionsActivity.PERMISSION_TO_BIT_SHIFT
-import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler
+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
+import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.DENIED_MORE
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.GrantPermissionsViewHandler.GRANTED_ONE_TIME
+import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler.GRANTED_USER_SELECTED
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.handheld.v31.getDefaultPrecision
-import com.android.permissioncontroller.permission.ui.handheld.v31.isLocationAccuracyEnabled
-import com.android.permissioncontroller.permission.utils.AdminRestrictedPermissionsUtils
+import com.android.permissioncontroller.permission.ui.v34.PermissionRationaleActivity
+import com.android.permissioncontroller.permission.utils.v31.AdminRestrictedPermissionsUtils
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.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.v34.SafetyLabelUtils
/**
* ViewModel for the GrantPermissionsActivity. Tracks all permission groups that are affected by
@@ -126,11 +154,18 @@ class GrantPermissionsViewModel(
private val LOG_TAG = GrantPermissionsViewModel::class.java.simpleName
private val user = Process.myUserHandle()
private val packageInfoLiveData = LightPackageInfoLiveData[packageName, user]
+ private val safetyLabelInfoLiveData =
+ 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 var isFirstTimeRequestingFineAndCoarse: Boolean = false
private var autoGrantNotifier: AutoGrantPermissionsNotifier? = null
private fun getAutoGrantNotifier(): AutoGrantPermissionsNotifier {
@@ -158,7 +193,8 @@ class GrantPermissionsViewModel(
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 sendToSettingsImmediately: Boolean = false,
+ val openPhotoPicker: Boolean = false,
) {
val groupName = groupInfo.name
}
@@ -176,12 +212,18 @@ class GrantPermissionsViewModel(
init {
addSource(packagePermissionsLiveData) { onPackageLoaded() }
addSource(packageInfoLiveData) { onPackageLoaded() }
+ if (safetyLabelInfoLiveData != null) {
+ addSource(safetyLabelInfoLiveData) { onPackageLoaded() }
+ }
+
// Load package state, if available
onPackageLoaded()
}
private fun onPackageLoaded() {
- if (packageInfoLiveData.isStale || packagePermissionsLiveData.isStale) {
+ if (packageInfoLiveData.isStale ||
+ packagePermissionsLiveData.isStale ||
+ (safetyLabelInfoLiveData != null && safetyLabelInfoLiveData.isStale)) {
return
}
@@ -208,7 +250,7 @@ class GrantPermissionsViewModel(
}
unfilteredAffectedPermissions = allAffectedPermissions.toList()
- getAppPermGroups(groups.toMutableMap().apply {
+ setAppPermGroupsLiveDatas(groups.toMutableMap().apply {
remove(PackagePermissionsLiveData.NON_RUNTIME_NORMAL_PERMS)
})
@@ -218,7 +260,7 @@ class GrantPermissionsViewModel(
}
}
- private fun getAppPermGroups(groups: Map<String, List<String>>) {
+ private fun setAppPermGroupsLiveDatas(groups: Map<String, List<String>>) {
val requestedGroups = groups.filter { (_, perms) ->
perms.any { it in unfilteredAffectedPermissions }
@@ -257,14 +299,11 @@ class GrantPermissionsViewModel(
val states = groupStates.filter { it.key.first == groupName }
if (states.isNotEmpty()) {
- // some requests might have been granted, check for that
- // TODO(b/205888750): remove isRuntimePermReview line once confident in
- // REVIEW_REQUIRED flag setting
for ((key, state) in states) {
val allAffectedGranted = state.affectedPermissions.all { perm ->
appPermGroup.permissions[perm]?.isGrantedIncludingAppOp == true &&
appPermGroup.permissions[perm]?.isRevokeWhenRequested == false
- } && !appPermGroup.isRuntimePermReviewRequired
+ }
if (allAffectedGranted) {
groupStates[key]!!.state = STATE_ALLOWED
}
@@ -278,10 +317,10 @@ class GrantPermissionsViewModel(
groupStates = getRequiredGroupStates(
appPermGroupLiveDatas.mapNotNull { it.value.value })
}
- getRequestInfosFromGroupStates()
+ setRequestInfosFromGroupStates()
}
- private fun getRequestInfosFromGroupStates() {
+ private fun setRequestInfosFromGroupStates() {
val requestInfos = mutableListOf<RequestInfo>()
for ((key, groupState) in groupStates) {
val groupInfo = groupState.group.permGroupInfo
@@ -322,12 +361,37 @@ class GrantPermissionsViewModel(
buttonVisibilities[ALLOW_BUTTON] = true
buttonVisibilities[DENY_BUTTON] = true
buttonVisibilities[ALLOW_ONE_TIME_BUTTON] =
- Utils.supportsOneTimeGrant(groupName)
+ 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 (groupState.group.packageInfo.targetSdkVersion >=
+
+ 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))
+ 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) {
@@ -374,8 +438,17 @@ class GrantPermissionsViewModel(
}
} else if (needBgPermissions) {
// Case: sdk >= R, BG/FG permission requesting BG only
- requestInfos.add(RequestInfo(
- groupInfo, sendToSettingsImmediately = true))
+ 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
@@ -444,7 +517,7 @@ class GrantPermissionsViewModel(
// 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) {
+ packageInfo.targetSdkVersion >= Build.VERSION_CODES.S) {
if (needFgPermissions) {
locationVisibilities[LOCATION_ACCURACY_LAYOUT] = true
if (fgState != null &&
@@ -466,11 +539,6 @@ class GrantPermissionsViewModel(
value = null
return
}
- if (coarseLocationPerm?.isOneTime == false &&
- !coarseLocationPerm.isUserSet &&
- !coarseLocationPerm.isUserFixed) {
- isFirstTimeRequestingFineAndCoarse = true
- }
// Normal flow with both Coarse and Fine locations
locationVisibilities[DIALOG_WITH_BOTH_LOCATIONS] = true
// Steps to decide location accuracy default state
@@ -508,7 +576,8 @@ class GrantPermissionsViewModel(
continue
}
// If app is <T and requests STORAGE, grant dialogs has special text
- if (groupState.group.permGroupName in Utils.STORAGE_SUPERGROUP_PERMISSIONS) {
+ 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) {
@@ -517,6 +586,11 @@ class GrantPermissionsViewModel(
}
}
+ val safetyLabel = safetyLabelInfoLiveData?.value?.safetyLabel
+ val showPermissionRationale =
+ shouldShowPermissionRationale(safetyLabel, groupState.group.permGroupName)
+ buttonVisibilities[LINK_TO_PERMISSION_RATIONALE] = showPermissionRationale
+
requestInfos.add(RequestInfo(
groupInfo,
buttonVisibilities,
@@ -524,17 +598,8 @@ class GrantPermissionsViewModel(
message,
detailMessage))
}
- requestInfos.sortWith(Comparator { rhs, lhs ->
- val rhsHasOneTime = rhs.buttonVisibilities[ALLOW_ONE_TIME_BUTTON]
- val lhsHasOneTime = lhs.buttonVisibilities[ALLOW_ONE_TIME_BUTTON]
- if (rhsHasOneTime && !lhsHasOneTime) {
- -1
- } else if (!rhsHasOneTime && lhsHasOneTime) {
- 1
- } else {
- rhs.groupName.compareTo(lhs.groupName)
- }
- })
+
+ sortPermissionGroups(requestInfos)
value = if (requestInfos.any { it.sendToSettingsImmediately } &&
requestInfos.size > 1) {
@@ -547,6 +612,35 @@ class GrantPermissionsViewModel(
}
}
+ 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]
+ if (rhsHasOneTime && !lhsHasOneTime) {
+ -1
+ } else if ((!rhsHasOneTime && lhsHasOneTime) ||
+ isHealthPermissionGroup(rhs.groupName)
+ ) {
+ 1
+ } else {
+ rhs.groupName.compareTo(lhs.groupName)
+ }
+ }
+ }
+
+ private fun shouldShowPermissionRationale(
+ safetyLabel: SafetyLabel?,
+ permissionGroupName: String?
+ ): Boolean {
+ if (safetyLabel == null || permissionGroupName == null) {
+ return false
+ }
+
+ val purposes = SafetyLabelUtils.getSafetyLabelSharingPurposesForGroup(safetyLabel,
+ permissionGroupName)
+ return purposes.isNotEmpty()
+ }
+
/**
* Converts a list of LightAppPermGroups into a list of GroupStates
*/
@@ -653,6 +747,10 @@ class GrantPermissionsViewModel(
return false
}
+ if (HEALTH_PERMISSION_GROUP == group.permGroupName) {
+ return !(group.permissions[perm]?.isUserFixed ?: true)
+ }
+
val subGroup = if (perm in group.backgroundPermNames) {
group.background
} else {
@@ -674,6 +772,11 @@ class GrantPermissionsViewModel(
// 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)
@@ -701,6 +804,17 @@ class GrantPermissionsViewModel(
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
@@ -723,25 +837,14 @@ class GrantPermissionsViewModel(
return STATE_SKIPPED
}
- // TODO(b/205888750): remove isRuntimePermReview line once confident in
- // REVIEW_REQUIRED flag setting
if ((isBackground && group.background.isGrantedExcludingRWROrAllRWR ||
!isBackground && group.foreground.isGrantedExcludingRWROrAllRWR) &&
- !group.isRuntimePermReviewRequired) {
- // 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 STATE_UNKNOWN
- }
-
+ canAutoGrantWholeGroup(group)) {
if (group.permissions[perm]?.isGrantedIncludingAppOp == false) {
if (isBackground) {
- KotlinUtils.grantBackgroundRuntimePermissions(app, group, listOf(perm))
+ grantBackgroundRuntimePermissions(app, group, listOf(perm))
} else {
- KotlinUtils.grantForegroundRuntimePermissions(app, group, listOf(perm),
- group.isOneTime)
+ 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))
@@ -754,15 +857,46 @@ class GrantPermissionsViewModel(
} else {
STATE_ALLOWED
}
- } else if (group.isRuntimePermReviewRequired) {
- // TODO(b/205888750): uncomment line if it is deemed necessary to deal with bad flag
- // state
- // KotlinUtils.setGroupFlags(app, group, FLAG_PERMISSION_REVIEW_REQUIRED to false,
- // filterPermissions = listOf(perm))
}
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)
+ }
+ }
+
private fun getStateFromPolicy(perm: String, group: LightAppPermGroup): Int {
val isBackground = perm in group.backgroundPermNames
var skipGroup = false
@@ -772,9 +906,9 @@ class GrantPermissionsViewModel(
if (AdminRestrictedPermissionsUtils.mayAdminGrantPermission(
app, perm, user.identifier)) {
if (isBackground) {
- KotlinUtils.grantBackgroundRuntimePermissions(app, group, listOf(perm))
+ grantBackgroundRuntimePermissions(app, group, listOf(perm))
} else {
- KotlinUtils.grantForegroundRuntimePermissions(app, group, listOf(perm))
+ 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,
@@ -834,9 +968,9 @@ class GrantPermissionsViewModel(
// If this is a legacy app, and a storage group is requested: request all storage groups
if (!alreadyRequestedStorageGroupsIfNeeded &&
- groupName in Utils.STORAGE_SUPERGROUP_PERMISSIONS &&
+ groupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS &&
packageInfo.targetSdkVersion <= Build.VERSION_CODES.S_V2) {
- for (storageGroupName in Utils.STORAGE_SUPERGROUP_PERMISSIONS) {
+ for (storageGroupName in PermissionMapping.STORAGE_SUPERGROUP_PERMISSIONS) {
val groupPerms = appPermGroupLiveDatas[storageGroupName]
?.value?.allPermissions?.keys?.toList()
onPermissionGrantResult(storageGroupName, groupPerms, result, true)
@@ -847,15 +981,18 @@ class GrantPermissionsViewModel(
val foregroundGroupState = groupStates[groupName to false]
val backgroundGroupState = groupStates[groupName to true]
when (result) {
- GrantPermissionsViewHandler.CANCELED -> {
+ 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
}
+ requestInfosLiveData.update()
return
}
GRANTED_ALWAYS -> {
@@ -882,7 +1019,7 @@ class GrantPermissionsViewModel(
doNotAskAgain = false)
}
}
- GrantPermissionsViewHandler.GRANTED_ONE_TIME -> {
+ GRANTED_ONE_TIME -> {
if (foregroundGroupState != null) {
onPermissionGrantResultSingleState(foregroundGroupState,
affectedForegroundPermissions, granted = true, isOneTime = true,
@@ -894,6 +1031,11 @@ class GrantPermissionsViewModel(
doNotAskAgain = false)
}
}
+ GRANTED_USER_SELECTED, DENIED_MORE -> {
+ if (foregroundGroupState != null) {
+ grantUserSelectedVisualGroupPermissions(foregroundGroupState)
+ }
+ }
DENIED -> {
if (foregroundGroupState != null) {
onPermissionGrantResultSingleState(foregroundGroupState,
@@ -921,6 +1063,38 @@ class GrantPermissionsViewModel(
}
}
+ private fun grantUserSelectedVisualGroupPermissions(groupState: GroupState) {
+ 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 }
+ // 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)
+ appPermGroup.setSelfRevoked()
+ appPermGroup.persistChanges(false, null, nonSelectedPerms.toSet())
+ } else {
+ 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)
+ }
+ groupState.state = STATE_ALLOWED
+ reportButtonClickResult(groupState, true,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__PHOTOS_SELECTED)
+ }
+
@SuppressLint("NewApi")
private fun onPermissionGrantResultSingleState(
groupState: GroupState,
@@ -941,11 +1115,11 @@ class GrantPermissionsViewModel(
PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED
}
if (groupState.isBackground) {
- KotlinUtils.grantBackgroundRuntimePermissions(app, groupState.group,
+ grantBackgroundRuntimePermissions(app, groupState.group,
groupState.affectedPermissions)
} else {
if (affectedForegroundPermissions == null) {
- KotlinUtils.grantForegroundRuntimePermissions(app, groupState.group,
+ 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)) {
@@ -953,7 +1127,7 @@ class GrantPermissionsViewModel(
app, groupState.group, true)
}
} else {
- val newGroup = KotlinUtils.grantForegroundRuntimePermissions(app,
+ val newGroup = grantForegroundRuntimePermissions(app,
groupState.group, affectedForegroundPermissions, isOneTime)
if (!isOneTime || newGroup.isOneTime) {
KotlinUtils.setFlagsWhenLocationAccuracyChanged(app, newGroup,
@@ -964,16 +1138,16 @@ class GrantPermissionsViewModel(
groupState.state = STATE_ALLOWED
} else {
if (groupState.isBackground) {
- KotlinUtils.revokeBackgroundRuntimePermissions(app, groupState.group,
+ revokeBackgroundRuntimePermissions(app, groupState.group,
userFixed = doNotAskAgain, filterPermissions = groupState.affectedPermissions)
} else {
if (affectedForegroundPermissions == null ||
affectedForegroundPermissions.contains(ACCESS_COARSE_LOCATION)) {
- KotlinUtils.revokeForegroundRuntimePermissions(app, groupState.group,
+ revokeForegroundRuntimePermissions(app, groupState.group,
userFixed = doNotAskAgain,
filterPermissions = groupState.affectedPermissions, oneTime = isOneTime)
} else {
- KotlinUtils.revokeForegroundRuntimePermissions(app, groupState.group,
+ revokeForegroundRuntimePermissions(app, groupState.group,
userFixed = doNotAskAgain,
filterPermissions = affectedForegroundPermissions, oneTime = isOneTime)
}
@@ -985,11 +1159,16 @@ class GrantPermissionsViewModel(
}
groupState.state = STATE_DENIED
}
+ reportButtonClickResult(groupState, granted, result)
+ }
+
+ private fun reportButtonClickResult(groupState: GroupState, granted: Boolean, result: Int) {
reportRequestResult(groupState.affectedPermissions, result)
// group state has changed, reload liveData
requestInfosLiveData.update()
PermissionDecisionStorageImpl.recordPermissionDecision(app.applicationContext,
packageName, groupState.group.permGroupName, granted)
+ PermissionChangeStorageImpl.recordPermissionChange(packageName)
if (granted) {
startDrivingDecisionReminderServiceIfNecessary(groupState.group.permGroupName)
}
@@ -1052,14 +1231,19 @@ 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")
+ "isImplicit=$isImplicit result=$result " +
+ "isPermissionRationaleShown=$isPermissionRationaleShown")
PermissionControllerStatsLog.write(
- PermissionControllerStatsLog.PERMISSION_GRANT_REQUEST_RESULT_REPORTED, sessionId,
- packageInfo.uid, packageName, permission, isImplicit, result)
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED, sessionId,
+ packageInfo.uid, packageName, permission, isImplicit, result,
+ isPermissionRationaleShown)
}
/**
@@ -1096,6 +1280,29 @@ class GrantPermissionsViewModel(
}
}
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ private fun isHealthPermissionGroup(permGroupName: String): Boolean {
+ return SdkLevel.isAtLeastU() && HEALTH_PERMISSION_GROUP.equals(permGroupName)
+ }
+
+ 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)
+ activity.startActivityForResult(intent, APP_PERMISSION_REQUEST_CODE)
+ }
+ }
+
/**
* Send the user directly to the AppPermissionFragment. Used for R+ apps.
*
@@ -1104,7 +1311,6 @@ class GrantPermissionsViewModel(
*/
fun sendDirectlyToSettings(activity: Activity, groupName: String) {
if (activityResultCallback == null) {
- startAppPermissionFragment(activity, groupName)
activityResultCallback = Consumer { data ->
if (data?.getStringExtra(EXTRA_RESULT_PERMISSION_INTERACTED) == null) {
// User didn't interact, count against rate limit
@@ -1123,7 +1329,38 @@ class GrantPermissionsViewModel(
// Update our liveData now that there is a new skipped group
requestInfosLiveData.update()
}
+ startAppPermissionFragment(activity, groupName)
+ }
+ }
+
+ fun openPhotoPicker(activity: Activity, result: Int) {
+ if (activityResultCallback != null) {
+ return
+ }
+ if (groupStates[READ_MEDIA_VISUAL to false]?.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)
}
/**
@@ -1145,6 +1382,34 @@ class GrantPermissionsViewModel(
}
}
+ /**
+ * 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()
+ }
+ }
+ 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)
@@ -1234,32 +1499,31 @@ class GrantPermissionsViewModel(
groupName: String?,
selectedPrecision: Int,
clickedButton: Int,
- presentedButtons: Int
+ presentedButtons: Int,
+ isPermissionRationaleShown: Boolean
) {
if (groupName == null) {
return
}
+
if (!requestInfosLiveData.isInitialized || !packageInfoLiveData.isInitialized) {
Log.wtf(LOG_TAG, "Logged buttons presented and clicked permissionGroupName=" +
"$groupName package=$packageName presentedButtons=$presentedButtons " +
- "clickedButton=$clickedButton sessionId=$sessionId, but requests were not yet" +
+ "clickedButton=$clickedButton isPermissionRationaleShown=" +
+ "$isPermissionRationaleShown sessionId=$sessionId, but requests were not yet" +
"initialized", IllegalStateException())
return
}
- var selectedLocations = 0
- // log permissions if it's 1) first time requesting both locations OR 2) upgrade flow
- if (isFirstTimeRequestingFineAndCoarse ||
- selectedPrecision ==
- 1 shl PERMISSION_TO_BIT_SHIFT[ACCESS_FINE_LOCATION]!!) {
- selectedLocations = selectedPrecision
- }
+
PermissionControllerStatsLog.write(GRANT_PERMISSIONS_ACTIVITY_BUTTON_ACTIONS,
groupName, packageInfo.uid, packageName, presentedButtons, clickedButton, sessionId,
- packageInfo.targetSdkVersion, selectedLocations)
+ packageInfo.targetSdkVersion, selectedPrecision,
+ isPermissionRationaleShown)
Log.v(LOG_TAG, "Logged buttons presented and clicked permissionGroupName=" +
- "$groupName uid=${packageInfo.uid} selectedLocations=$selectedLocations " +
+ "$groupName uid=${packageInfo.uid} selectedPrecision=$selectedPrecision " +
"package=$packageName presentedButtons=$presentedButtons " +
- "clickedButton=$clickedButton sessionId=$sessionId " +
+ "clickedButton=$clickedButton isPermissionRationaleShown=" +
+ "$isPermissionRationaleShown sessionId=$sessionId " +
"targetSdk=${packageInfo.targetSdkVersion}")
}
@@ -1271,7 +1535,8 @@ class GrantPermissionsViewModel(
}
companion object {
- private const val APP_PERMISSION_REQUEST_CODE = 1
+ const val APP_PERMISSION_REQUEST_CODE = 1
+ const val PHOTO_PICKER_REQUEST_CODE = 2
private const val STATE_UNKNOWN = 0
private const val STATE_ALLOWED = 1
private const val STATE_DENIED = 2
@@ -1291,27 +1556,24 @@ class GrantPermissionsViewModel(
FG_COARSE_LOCATION_MESSAGE,
STORAGE_SUPERGROUP_MESSAGE_Q_TO_S,
STORAGE_SUPERGROUP_MESSAGE_PRE_Q,
+ MORE_PHOTOS_MESSAGE,
}
- fun filterNotificationPermissionIfNeededSync(
- packageName: String,
- permissions: Array<String>?
- ): Array<String>? {
- if (permissions == null) {
- return null
- }
-
- try {
- val targetSdk = PermissionControllerApplication.get().packageManager
- .getPackageInfo(packageName, 0).applicationInfo.targetSdkVersion
- if (targetSdk > Build.VERSION_CODES.S_V2) {
- return permissions
- }
- } catch (e: PackageManager.NameNotFoundException) {
- return permissions
- }
-
- return permissions.toList().filter { it != POST_NOTIFICATIONS }.toTypedArray()
+ /**
+ * 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>()
}
}
}
@@ -1325,13 +1587,13 @@ class GrantPermissionsViewModel(
class GrantPermissionsViewModelFactory(
private val app: Application,
private val packageName: String,
- private val requestedPermissions: Array<String>,
+ private val requestedPermissions: 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.toList(),
+ return GrantPermissionsViewModel(app, packageName, requestedPermissions,
sessionId, savedState) as T
}
}
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 682ec108f..e3ddab925 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageStandardPermissionsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManageStandardPermissionsViewModel.kt
@@ -19,10 +19,11 @@ package com.android.permissioncontroller.permission.ui.model
import android.Manifest
import android.app.Application
import android.content.Intent
+import android.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.lifecycle.AndroidViewModel
-import androidx.lifecycle.Transformations
+import androidx.lifecycle.map
import androidx.navigation.fragment.findNavController
import com.android.permissioncontroller.R
import com.android.permissioncontroller.permission.data.PermGroupsPackagesLiveData
@@ -47,9 +48,7 @@ class ManageStandardPermissionsViewModel(
val uiDataLiveData = PermGroupsPackagesUiInfoLiveData(app,
StandardPermGroupNamesLiveData)
val numCustomPermGroups = NumCustomPermGroupsWithPackagesLiveData()
- val numAutoRevoked = Transformations.map(unusedAutoRevokePackagesLiveData) {
- it?.size ?: 0
- }
+ val numAutoRevoked = unusedAutoRevokePackagesLiveData.map { it?.size ?: 0 }
/**
* Navigate to the Custom Permissions screen
@@ -73,6 +72,11 @@ class ManageStandardPermissionsViewModel(
Utils.navigateToNotificationSettings(fragment.context!!)
return
}
+ if (Utils.isHealthPermissionUiEnabled() &&
+ groupName == HEALTH_PERMISSION_GROUP) {
+ Utils.navigateToHealthConnectSettings(fragment.context!!)
+ return
+ }
fragment.findNavController().navigateSafe(R.id.manage_to_perm_apps, args)
}
@@ -99,4 +103,4 @@ class NumCustomPermGroupsWithPackagesLiveData() :
override fun onUpdate() {
value = customPermGroupPackages.value?.size ?: 0
}
-} \ No newline at end of file
+}
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 692f92795..114b8e045 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt
@@ -39,25 +39,25 @@ import androidx.savedstate.SavedStateRegistryOwner
import com.android.modules.utils.build.SdkLevel
import com.android.permissioncontroller.PermissionControllerStatsLog
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__ALLOWED
-import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__UNDEFINED
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__ALLOWED_FOREGROUND
import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__DENIED
+import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__UNDEFINED
import com.android.permissioncontroller.R
import com.android.permissioncontroller.permission.data.AllPackageInfosLiveData
import com.android.permissioncontroller.permission.data.FullStoragePermissionAppsLiveData
import com.android.permissioncontroller.permission.data.FullStoragePermissionAppsLiveData.FullStoragePackageState
import com.android.permissioncontroller.permission.data.SinglePermGroupPackagesUiInfoLiveData
-import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage
import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData
import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGroupUiInfo.PermGrantState
+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.v31.is7DayToggleEnabled
import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel.Companion.CREATION_LOGGED_KEY
import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel.Companion.HAS_SYSTEM_APPS_KEY
import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel.Companion.SHOULD_SHOW_SYSTEM_KEY
import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel.Companion.SHOW_ALWAYS_ALLOWED
import com.android.permissioncontroller.permission.utils.KotlinUtils.getPackageUid
+import com.android.permissioncontroller.permission.utils.KotlinUtils.is7DayToggleEnabled
import com.android.permissioncontroller.permission.utils.LocationUtils
import com.android.permissioncontroller.permission.utils.Utils
import com.android.permissioncontroller.permission.utils.navigateSafe
@@ -170,8 +170,8 @@ class PermissionAppsViewModel(
}
}
- inner class CategorizedAppsLiveData(groupName: String)
- : MediatorLiveData<@kotlin.jvm.JvmSuppressWildcards
+ inner class CategorizedAppsLiveData(groupName: String) :
+ MediatorLiveData<@kotlin.jvm.JvmSuppressWildcards
Map<Category, List<Pair<String, UserHandle>>>>() {
private val packagesUiInfoLiveData = SinglePermGroupPackagesUiInfoLiveData[groupName]
@@ -464,13 +464,16 @@ class PermissionAppsViewModelFactory(
owner: SavedStateRegistryOwner,
defaultArgs: Bundle
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
-
- override fun <T : ViewModel> create(p0: String, p1: Class<T>, state: SavedStateHandle): T {
- state.set(SHOULD_SHOW_SYSTEM_KEY, state.get<Boolean>(SHOULD_SHOW_SYSTEM_KEY) ?: false)
- state.set(HAS_SYSTEM_APPS_KEY, state.get<Boolean>(HAS_SYSTEM_APPS_KEY) ?: true)
- state.set(SHOW_ALWAYS_ALLOWED, state.get<Boolean>(SHOW_ALWAYS_ALLOWED) ?: false)
- state.set(CREATION_LOGGED_KEY, state.get<Boolean>(CREATION_LOGGED_KEY) ?: false)
+ override fun <T : ViewModel> create(
+ key: String,
+ modelClass: Class<T>,
+ handle: SavedStateHandle
+ ): T {
+ handle.set(SHOULD_SHOW_SYSTEM_KEY, handle.get<Boolean>(SHOULD_SHOW_SYSTEM_KEY) ?: false)
+ 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(state, app, groupName) as T
+ 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 94d0df0d5..4e1fc1861 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ReviewPermissionsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ReviewPermissionsViewModel.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.ui.model.v33
+package com.android.permissioncontroller.permission.ui.model
import android.app.Application
import android.content.Context
@@ -32,6 +32,7 @@ import com.android.permissioncontroller.permission.data.PackagePermissionsLiveDa
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.PermissionMapping
import com.android.permissioncontroller.permission.utils.Utils
import com.android.permissioncontroller.permission.utils.navigateSafe
import com.android.settingslib.RestrictedLockUtils
@@ -99,7 +100,8 @@ class ReviewPermissionsViewModel(
}
val isPlatformPermission = group.packageName == Utils.OS_PKG
// Show legacy permissions only if the user chose that.
- return !(isPlatformPermission && !Utils.isModernPermissionGroup(group.permGroupName))
+ return !(isPlatformPermission &&
+ !PermissionMapping.isPlatformPermissionGroup(group.permGroupName))
}
fun isPackageUpdated(): Boolean {
@@ -324,4 +326,4 @@ class ReviewPermissionViewModelFactory(
@Suppress("UNCHECKED_CAST")
return ReviewPermissionsViewModel(app, packageInfo = packageInfo) as T
}
-} \ No newline at end of file
+}
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 be59157af..3c3f347a4 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/UnusedAppsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/UnusedAppsViewModel.kt
@@ -18,6 +18,7 @@
package com.android.permissioncontroller.permission.ui.model
import android.app.Application
+import android.app.usage.UsageStats
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
@@ -34,16 +35,20 @@ import com.android.permissioncontroller.PermissionControllerStatsLog.AUTO_REVOKE
import com.android.permissioncontroller.PermissionControllerStatsLog.AUTO_REVOKE_FRAGMENT_APP_VIEWED
import com.android.permissioncontroller.PermissionControllerStatsLog.AUTO_REVOKE_FRAGMENT_APP_VIEWED__AGE__NEWER_BUCKET
import com.android.permissioncontroller.PermissionControllerStatsLog.AUTO_REVOKE_FRAGMENT_APP_VIEWED__AGE__OLDER_BUCKET
+import com.android.permissioncontroller.hibernation.lastTimePackageUsed
import com.android.permissioncontroller.permission.data.AllPackageInfosLiveData
import com.android.permissioncontroller.permission.data.SmartAsyncMediatorLiveData
import com.android.permissioncontroller.permission.data.UsageStatsLiveData
import com.android.permissioncontroller.permission.data.getUnusedPackages
+import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
import com.android.permissioncontroller.permission.utils.IPC
import com.android.permissioncontroller.permission.utils.Utils
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.days
+import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
-import java.util.concurrent.TimeUnit.DAYS
/**
* UnusedAppsViewModel for the AutoRevokeFragment. Has a livedata which provides all unused apps,
@@ -52,18 +57,31 @@ import java.util.concurrent.TimeUnit.DAYS
class UnusedAppsViewModel(private val app: Application, private val sessionId: Long) : ViewModel() {
companion object {
- private val SIX_MONTHS_MILLIS = DAYS.toMillis(180)
+ private val MAX_UNUSED_PERIOD_MILLIS =
+ UnusedPeriod.allPeriods.maxBy(UnusedPeriod::duration).duration.inWholeMilliseconds
private val LOG_TAG = AppPermissionViewModel::class.java.simpleName
}
- enum class Months(val value: String) {
- THREE("three_months"),
- SIX("six_months");
+ enum class UnusedPeriod(val duration: Duration) {
+ ONE_MONTH(30.days),
+ THREE_MONTHS(90.days),
+ SIX_MONTHS(180.days);
+
+ val months: Int = (duration.inWholeDays / 30).toInt()
+
+ fun isNewlyUnused(): Boolean {
+ return (this == ONE_MONTH) || (this == THREE_MONTHS)
+ }
companion object {
- @JvmStatic
- fun allMonths(): List<Months> {
- return listOf(THREE, SIX)
+
+ val allPeriods: List<UnusedPeriod> = values().toList()
+
+ // Find the longest period shorter than unused time
+ fun findLongestValidPeriod(durationInMs: Long): UnusedPeriod {
+ val duration = durationInMs.milliseconds
+ return UnusedPeriod.allPeriods.findLast { duration > it.duration }
+ ?: UnusedPeriod.allPeriods.first()
}
}
}
@@ -72,14 +90,17 @@ class UnusedAppsViewModel(private val app: Application, private val sessionId: L
val packageName: String,
val user: UserHandle,
val isSystemApp: Boolean,
- val revokedGroups: Set<String>
+ val revokedGroups: Set<String>,
)
- val unusedPackageCategoriesLiveData = object
- : SmartAsyncMediatorLiveData<Map<Months, List<UnusedPackageInfo>>>(
+ private data class PackageLastUsageTime(val packageName: String, val usageTime: Long)
+
+ val unusedPackageCategoriesLiveData =
+ object : SmartAsyncMediatorLiveData<Map<UnusedPeriod, List<UnusedPackageInfo>>>(
alwaysUpdateOnActive = false
) {
- private val usageStatsLiveData = UsageStatsLiveData[SIX_MONTHS_MILLIS]
+ // Get apps usage stats from the longest interesting period (MAX_UNUSED_PERIOD_MILLIS)
+ private val usageStatsLiveData = UsageStatsLiveData[MAX_UNUSED_PERIOD_MILLIS]
init {
addSource(getUnusedPackages()) {
@@ -97,74 +118,79 @@ class UnusedAppsViewModel(private val app: Application, private val sessionId: L
override suspend fun loadDataAndPostValue(job: Job) {
if (!getUnusedPackages().isInitialized ||
- !usageStatsLiveData.isInitialized || !AllPackageInfosLiveData.isInitialized) {
+ !usageStatsLiveData.isInitialized || !AllPackageInfosLiveData.isInitialized
+ ) {
return
}
val unusedApps = getUnusedPackages().value!!
Log.i(LOG_TAG, "Unused apps: $unusedApps")
- val overSixMonthApps = unusedApps.keys.toMutableSet()
- val categorizedApps = mutableMapOf<Months, MutableList<UnusedPackageInfo>>()
- categorizedApps[Months.THREE] = mutableListOf()
- categorizedApps[Months.SIX] = mutableListOf()
-
- // Get all packages which cannot be uninstalled.
- val systemApps = mutableListOf<Pair<String, UserHandle>>()
- for ((user, packageList) in AllPackageInfosLiveData.value!!) {
- systemApps.addAll(packageList.mapNotNull { packageInfo ->
- val key = packageInfo.packageName to user
- if (unusedApps.contains(key) &&
- (packageInfo.appFlags and ApplicationInfo.FLAG_SYSTEM) != 0) {
- key
- } else {
- null
- }
- })
+ val categorizedApps = mutableMapOf<UnusedPeriod, MutableList<UnusedPackageInfo>>()
+ for (period in UnusedPeriod.allPeriods) {
+ categorizedApps[period] = mutableListOf()
}
- val now = System.currentTimeMillis()
- for ((user, stats) in usageStatsLiveData.value!!) {
- for (stat in stats) {
- val statPackage = stat.packageName to user
- if (!unusedApps.contains(statPackage)) {
- continue
- }
-
- categorizedApps[Months.THREE]!!.add(
- UnusedPackageInfo(stat.packageName, user,
- systemApps.contains(statPackage), unusedApps[statPackage]!!))
- overSixMonthApps.remove(statPackage)
+ // 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())
}
- }
-
- // If we didn't find the stat for a package in our six month search, it is more than
- // 6 months old, or the app has never been opened.
- overSixMonthApps.forEach { (packageName, user) ->
- var installTime: Long = 0
- for (pI in AllPackageInfosLiveData.value!![user]!!) {
- if (pI.packageName == packageName) {
- installTime = pI.firstInstallTime
- }
+ val firstInstallDataUnusedApps =
+ extractUnusedAppsUsageData(AllPackageInfosLiveData.value!!, unusedApps)
+ { it: LightPackageInfo ->
+ PackageLastUsageTime(it.packageName, it.firstInstallTime)
}
- // Check if the app was installed less than six months ago, and never opened
- val months = if (now - installTime <= SIX_MONTHS_MILLIS) {
- Months.THREE
- } else {
- Months.SIX
- }
+ val now = System.currentTimeMillis()
+ unusedApps.keys.forEach { (packageName, user) ->
val userPackage = packageName to user
- categorizedApps[months]!!.add(
- UnusedPackageInfo(packageName, user, systemApps.contains(userPackage),
- unusedApps[userPackage]!!))
+
+ // 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)
}
}
- fun areUnusedPackagesLoaded(): Boolean {
- return getUnusedPackages().isInitialized
+ // Extract UserPackage information for unused system apps from source map.
+ private fun getUnusedSystemApps(
+ userPackages: Map<UserHandle, List<LightPackageInfo>>,
+ 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) }
+ }
+
+ /**
+ * Extract PackageLastUsageTime for unused apps from userPackages map. This method may be used
+ * for extracting different usage time (such as installation time or last opened time) from
+ * different Package structures
+ */
+ private fun <PackageData> extractUnusedAppsUsageData(
+ userPackages: Map<UserHandle, List<PackageData>>,
+ 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 }
+ .filterKeys { unusedApps.contains(it) }
}
fun navigateToAppInfo(packageName: String, user: UserHandle, sessionId: Long) {
@@ -196,8 +222,8 @@ class UnusedAppsViewModel(private val app: Application, private val sessionId: L
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,
@@ -208,8 +234,9 @@ class UnusedAppsViewModel(private val app: Application, private val sessionId: L
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) {
@@ -224,9 +251,11 @@ class UnusedAppsViewModel(private val app: Application, private val sessionId: L
}
}
+typealias UserPackage = Pair<String, UserHandle>
+
class UnusedAppsViewModelFactory(
private val app: Application,
- private val sessionId: Long
+ private val sessionId: Long,
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
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 b3442645d..db79165c3 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
@@ -61,9 +61,13 @@ object PermissionUsageControlPreferenceUtils {
if (count == 0) {
isEnabled = false
val permissionUsageSummaryNotUsed = if (show7Days) {
- R.string.permission_usage_preference_summary_not_used_7d
+ StringUtils.getIcuPluralsString(context,
+ R.string.permission_usage_preference_summary_not_used_in_past_n_days,
+ 7)
} else {
- R.string.permission_usage_preference_summary_not_used_24h
+ StringUtils.getIcuPluralsString(context,
+ R.string.permission_usage_preference_summary_not_used_in_past_n_hours,
+ 24)
}
setSummary(permissionUsageSummaryNotUsed)
} else if (SENSOR_DATA_PERMISSIONS.contains(groupName)) {
@@ -102,4 +106,4 @@ object PermissionUsageControlPreferenceUtils {
}
PermissionControllerStatsLog.write(PERMISSION_USAGE_FRAGMENT_INTERACTION, sessionId, act)
}
-} \ No newline at end of file
+}
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 e7de6c9d9..f77bfff3b 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
@@ -19,563 +19,715 @@ package com.android.permissioncontroller.permission.ui.model.v31
import android.Manifest
import android.app.AppOpsManager
+import android.app.AppOpsManager.OPSTR_PHONE_CALL_CAMERA
+import android.app.AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE
import android.app.Application
-import android.app.LoaderManager
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.res.Resources
-import android.graphics.drawable.Drawable
import android.os.Build
+import android.os.Bundle
import android.os.UserHandle
-import android.text.format.DateFormat
import androidx.annotation.RequiresApi
+import androidx.lifecycle.AbstractSavedStateViewModelFactory
+import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-import androidx.preference.Preference
-import androidx.preference.PreferenceCategory
-import androidx.preference.PreferenceScreen
+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.model.AppPermissionGroup
-import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage
-import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage.GroupUsage
-import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage.GroupUsage.AttributionLabelledGroupUsage
-import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage.TimelineUsage
-import com.android.permissioncontroller.permission.model.v31.PermissionUsages
-import com.android.permissioncontroller.permission.model.legacy.PermissionApps.PermissionApp
+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.v31.AllLightHistoricalPackageOpsLiveData
+import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
+import com.android.permissioncontroller.permission.model.livedatatypes.v31.AppPermissionId
+import com.android.permissioncontroller.permission.model.livedatatypes.v31.LightHistoricalPackageOps
+import com.android.permissioncontroller.permission.model.livedatatypes.v31.LightHistoricalPackageOps.AppPermissionDiscreteAccesses
+import com.android.permissioncontroller.permission.model.livedatatypes.v31.LightHistoricalPackageOps.AttributedAppPermissionDiscreteAccesses
+import com.android.permissioncontroller.permission.model.livedatatypes.v31.LightHistoricalPackageOps.Companion.NO_ATTRIBUTION_TAG
+import com.android.permissioncontroller.permission.model.livedatatypes.v31.LightHistoricalPackageOps.DiscreteAccess
import com.android.permissioncontroller.permission.ui.handheld.v31.getDurationUsedStr
-import com.android.permissioncontroller.permission.ui.handheld.v31.is7DayToggleEnabled
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.SubattributionUtils
+import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.utils.Utils
-import java.time.Clock
+import com.android.permissioncontroller.permission.utils.v31.SubattributionUtils
import java.time.Instant
-import java.time.ZonedDateTime
-import java.time.temporal.ChronoUnit
import java.util.Objects
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeUnit.DAYS
-import java.util.concurrent.atomic.AtomicBoolean
-import java.util.concurrent.atomic.AtomicReference
-import java.util.stream.Collectors
-import kotlin.math.max
-/**
- * View model for the permission details fragment.
- */
+/** [ViewModel] for the Permission Usage Details page. */
@RequiresApi(Build.VERSION_CODES.S)
class PermissionUsageDetailsViewModel(
val application: Application,
- val roleManager: RoleManager,
- private val filterGroup: String,
- val sessionId: Long
+ private val state: SavedStateHandle,
+ private val permissionGroup: String,
) : ViewModel() {
- companion object {
- private const val ONE_HOUR_MS = 3_600_000
- private const val ONE_MINUTE_MS = 60_000
- private const val CLUSTER_MINUTES_APART = 1
- private val TIME_7_DAYS_DURATION: Long = DAYS.toMillis(7)
- private val TIME_24_HOURS_DURATION: Long = DAYS.toMillis(1)
- private val ALLOW_CLUSTERING_PERMISSION_GROUPS = listOf(
- Manifest.permission_group.LOCATION,
- Manifest.permission_group.CAMERA,
- Manifest.permission_group.MICROPHONE
- )
+ val allLightHistoricalPackageOpsLiveData =
+ AllLightHistoricalPackageOpsLiveData(application, opNames)
+ private val appPermGroupUiInfoLiveDataList =
+ mutableMapOf<AppPermissionId, AppPermGroupUiInfoLiveData>()
+ private val lightPackageInfoLiveDataMap =
+ mutableMapOf<Pair<String, UserHandle>, LightPackageInfoLiveData>()
+ val showSystemLiveData = state.getLiveData(SHOULD_SHOW_SYSTEM_KEY, false)
+ val show7DaysLiveData = state.getLiveData(SHOULD_SHOW_7_DAYS_KEY, false)
+
+ private val roleManager =
+ Utils.getSystemServiceSafe(application.applicationContext, RoleManager::class.java)
+
+ /** Updates whether system app permissions usage should be displayed in the UI. */
+ fun updateShowSystemAppsToggle(showSystem: Boolean) {
+ if (showSystem != state[SHOULD_SHOW_SYSTEM_KEY]) {
+ state[SHOULD_SHOW_SYSTEM_KEY] = showSystem
+ }
}
- private val filterTimes = mutableListOf<TimeFilterItem>()
-
- // Truncate to midnight in current timezone.
- private val midnightToday = ZonedDateTime.now().truncatedTo(ChronoUnit.DAYS)
- .toEpochSecond() * 1000L
- private val midnightYesterday = ZonedDateTime.now().minusDays(1).truncatedTo(ChronoUnit.DAYS)
- .toEpochSecond() * 1000L
+ /** Updates whether 7 days usage or 1 day usage should be displayed in the UI. */
+ fun updateShow7DaysToggle(show7Days: Boolean) {
+ if (show7Days != state[SHOULD_SHOW_7_DAYS_KEY]) {
+ state[SHOULD_SHOW_7_DAYS_KEY] = show7Days
+ }
+ }
- init {
- initializeTimeFilter(application)
+ /** Creates a [PermissionUsageDetailsUiInfo] containing all information to render the UI. */
+ fun buildPermissionUsageDetailsUiInfo(): PermissionUsageDetailsUiInfo {
+ val showSystem: Boolean = state[SHOULD_SHOW_SYSTEM_KEY] ?: false
+ val show7Days: Boolean = state[SHOULD_SHOW_7_DAYS_KEY] ?: false
+ val showPermissionUsagesDuration =
+ if (KotlinUtils.is7DayToggleEnabled() && show7Days) {
+ TIME_7_DAYS_DURATION
+ } else {
+ TIME_24_HOURS_DURATION
+ }
+ val startTime =
+ (System.currentTimeMillis() - showPermissionUsagesDuration).coerceAtLeast(
+ Instant.EPOCH.toEpochMilli())
+
+ return PermissionUsageDetailsUiInfo(
+ show7Days,
+ showSystem,
+ buildAppPermissionAccessUiInfoList(
+ allLightHistoricalPackageOpsLiveData, startTime, showSystem),
+ containsSystemAppUsages(allLightHistoricalPackageOpsLiveData, startTime))
}
/**
- * Loads permission usages using [PermissionUsages]. Response is returned to the [callback].
+ * Returns whether the "show/hide system" toggle should be displayed in the UI for the provided
+ * [AllLightHistoricalPackageOpsLiveData].
*/
- fun loadPermissionUsages(
- loaderManager: LoaderManager,
- permissionUsages: PermissionUsages,
- callback: PermissionUsages.PermissionsUsagesChangeCallback,
- filterTimesIndex: Int
- ) {
- val timeFilterItem: TimeFilterItem = filterTimes[filterTimesIndex]
- val filterTimeBeginMillis = max(System.currentTimeMillis() - timeFilterItem.time, 0)
- permissionUsages.load(
- /* filterPackageName= */ null,
- /* filterPermissionGroups= */ null,
- filterTimeBeginMillis,
- Long.MAX_VALUE,
- PermissionUsages.USAGE_FLAG_LAST or PermissionUsages.USAGE_FLAG_HISTORICAL,
- loaderManager,
- /* getUiInfo= */ false,
- /* getNonPlatformPermissions= */ false,
- /* callback= */ callback,
- /* sync= */ false)
+ private fun containsSystemAppUsages(
+ allLightHistoricalPackageOpsLiveData: AllLightHistoricalPackageOpsLiveData,
+ startTime: Long
+ ): Boolean {
+ return allLightHistoricalPackageOpsLiveData
+ .getLightHistoricalPackageOps()
+ ?.flatMap {
+ it.appPermissionDiscreteAccesses
+ .map { it.withLabel() }
+ .filterOutExemptAppPermissions(true)
+ .filterAccessesLaterThan(startTime)
+ }
+ ?.any { isAppPermissionSystem(it.appPermissionId) }
+ ?: false
+ }
+
+ private fun isPermissionRequestedByApp(appPermissionId: AppPermissionId): Boolean {
+ val appRequestedPermissions =
+ lightPackageInfoLiveDataMap[
+ Pair(appPermissionId.packageName, appPermissionId.userHandle)]
+ ?.value
+ ?.requestedPermissions
+ ?: listOf()
+ return appRequestedPermissions.any {
+ PermissionMapping.getGroupOfPlatformPermission(it) == appPermissionId.permissionGroup
+ }
+ }
+
+ private fun isAppPermissionSystem(appPermissionId: AppPermissionId): Boolean {
+ val appPermGroupUiInfo = appPermGroupUiInfoLiveDataList[appPermissionId]?.value
+
+ if (appPermGroupUiInfo != null) {
+ return appPermGroupUiInfo.isSystem
+ } else
+ // The AppPermGroupUiInfo may be null if it has either not loaded yet or if the app has not
+ // requested any permissions from the permission group in question.
+ // 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)) {
+ return true
+ }
+ return false
}
/**
- * Returns whether app subattribution should be shown.
+ * Extracts access data from [AllLightHistoricalPackageOpsLiveData] and composes
+ * [AppPermissionAccessUiInfo]s to be displayed in the UI.
*/
- private fun shouldShowSubattributionForApp(appPermissionUsage: AppPermissionUsage): Boolean {
- return shouldShowSubattributionInPermissionsDashboard() &&
- SubattributionUtils.isSubattributionSupported(application,
- appPermissionUsage.app.appInfo)
+ private fun buildAppPermissionAccessUiInfoList(
+ allLightHistoricalPackageOpsLiveData: AllLightHistoricalPackageOpsLiveData,
+ startTime: Long,
+ showSystem: Boolean
+ ): List<AppPermissionAccessUiInfo> {
+ return allLightHistoricalPackageOpsLiveData
+ .getLightHistoricalPackageOps()
+ ?.flatMap { it.clusterAccesses(startTime, showSystem) }
+ ?.sortedBy { -1 * it.discreteAccesses.first().accessTimeMs }
+ ?.map { it.buildAppPermissionAccessUiInfo() }
+ ?: listOf()
+ }
+
+ private fun LightHistoricalPackageOps.clusterAccesses(
+ startTime: Long,
+ showSystem: Boolean
+ ): List<AppPermissionDiscreteAccessCluster> {
+ return if (!shouldShowSubAttributionForApp(getLightPackageInfo(packageName, userHandle)))
+ this.clusterAccessesWithoutAttribution(startTime, showSystem)
+ else {
+ this.clusterAccessesWithAttribution(startTime, showSystem)
+ }
}
/**
- * Create a list of [AppPermissionUsageEntry]s based on the provided data.
+ * Clusters accesses that are close enough together in time such that they can be displayed as a
+ * single access to the user.
*
- * @param appPermissionUsages data about app permission usages
- * @param exemptedPackages packages whose usage should not be included in the out
- * @param permApps mutable list of [PermissionApp] for keeping track of information about apps.
- * This field is updated as a side effect of running this method.
- * @param seenSystemApp mutable field to track whether a system app has recent usage. Updated
- * as a side effect of running this method.
- * @param showSystemApp whether System apps should be shown
- * @param show7Days whether the last 7 days of history should be shown
+ * Accesses are clustered taking into account any app subattribution, so each cluster will
+ * pertain a particular attribution label.
*/
- fun parseUsages(
- appPermissionUsages: List<AppPermissionUsage>,
- exemptedPackages: Set<String>,
- permApps: MutableList<PermissionApp>,
- seenSystemApp: AtomicBoolean,
- showSystemApp: Boolean,
- show7Days: Boolean
- ): List<AppPermissionUsageEntry> {
- val curTime = System.currentTimeMillis()
- val showPermissionUsagesDuration = if (is7DayToggleEnabled() && show7Days) {
- TIME_7_DAYS_DURATION
- } else {
- TIME_24_HOURS_DURATION
- }
- val startTime = (curTime - showPermissionUsagesDuration)
- .coerceAtLeast(Instant.EPOCH.toEpochMilli())
+ private fun LightHistoricalPackageOps.clusterAccessesWithAttribution(
+ startTime: Long,
+ showSystem: Boolean
+ ): List<AppPermissionDiscreteAccessCluster> =
+ this.attributedAppPermissionDiscreteAccesses
+ .flatMap { it.groupAccessesByLabel(getLightPackageInfo(packageName, userHandle)) }
+ .filterOutExemptAppPermissions(showSystem)
+ .filterAccessesLaterThan(startTime)
+ .flatMap { createAccessClusters(it) }
- return appPermissionUsages
- .asSequence()
- .filter { appUsage: AppPermissionUsage ->
- !exemptedPackages.contains(appUsage.packageName)
- }
- .map { appUsage: AppPermissionUsage ->
- filterAndConvert(appUsage, filterGroup)
- }
- .flatten()
- .map { usageData: UsageData ->
- // Fetch the access time list of the app accesses mFilterGroup permission group
- // The DiscreteAccessTime is a Triple of (access time, access duration,
- // proxy) of that app
- val discreteAccessTimeList:
- MutableList<Triple<Long, Long, AppOpsManager.OpEventProxyInfo?>> =
- mutableListOf()
- val timelineUsages = usageData.timelineUsages
- val numGroups = timelineUsages.size
- for (groupIndex in 0 until numGroups) {
- val timelineUsage = timelineUsages[groupIndex]
- if (!timelineUsage.hasDiscreteData()) {
- continue
- }
- val isSystemApp = !Utils.isGroupOrBgGroupUserSensitive(timelineUsage.group)
- seenSystemApp.set(seenSystemApp.get() || isSystemApp)
- if (isSystemApp && !showSystemApp) {
- continue
- }
- for (discreteAccessTime in timelineUsage.allDiscreteAccessTime) {
- if (discreteAccessTime.first == 0L ||
- discreteAccessTime.first < startTime) {
- continue
- }
- discreteAccessTimeList.add(discreteAccessTime)
- }
- }
- discreteAccessTimeList.sortWith { x, y -> y.first.compareTo(x.first) }
- if (discreteAccessTimeList.size > 0) {
- permApps.add(usageData.app)
- }
-
- // If the current permission group is not LOCATION or there's only one access
- // for the app, return individual entry early.
- if (!ALLOW_CLUSTERING_PERMISSION_GROUPS.contains(filterGroup) ||
- discreteAccessTimeList.size <= 1) {
- return@map discreteAccessTimeList.map { time ->
- AppPermissionUsageEntry(usageData, time.first, mutableListOf(time))
- }
- }
+ /**
+ * Clusters accesses that are close enough together in time such that they can be displayed as a
+ * single access to the user.
+ *
+ * Accesses are clustered disregarding any app subattribution.
+ */
+ private fun LightHistoricalPackageOps.clusterAccessesWithoutAttribution(
+ startTime: Long,
+ showSystem: Boolean
+ ): List<AppPermissionDiscreteAccessCluster> =
+ this.appPermissionDiscreteAccesses
+ .map { it.withLabel() }
+ .filterOutExemptAppPermissions(showSystem)
+ .filterAccessesLaterThan(startTime)
+ .flatMap { createAccessClusters(it) }
+
+ /** Filters out accesses earlier than the provided start time. */
+ private fun List<AppPermissionDiscreteAccessesWithLabel>.filterAccessesLaterThan(
+ startTime: Long,
+ ): List<AppPermissionDiscreteAccessesWithLabel> =
+ this.mapNotNull {
+ val updatedDiscreteAccesses =
+ it.discreteAccesses.filter { access -> access.accessTimeMs > startTime }
+ if (updatedDiscreteAccesses.isEmpty()) null
+ else
+ AppPermissionDiscreteAccessesWithLabel(
+ it.appPermissionId,
+ it.attributionLabel,
+ it.attributionTags,
+ updatedDiscreteAccesses)
+ }
- // Group access time list
- val usageEntries = mutableListOf<AppPermissionUsageEntry>()
- var ongoingEntry: AppPermissionUsageEntry? = null
- for (time in discreteAccessTimeList) {
- if (ongoingEntry == null) {
- ongoingEntry = AppPermissionUsageEntry(usageData, time.first,
- mutableListOf(time))
- } else {
- val ongoingAccessTimeList:
- MutableList<Triple<Long, Long, AppOpsManager.OpEventProxyInfo?>> =
- ongoingEntry.clusteredAccessTimeList
- if (time.first / ONE_HOUR_MS !=
- ongoingAccessTimeList[0].first / ONE_HOUR_MS ||
- ongoingAccessTimeList[ongoingAccessTimeList.size - 1].first /
- ONE_MINUTE_MS - time.first / ONE_MINUTE_MS > CLUSTER_MINUTES_APART
- ) {
- // If the current access time is not in the same hour nor within
- // CLUSTER_MINUTES_APART, add the ongoing entry to the usage list
- // and start a new ongoing entry.
- usageEntries.add(ongoingEntry)
- ongoingEntry = AppPermissionUsageEntry(usageData, time.first,
- mutableListOf(time))
- } else {
- ongoingAccessTimeList.add(time)
- }
- }
- }
- ongoingEntry?.let { usageEntries.add(it) }
- usageEntries
+ /** Filters out data for apps and permissions that don't need to be displayed in the UI. */
+ private fun List<AppPermissionDiscreteAccessesWithLabel>.filterOutExemptAppPermissions(
+ showSystem: Boolean
+ ): List<AppPermissionDiscreteAccessesWithLabel> {
+ return this.filter {
+ !Utils.getExemptedPackages(roleManager).contains(it.appPermissionId.packageName)
}
- .flatten()
- .sortedWith { x, y ->
- // Sort all usage entries by startTime desc, and then by app name.
- val timeCompare = java.lang.Long.compare(y.endTime, x.endTime)
- if (timeCompare != 0) {
- return@sortedWith timeCompare
- }
- x.usageData.app.label.compareTo(y.usageData.app.label)
- }
- .toList()
+ .filter { it.appPermissionId.permissionGroup == permissionGroup }
+ .filter { isPermissionRequestedByApp(it.appPermissionId) }
+ .filter { showSystem || !isAppPermissionSystem(it.appPermissionId) }
}
/**
- * Render [usages] into the [preferenceScreen] UI.
+ * Converts the provided [AppPermissionDiscreteAccesses] to a
+ * [AppPermissionDiscreteAccessesWithLabel] by adding a label.
*/
- fun renderTimelinePreferences(
- usages: List<AppPermissionUsageEntry>,
- category: AtomicReference<PreferenceCategory>,
- preferenceScreen: PreferenceScreen,
- historyPreferenceFactory: HistoryPreferenceFactory
- ) {
- val context = application
- var hasADateLabel = false
- var lastDateLabel = 0L
- usages.forEachIndexed { usageNum, usage ->
- val usageTimestamp = usage.endTime
- val usageDateLabel = ZonedDateTime.ofInstant(Instant.ofEpochMilli(usageTimestamp),
- Clock.systemDefaultZone().zone)
- .truncatedTo(ChronoUnit.DAYS).toEpochSecond() * 1000L
- if (!hasADateLabel || usageDateLabel != lastDateLabel) {
- if (hasADateLabel) {
- category.set(historyPreferenceFactory.createDayCategoryPreference())
- preferenceScreen.addPreference(category.get())
- }
- val formattedDateTitle = DateFormat.getDateFormat(context)
- .format(usageDateLabel)
- if (usageTimestamp > midnightToday) {
- category.get().setTitle(R.string.permission_history_category_today)
- } else if (usageTimestamp > midnightYesterday) {
- category.get().setTitle(R.string.permission_history_category_yesterday)
- } else {
- category.get().setTitle(formattedDateTitle)
- }
- hasADateLabel = true
- }
-
- lastDateLabel = usageDateLabel
-
- val accessTime = DateFormat.getTimeFormat(context).format(usage.endTime)
- var durationLong: Long = usage.clusteredAccessTimeList
- .map { p -> p.second }
- .filter { dur -> dur > 0 }
- .sum()
-
- val accessTimeList: List<Long> = usage.clusteredAccessTimeList.map { p -> p.first }
-
- // Determine the preference summary. Start with the duration string
- var summaryLabel: String? = null
- // Since Location accesses are atomic, we manually calculate the access duration
- // by comparing the first and last access within the cluster
- if (filterGroup == Manifest.permission_group.LOCATION) {
- if (accessTimeList.size > 1) {
- durationLong = (accessTimeList[0] - accessTimeList[accessTimeList.size - 1])
-
- // Similar to other history items, only show the duration if it's longer
- // than the clustering granularity.
- if (durationLong
- >= TimeUnit.MINUTES.toMillis(CLUSTER_MINUTES_APART.toLong()) + 1) {
- summaryLabel = getDurationUsedStr(context, durationLong)
- }
- }
- } else {
- // Only show the duration if it is at least (cluster + 1) minutes. Displaying
- // times that are the same as the cluster granularity does not convey useful
- // information.
- if (durationLong >=
- TimeUnit.MINUTES.toMillis((CLUSTER_MINUTES_APART + 1).toLong())) {
- summaryLabel = getDurationUsedStr(context, durationLong)
- }
+ private fun AppPermissionDiscreteAccesses.withLabel(): AppPermissionDiscreteAccessesWithLabel =
+ AppPermissionDiscreteAccessesWithLabel(
+ this.appPermissionId,
+ Resources.ID_NULL,
+ attributionTags = emptyList(),
+ this.discreteAccesses)
+
+ /** Groups tag-attributed accesses for the provided app and permission by attribution label. */
+ private fun AttributedAppPermissionDiscreteAccesses.groupAccessesByLabel(
+ lightPackageInfo: LightPackageInfo?
+ ): List<AppPermissionDiscreteAccessesWithLabel> {
+ if (lightPackageInfo == null) return emptyList()
+
+ val appPermissionId = this.appPermissionId
+ val labelsToDiscreteAccesses = mutableMapOf<Int, MutableList<DiscreteAccess>>()
+ val labelsToTags = mutableMapOf<Int, MutableList<String>>()
+
+ val appPermissionDiscreteAccessWithLabels =
+ mutableListOf<AppPermissionDiscreteAccessesWithLabel>()
+
+ for ((tag, discreteAccesses) in this.attributedDiscreteAccesses) {
+ val label: Int =
+ if (tag == NO_ATTRIBUTION_TAG) Resources.ID_NULL
+ else lightPackageInfo.attributionTagsToLabels[tag] ?: Resources.ID_NULL
+
+ if (!labelsToDiscreteAccesses.containsKey(label)) {
+ labelsToDiscreteAccesses[label] = mutableListOf()
}
+ labelsToDiscreteAccesses[label]?.addAll(discreteAccesses)
- var proxyPackageLabel: String? = null
- for (clusteredAccessTime in usage.clusteredAccessTimeList) {
- val proxy = clusteredAccessTime.third
- if (proxy != null && proxy.packageName != null) {
- proxyPackageLabel = getPackageLabel(
- PermissionControllerApplication.get(), proxy.packageName!!,
- UserHandle.getUserHandleForUid(proxy.uid))
- break
- }
+ if (!labelsToTags.containsKey(label)) {
+ labelsToTags[label] = mutableListOf()
}
+ labelsToTags[label]?.add(tag)
+ }
- // fetch the subattribution label for this usage.
- var subattributionLabel: String? = null
- if (usage.usageData.label != Resources.ID_NULL) {
- val attributionLabels: Map<Int, String>? = usage.usageData.app.attributionLabels
- if (attributionLabels != null) {
- subattributionLabel = attributionLabels[usage.usageData.label]
- }
- }
+ for ((label, discreteAccesses) in labelsToDiscreteAccesses.entries) {
+ val tags = labelsToTags[label]?.toList() ?: listOf()
- // create subtext string.
- val subTextStrings: MutableList<String?> = mutableListOf()
- val showingAttribution = subattributionLabel != null && subattributionLabel.isNotEmpty()
- if (showingAttribution) {
- subTextStrings.add(subattributionLabel)
- }
- if (proxyPackageLabel != null) {
- subTextStrings.add(proxyPackageLabel)
- }
- if (summaryLabel != null) {
- subTextStrings.add(summaryLabel)
- }
- var subText: String? = null
- when (subTextStrings.size) {
- 3 -> {
- subText = context.getString(
- R.string.history_preference_subtext_3,
- subTextStrings[0],
- subTextStrings[1],
- subTextStrings[2])
- }
- 2 -> {
- subText = context.getString(R.string.history_preference_subtext_2,
- subTextStrings[0],
- subTextStrings[1])
- }
- 1 -> {
- subText = subTextStrings[0]
- }
- }
-
- val permissionUsagePreference = historyPreferenceFactory
- .createPermissionHistoryPreference(
- HistoryPreferenceData(
- UserHandle.getUserHandleForUid(usage.usageData.app.getUid()),
- usage.usageData.app.packageName,
- usage.usageData.app.icon,
- usage.usageData.app.label,
- filterGroup, accessTime, subText,
- showingAttribution, accessTimeList,
- usage.usageData.attributionTags,
- usageNum == usages.size - 1,
- sessionId)
- )
- category.get().addPreference(permissionUsagePreference)
+ appPermissionDiscreteAccessWithLabels.add(
+ AppPermissionDiscreteAccessesWithLabel(
+ appPermissionId,
+ label,
+ tags,
+ discreteAccesses.sortedBy { -1 * it.accessTimeMs }))
}
+
+ return appPermissionDiscreteAccessWithLabels
}
/**
- * Filter the usage data from [appPermissionUsage] into a list of [UsageData].
+ * Clusters [DiscreteAccess]es represented by a [AppPermissionDiscreteAccessesWithLabel] into
+ * smaller groups to form a list of [AppPermissionDiscreteAccessCluster] instances.
+ *
+ * [DiscreteAccess]es which have accesses sufficiently close together in time will be places in
+ * the same cluster.
*/
- private fun filterAndConvert(
- appPermissionUsage: AppPermissionUsage,
- filterGroup: String
- ): List<UsageData> {
- if (shouldShowSubattributionForApp(appPermissionUsage)) {
- return appPermissionUsage.groupUsages
- .filter { groupUsage: GroupUsage -> groupUsage.group.name == filterGroup }
- .map(GroupUsage::getAttributionLabelledGroupUsages)
- .flatten()
- .map { labelledGroupUsage: AttributionLabelledGroupUsage ->
- UsageData(filterGroup, appPermissionUsage.app,
- listOf<TimelineUsage>(labelledGroupUsage),
- labelledGroupUsage.label)
- }
+ private fun createAccessClusters(
+ appPermAccesses: AppPermissionDiscreteAccessesWithLabel,
+ ): List<AppPermissionDiscreteAccessCluster> {
+ val clusters = mutableListOf<AppPermissionDiscreteAccessCluster>()
+ val currentDiscreteAccesses = mutableListOf<DiscreteAccess>()
+ for (discreteAccess in appPermAccesses.discreteAccesses) {
+ if (currentDiscreteAccesses.isEmpty()) {
+ currentDiscreteAccesses.add(discreteAccess)
+ } else if (!canAccessBeAddedToCluster(discreteAccess, currentDiscreteAccesses)) {
+ clusters.add(
+ AppPermissionDiscreteAccessCluster(
+ appPermAccesses.appPermissionId,
+ appPermAccesses.attributionLabel,
+ appPermAccesses.attributionTags,
+ currentDiscreteAccesses.toMutableList()))
+ currentDiscreteAccesses.clear()
+ currentDiscreteAccesses.add(discreteAccess)
+ } else {
+ currentDiscreteAccesses.add(discreteAccess)
+ }
+ }
+
+ if (currentDiscreteAccesses.isNotEmpty()) {
+ clusters.add(
+ AppPermissionDiscreteAccessCluster(
+ appPermAccesses.appPermissionId,
+ appPermAccesses.attributionLabel,
+ appPermAccesses.attributionTags,
+ currentDiscreteAccesses.toMutableList()))
}
- val groupUsages = appPermissionUsage.groupUsages
- .filter { groupUsage: GroupUsage -> groupUsage.group.name == filterGroup }
- return listOf(
- UsageData(filterGroup, appPermissionUsage.app, groupUsages,
- Resources.ID_NULL)
- )
+ return clusters
}
/**
- * Get an AppPermissionGroup that represents the given permission group (and an arbitrary app).
- *
- * @param groupName The name of the permission group.
- *
- * @return an AppPermissionGroup representing the given permission group or null if no such
- * AppPermissionGroup is found.
+ * Returns whether the provided [DiscreteAccess] occurred close enough to those in the clustered
+ * list that it can be added to the cluster.
*/
- fun getGroup(
- groupName: String,
- appPermissionUsages: List<AppPermissionUsage>
- ): AppPermissionGroup? {
- val groups = getOSPermissionGroups(appPermissionUsages)
- return groups.firstOrNull { it.name == groupName }
- }
+ private fun canAccessBeAddedToCluster(
+ discreteAccess: DiscreteAccess,
+ clusteredAccesses: List<DiscreteAccess>
+ ): Boolean =
+ discreteAccess.accessTimeMs / ONE_HOUR_MS ==
+ clusteredAccesses.first().accessTimeMs / ONE_HOUR_MS &&
+ clusteredAccesses.last().accessTimeMs / ONE_MINUTE_MS -
+ discreteAccess.accessTimeMs / ONE_MINUTE_MS <= CLUSTER_SPACING_MINUTES
/**
- * Get the permission groups declared by the OS.
- *
- * TODO: theianchen change the method name to make that clear,
- * and return a list of string group names, not AppPermissionGroups.
- * @return a list of the permission groups declared by the OS.
+ * Composes all UI information from a [AppPermissionDiscreteAccessCluster] into a
+ * [AppPermissionAccessUiInfo].
*/
- private fun getOSPermissionGroups(
- appPermissionUsages: List<AppPermissionUsage>
- ): List<AppPermissionGroup> {
- val groups: MutableList<AppPermissionGroup> = mutableListOf()
- val seenGroups: MutableSet<String> = mutableSetOf()
- for (appUsage in appPermissionUsages) {
- val groupUsages = appUsage.groupUsages
- for (groupUsage in groupUsages) {
- if (Utils.isModernPermissionGroup(groupUsage.group.name)) {
- if (seenGroups.add(groupUsage.group.name)) {
- groups.add(groupUsage.group)
- }
- }
- }
+ private fun AppPermissionDiscreteAccessCluster.buildAppPermissionAccessUiInfo():
+ AppPermissionAccessUiInfo {
+ val context = application
+ val accessTimeList = this.discreteAccesses.map { it.accessTimeMs }
+ val durationSummaryLabel = getDurationSummary(context, this, accessTimeList)
+ val proxyLabel = getProxyPackageLabel(this)
+ val subAttributionLabel = getSubAttributionLabel(this)
+ val showingSubAttribution = subAttributionLabel != null && subAttributionLabel.isNotEmpty()
+ val summary =
+ buildUsageSummary(context, subAttributionLabel, proxyLabel, durationSummaryLabel)
+
+ return AppPermissionAccessUiInfo(
+ this.appPermissionId.userHandle,
+ this.appPermissionId.packageName,
+ permissionGroup,
+ this.discreteAccesses.last().accessTimeMs,
+ this.discreteAccesses.first().accessTimeMs,
+ summary,
+ showingSubAttribution,
+ ArrayList(this.attributionTags))
+ }
+
+ /** Builds a summary of the permission access. */
+ private fun buildUsageSummary(
+ context: Context,
+ subAttributionLabel: String?,
+ proxyPackageLabel: String?,
+ durationSummary: String?
+ ): String? {
+ val subTextStrings: MutableList<String> = mutableListOf()
+
+ subAttributionLabel?.let { subTextStrings.add(subAttributionLabel) }
+ proxyPackageLabel?.let { subTextStrings.add(it) }
+ durationSummary?.let { subTextStrings.add(it) }
+ return when (subTextStrings.size) {
+ 3 ->
+ context.getString(
+ R.string.history_preference_subtext_3,
+ subTextStrings[0],
+ subTextStrings[1],
+ subTextStrings[2])
+ 2 ->
+ context.getString(
+ R.string.history_preference_subtext_2, subTextStrings[0], subTextStrings[1])
+ 1 -> subTextStrings[0]
+ else -> null
}
- return groups
}
- /**
- * Initialize the time filter to show the smallest entry greater than the time passed in as an
- * argument. If nothing is passed, this simply initializes the possible values.
- */
- private fun initializeTimeFilter(context: Context) {
- filterTimes.add(
- TimeFilterItem(Long.MAX_VALUE,
- context.getString(R.string.permission_usage_any_time))
- )
- filterTimes.add(
- TimeFilterItem(DAYS.toMillis(7),
- context.getString(R.string.permission_usage_last_7_days))
- )
- filterTimes.add(
- TimeFilterItem(DAYS.toMillis(1),
- context.getString(R.string.permission_usage_last_day))
- )
- filterTimes.add(
- TimeFilterItem(TimeUnit.HOURS.toMillis(1),
- context.getString(R.string.permission_usage_last_hour))
- )
- filterTimes.add(
- TimeFilterItem(TimeUnit.MINUTES.toMillis(15),
- context.getString(R.string.permission_usage_last_15_minutes))
- )
- filterTimes.add(
- TimeFilterItem(TimeUnit.MINUTES.toMillis(1),
- context.getString(R.string.permission_usage_last_minute))
- )
-
- // TODO: theianchen add code for filtering by time here.
+ /** Returns whether app subattribution should be shown. */
+ private fun shouldShowSubAttributionForApp(lightPackageInfo: LightPackageInfo?): Boolean {
+ return lightPackageInfo != null &&
+ shouldShowSubattributionInPermissionsDashboard() &&
+ SubattributionUtils.isSubattributionSupported(lightPackageInfo)
}
- /**
- * Factory for creating preferences to be added to the screen.
- */
- interface HistoryPreferenceFactory {
- /**
- * Returns a new [PreferenceCategory] representing a day of permission usage.
- */
- fun createDayCategoryPreference(): PreferenceCategory
+ /** Returns a summary of the duration the permission was accessed for. */
+ private fun getDurationSummary(
+ context: Context,
+ accessCluster: AppPermissionDiscreteAccessCluster,
+ accessTimeList: List<Long>,
+ ): String? {
+ if (accessTimeList.isEmpty()) {
+ return null
+ }
+ // Since Location accesses are atomic, we manually calculate the access duration by
+ // comparing the first and last access within the cluster.
+ val durationMs: Long =
+ if (permissionGroup == Manifest.permission_group.LOCATION) {
+ accessTimeList[0] - accessTimeList[accessTimeList.size - 1]
+ } else {
+ accessCluster.discreteAccesses
+ .filter { it.accessDurationMs > 0 }
+ .sumOf { it.accessDurationMs }
+ }
- /**
- * Returns a preference representing an app's permission usage, including its timestamp and
- * usage details.
- */
- fun createPermissionHistoryPreference(
- historyPreferenceData: HistoryPreferenceData
- ): Preference
+ // Only show the duration summary if it is at least (CLUSTER_SPACING_MINUTES + 1) minutes.
+ // Displaying a time that is shorter than the cluster granularity
+ // (CLUSTER_SPACING_MINUTES) will not convey useful information.
+ if (durationMs >= TimeUnit.MINUTES.toMillis(CLUSTER_SPACING_MINUTES + 1)) {
+ return getDurationUsedStr(context, durationMs)
+ }
+
+ return null
}
- /**
- * Data used to create a preference for an app's permission usage.
- */
- data class HistoryPreferenceData(
+ /** Returns the proxied package label if the permission access was proxied. */
+ private fun getProxyPackageLabel(accessCluster: AppPermissionDiscreteAccessCluster): String? =
+ accessCluster.discreteAccesses
+ .firstOrNull { it.proxy?.packageName != null }
+ ?.let {
+ getPackageLabel(
+ PermissionControllerApplication.get(),
+ it.proxy!!.packageName!!,
+ UserHandle.getUserHandleForUid(it.proxy.uid))
+ }
+
+ /** Returns the attribution label for the permission access, if any. */
+ private fun getSubAttributionLabel(accessCluster: AppPermissionDiscreteAccessCluster): String? =
+ if (accessCluster.attributionLabel == Resources.ID_NULL) null
+ else {
+ val lightPackageInfo = getLightPackageInfo(accessCluster.appPermissionId)
+ getSubAttributionLabels(lightPackageInfo)?.get(accessCluster.attributionLabel)
+ }
+
+ private fun getSubAttributionLabels(lightPackageInfo: LightPackageInfo?): Map<Int, String>? =
+ if (lightPackageInfo == null) null
+ else SubattributionUtils.getAttributionLabels(application, lightPackageInfo)
+
+ private fun getLightPackageInfo(appPermissionId: AppPermissionId) =
+ lightPackageInfoLiveDataMap[Pair(appPermissionId.packageName, appPermissionId.userHandle)]
+ ?.value
+
+ private fun getLightPackageInfo(packageName: String, userHandle: UserHandle) =
+ lightPackageInfoLiveDataMap[Pair(packageName, userHandle)]?.value
+
+ private fun AllLightHistoricalPackageOpsLiveData.getLightHistoricalPackageOps() =
+ this.value?.values
+
+ /** Data used to create a preference for an app's permission usage. */
+ data class AppPermissionAccessUiInfo(
val userHandle: UserHandle,
val pkgName: String,
- val appIcon: Drawable?,
- val preferenceTitle: String,
val permissionGroup: String,
- val accessTime: String,
+ val accessStartTime: Long,
+ val accessEndTime: Long,
val summaryText: CharSequence?,
val showingAttribution: Boolean,
- val accessTimeList: List<Long>,
val attributionTags: ArrayList<String>,
- val isLastUsage: Boolean,
- val sessionId: Long
)
/**
- * A class representing a given time, e.g., "in the last hour".
- *
- * @param time the time represented by this object in milliseconds.
- * @param label the label to describe the timeframe
+ * Class containing all the information needed by the permission usage details fragments to
+ * render UI.
*/
- data class TimeFilterItem(
- val time: Long,
- val label: String
+ data class PermissionUsageDetailsUiInfo(
+ /**
+ * Whether to show data over the last 7 days.
+ *
+ * While this information is available from the [SHOULD_SHOW_7_DAYS_KEY] state, we include
+ * it in the UI info so that it triggers a UI update when changed.
+ */
+ private val show7Days: Boolean,
+ /**
+ * Whether to show system apps' data.
+ *
+ * While this information is available from the [SHOULD_SHOW_SYSTEM_KEY] state, we include
+ * it in the UI info so that it triggers a UI update when changed.
+ */
+ private val showSystem: Boolean,
+ /** List of [AppPermissionAccessUiInfo]s to be displayed in the UI. */
+ val appPermissionAccessUiInfoList: List<AppPermissionAccessUiInfo>,
+ /** Whether to show the "show/hide system" toggle. */
+ val containsSystemAppAccesses: Boolean,
)
- /** A class representing an app's usage for a group. */
- data class UsageData(
- val group: String,
- // we need a PermissionApp because the loader takes the PermissionApp
- // object and loads the icon and label information asynchronously
- val app: PermissionApp,
- val timelineUsages: List<TimelineUsage>,
- val label: Int
- ) {
- val attributionTags: java.util.ArrayList<String>
- get() = timelineUsages.stream()
- .map { obj: TimelineUsage -> obj.attributionTags }
- .filter { obj: List<String>? -> Objects.nonNull(obj) }
- .flatMap { obj: List<String> -> obj.stream() }
- .collect(Collectors.toCollection { ArrayList() })
- }
+ /**
+ * Data class representing a cluster of permission accesses close enough together to be
+ * displayed as a single access in the UI.
+ */
+ private data class AppPermissionDiscreteAccessCluster(
+ val appPermissionId: AppPermissionId,
+ val attributionLabel: Int,
+ val attributionTags: List<String>,
+ val discreteAccesses: List<DiscreteAccess>,
+ )
/**
- * A class representing an app usage entry in Permission Usage.
+ * Data class representing all permission accesses for a particular package, user, permission
+ * and attribution label.
*/
- data class AppPermissionUsageEntry(
- val usageData: UsageData,
- val endTime: Long,
- val clusteredAccessTimeList: MutableList<Triple<Long, Long, AppOpsManager.OpEventProxyInfo?>>
+ private data class AppPermissionDiscreteAccessesWithLabel(
+ val appPermissionId: AppPermissionId,
+ val attributionLabel: Int,
+ val attributionTags: List<String>,
+ val discreteAccesses: List<DiscreteAccess>
)
-}
-/**
- * Factory for an [PermissionUsageDetailsViewModel]
- */
-@RequiresApi(Build.VERSION_CODES.S)
-class PermissionUsageDetailsViewModelFactory(
- private val application: Application,
- private val roleManager: RoleManager,
- private val filterGroup: String,
- private val sessionId: Long
-) : ViewModelProvider.Factory {
-
- override fun <T : ViewModel> create(modelClass: Class<T>): T {
- @Suppress("UNCHECKED_CAST")
- return PermissionUsageDetailsViewModel(application, roleManager, filterGroup,
- sessionId) as T
+ /** [LiveData] object for [PermissionUsageDetailsUiInfo]. */
+ val permissionUsagesDetailsInfoUiLiveData =
+ object : SmartUpdateMediatorLiveData<@JvmSuppressWildcards PermissionUsageDetailsUiInfo>() {
+ private val getAppPermGroupUiInfoLiveData = { appPermissionId: AppPermissionId ->
+ AppPermGroupUiInfoLiveData[
+ Triple(
+ appPermissionId.packageName,
+ appPermissionId.permissionGroup,
+ appPermissionId.userHandle,
+ )]
+ }
+ private val getLightPackageInfoLiveData =
+ { packageWithUserHandle: Pair<String, UserHandle> ->
+ LightPackageInfoLiveData[packageWithUserHandle]
+ }
+
+ init {
+ addSource(allLightHistoricalPackageOpsLiveData) { update() }
+ addSource(showSystemLiveData) { update() }
+ addSource(show7DaysLiveData) { update() }
+ }
+
+ override fun onUpdate() {
+ if (!allLightHistoricalPackageOpsLiveData.isInitialized) {
+ return
+ }
+
+ val appPermissionIds = mutableSetOf<AppPermissionId>()
+ val allPackages: Set<Pair<String, UserHandle>> =
+ allLightHistoricalPackageOpsLiveData.value?.keys ?: setOf()
+ for (packageWithUserHandle: Pair<String, UserHandle> in allPackages) {
+ val appPermGroupIds =
+ allLightHistoricalPackageOpsLiveData.value
+ ?.get(packageWithUserHandle)
+ ?.appPermissionDiscreteAccesses
+ ?.map { it.appPermissionId }
+ ?.toSet()
+ ?: setOf()
+
+ appPermissionIds.addAll(appPermGroupIds)
+ }
+
+ setSourcesToDifference(
+ appPermissionIds,
+ appPermGroupUiInfoLiveDataList,
+ getAppPermGroupUiInfoLiveData) {
+ update()
+ }
+ setSourcesToDifference(
+ allPackages, lightPackageInfoLiveDataMap, getLightPackageInfoLiveData) {
+ update()
+ }
+
+ if (appPermGroupUiInfoLiveDataList.any { it.value.isStale }) {
+ return
+ }
+
+ if (lightPackageInfoLiveDataMap.any { it.value.isStale }) {
+ return
+ }
+
+ value = buildPermissionUsageDetailsUiInfo()
+ }
+ }
+
+ /** Companion object for [PermissionUsageDetailsViewModel]. */
+ companion object {
+ private const val ONE_HOUR_MS = 3_600_000
+ private const val ONE_MINUTE_MS = 60_000
+ private const val CLUSTER_SPACING_MINUTES: Long = 1L
+ private const val TELECOM_PACKAGE = "com.android.server.telecom"
+ private val TIME_7_DAYS_DURATION: Long = DAYS.toMillis(7)
+ private val TIME_24_HOURS_DURATION: Long = DAYS.toMillis(1)
+ internal const val SHOULD_SHOW_SYSTEM_KEY = "showSystem"
+ internal const val SHOULD_SHOW_7_DAYS_KEY = "show7Days"
+
+ /** Returns all op names for all permissions in a list of permission groups. */
+ val opNames =
+ listOf(
+ Manifest.permission_group.CAMERA,
+ Manifest.permission_group.LOCATION,
+ Manifest.permission_group.MICROPHONE)
+ .flatMap { group -> PermissionMapping.getPlatformPermissionNamesOfGroup(group) }
+ .mapNotNull { permName -> AppOpsManager.permissionToOp(permName) }
+ .toMutableSet()
+ .apply {
+ add(OPSTR_PHONE_CALL_MICROPHONE)
+ add(OPSTR_PHONE_CALL_CAMERA)
+ if (SdkLevel.isAtLeastT()) {
+ add(AppOpsManager.OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO)
+ }
+ }
+
+ /** Creates the [Intent] for the click action of a privacy dashboard app usage event. */
+ fun createHistoryPreferenceClickIntent(
+ context: Context,
+ userHandle: UserHandle,
+ packageName: String,
+ permissionGroup: String,
+ accessStartTime: Long,
+ accessEndTime: Long,
+ showingAttribution: Boolean,
+ attributionTags: List<String>
+ ): Intent {
+ return getManagePermissionUsageIntent(
+ context,
+ packageName,
+ permissionGroup,
+ accessStartTime,
+ accessEndTime,
+ showingAttribution,
+ attributionTags)
+ ?: getDefaultManageAppPermissionsIntent(packageName, userHandle)
+ }
+
+ /**
+ * Gets an [Intent.ACTION_MANAGE_PERMISSION_USAGE] intent, or null if attribution shouldn't
+ * be shown or the intent can't be handled.
+ */
+ private fun getManagePermissionUsageIntent(
+ context: Context,
+ packageName: String,
+ permissionGroup: String,
+ accessStartTime: Long,
+ accessEndTime: Long,
+ showingAttribution: Boolean,
+ attributionTags: List<String>
+ ): Intent? {
+ // TODO(b/255992934) only location provider apps should be able to provide this intent
+ if (!showingAttribution || !SdkLevel.isAtLeastT()) {
+ return null
+ }
+ val intent =
+ Intent(Intent.ACTION_MANAGE_PERMISSION_USAGE).apply {
+ setPackage(packageName)
+ putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, permissionGroup)
+ putExtra(Intent.EXTRA_ATTRIBUTION_TAGS, attributionTags.toTypedArray())
+ putExtra(Intent.EXTRA_START_TIME, accessStartTime)
+ putExtra(Intent.EXTRA_END_TIME, accessEndTime)
+ putExtra(IntentCompat.EXTRA_SHOWING_ATTRIBUTION, showingAttribution)
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
+ 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)) {
+ return null
+ }
+ intent.component = ComponentName(packageName, resolveInfo.activityInfo.name)
+ return intent
+ }
+
+ private fun getDefaultManageAppPermissionsIntent(
+ packageName: String,
+ userHandle: UserHandle
+ ): Intent {
+ return Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS).apply {
+ putExtra(Intent.EXTRA_USER, userHandle)
+ putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
+ }
+ }
+ }
+
+ /** Factory for [PermissionUsageDetailsViewModel]. */
+ @RequiresApi(Build.VERSION_CODES.S)
+ class PermissionUsageDetailsViewModelFactory(
+ val app: Application,
+ owner: SavedStateRegistryOwner,
+ private val permissionGroup: String,
+ ) : AbstractSavedStateViewModelFactory(owner, Bundle()) {
+ override fun <T : ViewModel> create(
+ key: String,
+ modelClass: Class<T>,
+ handle: SavedStateHandle,
+ ): T {
+ @Suppress("UNCHECKED_CAST")
+ return PermissionUsageDetailsViewModel(app, handle, permissionGroup) as T
+ }
}
}
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 8b2f05dad..4a952efd7 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
@@ -18,238 +18,361 @@
package com.android.permissioncontroller.permission.ui.model.v31
import android.Manifest
-import android.app.LoaderManager
+import android.app.Application
import android.app.role.RoleManager
-import android.content.Context
import android.os.Build
-import android.util.ArrayMap
-import android.util.ArraySet
-import android.util.Log
+import android.os.Bundle
+import android.os.UserHandle
import androidx.annotation.RequiresApi
+import androidx.lifecycle.AbstractSavedStateViewModelFactory
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-import com.android.permissioncontroller.permission.model.AppPermissionGroup
-import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage
-import com.android.permissioncontroller.permission.model.v31.PermissionUsages
-import com.android.permissioncontroller.permission.model.legacy.PermissionApps.PermissionApp
-import com.android.permissioncontroller.permission.ui.handheld.v31.is7DayToggleEnabled
-import com.android.permissioncontroller.permission.utils.KotlinUtils.getPermGroupLabel
+import androidx.savedstate.SavedStateRegistryOwner
+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.StandardPermGroupNamesLiveData
+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
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.Companion.SHOULD_SHOW_SYSTEM_KEY
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageViewModel.Companion.SHOULD_SHOW_7_DAYS_KEY
+import com.android.permissioncontroller.permission.utils.KotlinUtils
+import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.utils.Utils
import java.time.Instant
import java.util.concurrent.TimeUnit
import kotlin.math.max
-@RequiresApi(Build.VERSION_CODES.S)
-class PermissionUsageViewModel(val roleManager: RoleManager) : ViewModel() {
+/**
+ * [ViewModel] for handheld Permissions Usage UI.
+ *
+ * Note that this class replaces [PermissionUsageViewModelLegacy] to rely on [LiveData] instead of
+ * [PermissionUsages] loader.
+ */
+class PermissionUsageViewModel(
+ private val state: SavedStateHandle,
+ app: Application,
+) : AndroidViewModel(app) {
+ private val roleManager =
+ Utils.getSystemServiceSafe(app.applicationContext, RoleManager::class.java)
+ private val exemptedPackages: Set<String> = Utils.getExemptedPackages(roleManager)
- companion object {
- private const val LOG_TAG = "PermissionUsageViewModel"
+ private val mAllLightPackageOpsLiveData = AllLightPackageOpsLiveData(app)
+ private val appPermGroupUiInfoLiveDataList =
+ mutableMapOf<AppPermissionId, AppPermGroupUiInfoLiveData>()
+ private val lightPackageInfoLiveDataMap =
+ mutableMapOf<Pair<String, UserHandle>, LightPackageInfoLiveData>()
+ private val standardPermGroupNamesLiveData = StandardPermGroupNamesLiveData
- /** TODO(ewol): Use the config setting to determine amount of time to show. */
- private val TIME_FILTER_MILLIS = TimeUnit.DAYS.toMillis(7)
- private val TIME_7_DAYS_DURATION = TimeUnit.DAYS.toMillis(7)
- private val TIME_24_HOURS_DURATION = TimeUnit.DAYS.toMillis(1)
+ val showSystemAppsLiveData = state.getLiveData(SHOULD_SHOW_SYSTEM_KEY, false)
+ val show7DaysLiveData = state.getLiveData(SHOULD_SHOW_7_DAYS_KEY, false)
- @JvmStatic
- val PERMISSION_GROUP_ORDER: Map<String, Int> = mapOf(
- Manifest.permission_group.LOCATION to 0,
- Manifest.permission_group.CAMERA to 1,
- Manifest.permission_group.MICROPHONE to 2
- )
- private const val DEFAULT_ORDER = 3
+ /** Updates whether system app permissions usage should be displayed in the UI. */
+ fun updateShowSystem(showSystem: Boolean) {
+ if (showSystem != state[SHOULD_SHOW_SYSTEM_KEY]) {
+ state[SHOULD_SHOW_SYSTEM_KEY] = showSystem
+ }
}
- fun loadPermissionUsages(
- loaderManager: LoaderManager,
- permissionUsages: PermissionUsages,
- callback: PermissionUsages.PermissionsUsagesChangeCallback
- ) {
- val filterTimeBeginMillis = max(System.currentTimeMillis() - TIME_FILTER_MILLIS,
- Instant.EPOCH.toEpochMilli())
- permissionUsages.load(null /*filterPackageName*/, null /*filterPermissionGroups*/,
- filterTimeBeginMillis, Long.MAX_VALUE, PermissionUsages.USAGE_FLAG_LAST
- or PermissionUsages.USAGE_FLAG_HISTORICAL, loaderManager,
- false /*getUiInfo*/, false /*getNonPlatformPermissions*/, callback /*callback*/,
- false /*sync*/)
+ /** Updates whether 7 days usage or 1 day usage should be displayed in the UI. */
+ fun updateShow7Days(show7Days: Boolean) {
+ if (show7Days != state[SHOULD_SHOW_7_DAYS_KEY]) {
+ state[SHOULD_SHOW_7_DAYS_KEY] = show7Days
+ }
}
- fun extractUsages(
- permissionUsages: List<AppPermissionUsage>,
- show7Days: Boolean,
- showSystem: Boolean
- ): Triple<MutableMap<String, Int>, ArrayList<PermissionApp>, Boolean> {
+ /** Builds a [PermissionUsagesUiData] containing all the data necessary to render the UI. */
+ private fun buildPermissionUsagesUiData(): PermissionUsagesUiData {
val curTime = System.currentTimeMillis()
- val showPermissionUsagesDuration = if (is7DayToggleEnabled() && show7Days) {
- TIME_7_DAYS_DURATION
- } else {
- TIME_24_HOURS_DURATION
- }
+ val showSystem: Boolean = state[SHOULD_SHOW_SYSTEM_KEY] ?: false
+ val show7Days: Boolean = state[SHOULD_SHOW_7_DAYS_KEY] ?: false
+ val showPermissionUsagesDuration =
+ if (KotlinUtils.is7DayToggleEnabled() && show7Days) {
+ TIME_7_DAYS_DURATION
+ } else {
+ TIME_24_HOURS_DURATION
+ }
val startTime = max(curTime - showPermissionUsagesDuration, Instant.EPOCH.toEpochMilli())
+ return PermissionUsagesUiData(
+ showSystem,
+ show7Days,
+ mAllLightPackageOpsLiveData.containsSystemAppUsages(startTime),
+ mAllLightPackageOpsLiveData.buildPermissionGroupsWithUsageCounts(startTime, showSystem))
+ }
- // Permission group to count mapping.
- val usages: MutableMap<String, Int> = HashMap()
- val permissionGroups: List<AppPermissionGroup> = getOSPermissionGroups(permissionUsages)
- for (i in permissionGroups.indices) {
- usages[permissionGroups[i].name] = 0
+ /** Builds a map of permission groups to the number of apps that recently accessed them. */
+ private fun AllLightPackageOpsLiveData.buildPermissionGroupsWithUsageCounts(
+ startTime: Long,
+ showSystem: Boolean,
+ ): Map<String, Int> {
+ val permissionUsageCountMap: MutableMap<String, Int> = HashMap()
+ for (permissionGroup: String in getAllEligiblePermissionGroups()) {
+ permissionUsageCountMap[permissionGroup] = 0
}
- val permApps = ArrayList<PermissionApp>()
- val exemptedPackages = Utils.getExemptedPackages(roleManager)
+ val eligibleLightPackageOpsList: List<LightPackageOps> =
+ getAllLightPackageOps()?.filterOutExemptedApps() ?: listOf()
- val seenSystemApp: Boolean = extractPermissionUsage(exemptedPackages,
- usages, permApps, startTime, permissionUsages, showSystem)
+ for (lightPackageOps: LightPackageOps in eligibleLightPackageOpsList) {
+ val permGroupsToLastAccess: List<Map.Entry<String, Long>> =
+ lightPackageOps.lastPermissionGroupAccessTimesMs.entries
+ .filterOutExemptedPermissionGroupsFromKeys()
+ .filterOutPermissionsNotRequestedByApp(
+ lightPackageOps.packageName, lightPackageOps.userHandle)
+ .filterOutSystemAppPermissionsIfNecessary(
+ showSystem, lightPackageOps.packageName, lightPackageOps.userHandle)
+ .filterAccessTimeLaterThan(startTime)
+ val recentlyUsedPermissions: List<String> = permGroupsToLastAccess.map { it.key }
- return Triple(usages, permApps, seenSystemApp)
+ for (permissionGroup: String in recentlyUsedPermissions) {
+ permissionUsageCountMap[permissionGroup] =
+ permissionUsageCountMap.getOrDefault(permissionGroup, 0) + 1
+ }
+ }
+ return permissionUsageCountMap
}
- fun createGroupUsagesList(
- context: Context,
- usages: Map<String, Int>
- ): List<Map.Entry<String, Int>> {
- val groupUsageNameToLabel: MutableMap<String, CharSequence> = HashMap()
- val groupUsagesList: MutableList<Map.Entry<String, Int>> = ArrayList(usages.entries)
- val usagesEntryCount = groupUsagesList.size
- for (usageEntryIndex in 0 until usagesEntryCount) {
- val (key) = groupUsagesList[usageEntryIndex]
- groupUsageNameToLabel[key] = getPermGroupLabel(context, key)
+ /**
+ * Determines whether there are any system app permissions with recent usage, in which case the
+ * "show/hide system" toggle should be displayed in the UI.
+ */
+ private fun AllLightPackageOpsLiveData.containsSystemAppUsages(startTime: Long): Boolean {
+ val eligibleLightPackageOpsList: List<LightPackageOps> =
+ getAllLightPackageOps()?.filterOutExemptedApps() ?: listOf()
+
+ for (lightPackageOps: LightPackageOps in eligibleLightPackageOpsList) {
+ val recentlyUsedPermissions: Set<String> =
+ lightPackageOps.lastPermissionGroupAccessTimesMs.entries
+ .filterAccessTimeLaterThan(startTime)
+ .map { it.key }
+ .toSet()
+ if (recentlyUsedPermissions
+ .filterOutExemptedPermissionGroups()
+ .containsSystemAppPermission(
+ lightPackageOps.packageName, lightPackageOps.userHandle)) {
+ return true
+ }
}
- groupUsagesList.sortWith { e1: Map.Entry<String, Int>, e2: Map.Entry<String, Int> ->
- comparePermissionGroupUsage(e1, e2, groupUsageNameToLabel)
+ return false
+ }
+
+ /** Returns all permission groups eligible for display in the UI. */
+ private fun getAllEligiblePermissionGroups(): Set<String> =
+ standardPermGroupNamesLiveData.value?.filterOutExemptedPermissionGroups()?.toSet()
+ ?: setOf()
+
+ private fun isPermissionRequestedByApp(appPermissionId: AppPermissionId): Boolean {
+ val appRequestedPermissions =
+ lightPackageInfoLiveDataMap[
+ Pair(appPermissionId.packageName, appPermissionId.userHandle)]
+ ?.value
+ ?.requestedPermissions
+ ?: listOf()
+ return appRequestedPermissions.any {
+ PermissionMapping.getGroupOfPlatformPermission(it) == appPermissionId.permissionGroup
}
+ }
+
+ private fun isAppPermissionSystem(appPermissionId: AppPermissionId): Boolean {
+ val appPermGroupUiInfo = appPermGroupUiInfoLiveDataList[appPermissionId]?.value
- return groupUsagesList
+ if (appPermGroupUiInfo != null) {
+ return appPermGroupUiInfo.isSystem
+ } else
+ // The AppPermGroupUiInfo may be null if it has either not loaded yet or if the app has not
+ // requested any permissions from the permission group in question.
+ // 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)) {
+ return true
+ }
+ return false
}
- private fun comparePermissionGroupUsage(
- first: Map.Entry<String, Int>,
- second: Map.Entry<String, Int>,
- groupUsageNameToLabelMapping: Map<String, CharSequence>
- ): Int {
- val firstPermissionOrder = PERMISSION_GROUP_ORDER
- .getOrDefault(first.key, DEFAULT_ORDER)
- val secondPermissionOrder = PERMISSION_GROUP_ORDER
- .getOrDefault(second.key, DEFAULT_ORDER)
- return if (firstPermissionOrder != secondPermissionOrder) {
- firstPermissionOrder - secondPermissionOrder
- } else groupUsageNameToLabelMapping[first.key].toString()
- .compareTo(groupUsageNameToLabelMapping[second.key].toString())
+ private fun AllLightPackageOpsLiveData.getAllLightPackageOps() = value?.values
+
+ /**
+ * Filters out accesses earlier than the provided start time from a map of permission last
+ * accesses.
+ */
+ private fun Collection<Map.Entry<String, Long>>.filterAccessTimeLaterThan(startTime: Long) =
+ filter {
+ it.value > startTime
+ }
+
+ /** Filters out app permissions when the permission has not been requested by the app. */
+ private fun Collection<Map.Entry<String, Long>>.filterOutPermissionsNotRequestedByApp(
+ packageName: String,
+ userHandle: UserHandle
+ ) = filter { isPermissionRequestedByApp(AppPermissionId(packageName, userHandle, it.key)) }
+
+ /**
+ * Filters out system app permissions from a map of permission last accesses, if showSystem is
+ * false.
+ */
+ private fun Collection<Map.Entry<String, Long>>.filterOutSystemAppPermissionsIfNecessary(
+ showSystem: Boolean,
+ packageName: String,
+ userHandle: UserHandle
+ ) = filter {
+ showSystem || !isAppPermissionSystem(AppPermissionId(packageName, userHandle, it.key))
}
/**
- * Get the permission groups declared by the OS.
- *
- * @return a list of the permission groups declared by the OS.
+ * Filters out permission groups that are exempt from permission usage tracking from a map of
+ * permission last accesses.
*/
- private fun getOSPermissionGroups(
- permissionUsages: List<AppPermissionUsage>
- ): List<AppPermissionGroup> {
- val groups: MutableList<AppPermissionGroup> = java.util.ArrayList()
- val seenGroups: MutableSet<String> = ArraySet()
- val numGroups: Int = permissionUsages.size
- for (i in 0 until numGroups) {
- val appUsage: AppPermissionUsage = permissionUsages.get(i)
- val groupUsages = appUsage.groupUsages
- val groupUsageCount = groupUsages.size
- for (j in 0 until groupUsageCount) {
- val groupUsage = groupUsages[j]
- if (Utils.isModernPermissionGroup(groupUsage.group.name)) {
- if (seenGroups.add(groupUsage.group.name)) {
- groups.add(groupUsage.group)
- }
- }
- }
+ private fun Collection<Map.Entry<String, Long>>.filterOutExemptedPermissionGroupsFromKeys() =
+ filter {
+ !EXEMPTED_PERMISSION_GROUPS.contains(it.key)
}
- return groups
+
+ /**
+ * Filters out permission groups that are exempt from permission usage tracking from a map of
+ * permission last accesses.
+ */
+ private fun Collection<String>.filterOutExemptedPermissionGroups() = filter {
+ !EXEMPTED_PERMISSION_GROUPS.contains(it)
+ }
+
+ /** Filters out [LightPackageOps] for apps that are exempt from permission usage tracking. */
+ private fun Collection<LightPackageOps>.filterOutExemptedApps() = filter {
+ !exemptedPackages.contains(it.packageName)
}
/**
- * Extract the permission usages from mAppPermissionUsages and put the extracted usages
- * into usages and permApps. Returns whether we have seen a system app during the process.
- *
- * TODO: theianchen
- * It's doing two things at the same method which is violating the SOLID principle.
- * We should fix this.
- *
- * @param exemptedPackages packages that are the role holders for exempted roles
- * @param usages an empty List that will be filled with permission usages.
- * @param permApps an empty List that will be filled with permission apps.
- * @return whether we have seen a system app.
+ * Returns from a list of permissions whether any permission along with the provided package
+ * name and user handle are considered a system app permission.
*/
- private fun extractPermissionUsage(
- exemptedPackages: Set<String>,
- usages: MutableMap<String, Int>,
- permApps: java.util.ArrayList<PermissionApp>,
- startTime: Long,
- permissionUsages: List<AppPermissionUsage>,
- showSystem: Boolean
- ): Boolean {
-
- val mGroupAppCounts: ArrayMap<String?, Int> = ArrayMap()
- var seenSystemApp = false
- val numApps: Int = permissionUsages.size
- for (appNum in 0 until numApps) {
- val appUsage: AppPermissionUsage = permissionUsages.get(appNum)
- if (exemptedPackages.contains(appUsage.packageName)) {
- continue
+ private fun Collection<String>.containsSystemAppPermission(
+ packageName: String,
+ userHandle: UserHandle
+ ) = any { isAppPermissionSystem(AppPermissionId(packageName, userHandle, it)) }
+
+ /** Data class to hold all the information required to configure the UI. */
+ data class PermissionUsagesUiData(
+ /**
+ * Whether to show data over the last 7 days.
+ *
+ * While this information is available from the [SHOULD_SHOW_7_DAYS_KEY] state, we include
+ * it in the UI info so that it triggers a UI update when changed.
+ */
+ private val show7DaysUsage: Boolean,
+ /**
+ * Whether to show system apps' data.
+ *
+ * While this information is available from the [SHOULD_SHOW_SYSTEM_KEY] state, we include
+ * it in the UI info so that it triggers a UI update when changed.
+ */
+ private val showSystem: Boolean,
+ /** Whether to show the "show/hide system" toggle. */
+ val containsSystemAppUsages: Boolean,
+ /** Map instances for display in UI */
+ val permissionGroupsWithUsageCount: Map<String, Int>,
+ )
+
+ /** LiveData object for [PermissionUsagesUiData]. */
+ val permissionUsagesUiLiveData =
+ object : SmartUpdateMediatorLiveData<@JvmSuppressWildcards PermissionUsagesUiData>() {
+ private val getAppPermGroupUiInfoLiveData = { appPermissionId: AppPermissionId ->
+ AppPermGroupUiInfoLiveData[
+ Triple(
+ appPermissionId.packageName,
+ appPermissionId.permissionGroup,
+ appPermissionId.userHandle,
+ )]
+ }
+ private val getLightPackageInfoLiveData = { packageUser: Pair<String, UserHandle> ->
+ LightPackageInfoLiveData[packageUser]
}
- var used = false
- val appGroups = appUsage.groupUsages
- val numGroups = appGroups.size
- for (groupNum in 0 until numGroups) {
- val groupUsage = appGroups[groupNum]
- val groupName = groupUsage.group.name
- val lastAccessTime = groupUsage.lastAccessTime
- if (lastAccessTime == 0L) {
- Log.w(
- LOG_TAG,
- "Unexpected access time of 0 for ${appUsage.app.key} " +
- groupUsage.group.name)
- continue
+
+ init {
+ addSource(mAllLightPackageOpsLiveData) { update() }
+ addSource(showSystemAppsLiveData) { update() }
+ addSource(show7DaysLiveData) { update() }
+ addSource(standardPermGroupNamesLiveData) { update() }
+ }
+
+ override fun onUpdate() {
+ if (mAllLightPackageOpsLiveData.isStale) {
+ return
+ }
+
+ val appPermissionIds = mutableListOf<AppPermissionId>()
+ val allPackages = mAllLightPackageOpsLiveData.value?.keys ?: setOf()
+ for (packageWithUserHandle: Pair<String, UserHandle> in allPackages) {
+ for (permissionGroup in getAllEligiblePermissionGroups()) {
+ appPermissionIds.add(
+ AppPermissionId(
+ packageWithUserHandle.first,
+ packageWithUserHandle.second,
+ permissionGroup,
+ ))
+ }
+ }
+
+ setSourcesToDifference(
+ appPermissionIds,
+ appPermGroupUiInfoLiveDataList,
+ getAppPermGroupUiInfoLiveData) {
+ update()
+ }
+
+ setSourcesToDifference(
+ allPackages, lightPackageInfoLiveDataMap, getLightPackageInfoLiveData) {
+ update()
+ }
+
+ if (lightPackageInfoLiveDataMap.any { it.value.isStale }) {
+ return
}
- if (lastAccessTime < startTime) {
- continue
+
+
+ if (appPermGroupUiInfoLiveDataList.any { it.value.isStale }) {
+ return
}
- val isSystemApp = !Utils.isGroupOrBgGroupUserSensitive(
- groupUsage.group)
- seenSystemApp = seenSystemApp || isSystemApp
- // If not showing system apps, skip.
- if (!showSystem && isSystemApp) {
- continue
+ val uiData = buildPermissionUsagesUiData()
+ // We include this check as we don't want UX updates unless the data to be displayed
+ // has changed. SmartUpdateMediatorLiveData sends updates if the data has changed OR
+ // if the data has changed from stale to fresh.
+ if (value != uiData) {
+ value = uiData
}
- used = true
- addGroupUser(mGroupAppCounts, groupName)
- usages[groupName] = usages.getOrDefault(groupName, 0) + 1
- }
- if (used) {
- permApps.add(appUsage.app)
- addGroupUser(mGroupAppCounts, null)
}
}
- return seenSystemApp
- }
- private fun addGroupUser(groupAppCounts: ArrayMap<String?, Int>, app: String?) {
- val count: Int? = groupAppCounts[app]
- if (count == null) {
- groupAppCounts[app] = 1
- } else {
- groupAppCounts[app] = count + 1
- }
+ /** Companion class for [PermissionUsageViewModel]. */
+ companion object {
+ private val TIME_7_DAYS_DURATION = TimeUnit.DAYS.toMillis(7)
+ private val TIME_24_HOURS_DURATION = TimeUnit.DAYS.toMillis(1)
+ internal const val SHOULD_SHOW_SYSTEM_KEY = "showSystem"
+ internal const val SHOULD_SHOW_7_DAYS_KEY = "show7Days"
+ private const val TELECOM_PACKAGE = "com.android.server.telecom"
+
+ /** Permission groups that should be hidden from the permissions usage UI. */
+ private val EXEMPTED_PERMISSION_GROUPS = setOf(Manifest.permission_group.NOTIFICATIONS)
}
-}
-/**
- * Factory for an PermissionUsageViewModel
- */
-@RequiresApi(Build.VERSION_CODES.S)
-class PermissionUsageViewModelFactory(
- private val roleManager: RoleManager
-) : ViewModelProvider.Factory {
-
- override fun <T : ViewModel> create(modelClass: Class<T>): T {
- @Suppress("UNCHECKED_CAST")
- return PermissionUsageViewModel(roleManager) as T
+ /** Factory for [PermissionUsageViewModel]. */
+ @RequiresApi(Build.VERSION_CODES.S)
+ class PermissionUsageViewModelFactory(
+ val app: Application,
+ owner: SavedStateRegistryOwner,
+ defaultArgs: Bundle
+ ) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
+ override fun <T : ViewModel> create(
+ key: String,
+ modelClass: Class<T>,
+ handle: SavedStateHandle
+ ): T {
+ @Suppress("UNCHECKED_CAST") return PermissionUsageViewModel(handle, app) as T
+ }
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ReviewOngoingUsageViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/ReviewOngoingUsageViewModel.kt
index 4efed307c..d6efd38a6 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ReviewOngoingUsageViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/ReviewOngoingUsageViewModel.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
@file:Suppress("DEPRECATION")
-package com.android.permissioncontroller.permission.ui.model
+package com.android.permissioncontroller.permission.ui.model.v31
import android.Manifest
import android.Manifest.permission_group.CAMERA
@@ -47,15 +47,15 @@ import com.android.permissioncontroller.permission.data.PermGroupUsageLiveData
import com.android.permissioncontroller.permission.data.SmartAsyncMediatorLiveData
import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData
import com.android.permissioncontroller.permission.data.micMutedLiveData
-import com.android.permissioncontroller.permission.ui.handheld.v31.shouldShowLocationIndicators
-import com.android.permissioncontroller.permission.ui.handheld.v31.shouldShowPermissionsDashboard
import com.android.permissioncontroller.permission.ui.handheld.v31.ReviewOngoingUsageFragment.PHONE_CALL
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 kotlinx.coroutines.Job
import java.time.Instant
import kotlin.math.max
+import kotlinx.coroutines.Job
private const val FIRST_OPENED_KEY = "FIRST_OPENED"
private const val CALL_OP_USAGE_KEY = "CALL_OP_USAGE"
@@ -551,10 +551,14 @@ class ReviewOngoingUsageViewModelFactory(
owner: SavedStateRegistryOwner,
defaultArgs: Bundle
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
- override fun <T : ViewModel> create(p0: String, p1: Class<T>, state: SavedStateHandle): T {
- state.set(FIRST_OPENED_KEY, state.get<Long>(FIRST_OPENED_KEY)
+ override fun <T : ViewModel> create(
+ key: String,
+ modelClass: Class<T>,
+ handle: SavedStateHandle
+ ): T {
+ handle.set(FIRST_OPENED_KEY, handle.get<Long>(FIRST_OPENED_KEY)
?: System.currentTimeMillis())
@Suppress("UNCHECKED_CAST")
- return ReviewOngoingUsageViewModel(state, extraDurationMillis) as T
+ 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 8e523be90..69709264b 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,6 +28,7 @@ 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,7 +38,6 @@ 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.StringUtils
-import com.android.permissioncontroller.permission.utils.Utils
import kotlinx.coroutines.Job
import java.util.concurrent.TimeUnit
@@ -88,7 +88,7 @@ class ReviewPermissionDecisionsViewModel(val app: Application, val user: UserHan
continue
}
val grantedGroups: List<String?> = lightPackageInfo.grantedPermissions.map {
- Utils.getGroupOfPermission(
+ PermissionMapping.getGroupOfPermission(
app.packageManager.getPermissionInfo(it, /* flags= */ 0))
}
val currentlyGranted = grantedGroups.contains(recentDecision.permissionGroupName)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/AppDataSharingUpdatesViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/AppDataSharingUpdatesViewModel.kt
new file mode 100644
index 000000000..7f5a87552
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/AppDataSharingUpdatesViewModel.kt
@@ -0,0 +1,191 @@
+/*
+ * 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.permissioncontroller.permission.ui.model.v34
+
+import android.Manifest
+import android.app.Activity
+import android.app.Application
+import android.content.ActivityNotFoundException
+import android.content.Context
+import android.content.Intent
+import android.content.Intent.ACTION_MANAGE_APP_PERMISSION
+import android.content.Intent.EXTRA_PACKAGE_NAME
+import android.content.Intent.EXTRA_PERMISSION_GROUP_NAME
+import android.content.Intent.EXTRA_USER
+import android.net.Uri
+import android.os.Build
+import android.os.UserHandle
+import android.util.Log
+import androidx.annotation.RequiresApi
+import com.android.permission.safetylabel.DataCategoryConstants.CATEGORY_LOCATION
+import com.android.permissioncontroller.Constants.EXTRA_SESSION_ID
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.data.SinglePermGroupPackagesUiInfoLiveData
+import com.android.permissioncontroller.permission.data.SmartAsyncMediatorLiveData
+import com.android.permissioncontroller.permission.data.v34.AppDataSharingUpdatesLiveData
+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
+import com.android.permissioncontroller.permission.model.v34.DataSharingUpdateType
+import com.android.settingslib.HelpUtils
+import kotlinx.coroutines.Job
+
+/** View model for data sharing updates UI. */
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+class AppDataSharingUpdatesViewModel(app: Application) {
+
+ private val appDataSharingUpdatesLiveData = AppDataSharingUpdatesLiveData(app)
+ private val locationPermGroupPackagesUiInfoLiveData =
+ SinglePermGroupPackagesUiInfoLiveData[Manifest.permission_group.LOCATION]
+
+ /** Returns whether UI can provide link to help center */
+ fun canLinkToHelpCenter(context: Context): Boolean {
+ return !getHelpCenterUrlString(context).isNullOrEmpty()
+ }
+
+ /** Opens the Safety Label Help Center web page. */
+ fun openSafetyLabelsHelpCenterPage(activity: Activity) {
+ if (!canLinkToHelpCenter(activity)) {
+ Log.w(LOG_TAG, "Unable to open help center, no url provided.")
+ return
+ }
+
+ // 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)
+ }
+ try {
+ activity.startActivity(intent)
+ } catch (e: ActivityNotFoundException) {
+ // TODO(b/266755891): show snackbar when help center intent unable to be opened
+ Log.w(LOG_TAG, "Unable to open help center URL.", e)
+ }
+ }
+
+ /**
+ * Starts the App Permission fragment for location permission for the provided packageName and
+ * userHandle.
+ */
+ fun startAppLocationPermissionPage(
+ activity: Activity,
+ sessionId: Long,
+ packageName: String,
+ userHandle: UserHandle
+ ) {
+ activity.startActivity(
+ Intent(ACTION_MANAGE_APP_PERMISSION).apply {
+ putExtra(EXTRA_SESSION_ID, sessionId)
+ putExtra(EXTRA_PERMISSION_GROUP_NAME, Manifest.permission_group.LOCATION)
+ putExtra(EXTRA_PACKAGE_NAME, packageName)
+ putExtra(EXTRA_USER, userHandle)
+ }
+ )
+ }
+
+ /**
+ * Builds a list of [AppLocationDataSharingUpdateUiInfo], containing all the information
+ * required to render the app data sharing updates.
+ */
+ private fun buildAppLocationDataSharingUpdateUiInfoList():
+ List<AppLocationDataSharingUpdateUiInfo> {
+ val appDataSharingUpdates = appDataSharingUpdatesLiveData.value ?: return listOf()
+
+ return appDataSharingUpdates
+ .map { appDataSharingUpdate ->
+ val locationDataSharingUpdate =
+ appDataSharingUpdate.categorySharingUpdates[CATEGORY_LOCATION]
+
+ if (locationDataSharingUpdate == null) {
+ emptyList()
+ } else {
+ val users =
+ locationPermGroupPackagesUiInfoLiveData.getUsersWithPermGrantedForApp(
+ appDataSharingUpdate.packageName
+ )
+ users.map { user ->
+ // For each user profile under the current user, display one entry.
+ AppLocationDataSharingUpdateUiInfo(
+ appDataSharingUpdate.packageName,
+ user,
+ locationDataSharingUpdate
+ )
+ }
+ }
+ }
+ .flatten()
+ }
+
+ private fun getHelpCenterUrlString(context: Context): String? {
+ return context.getString(R.string.data_sharing_help_center_link)
+ }
+
+ private fun SinglePermGroupPackagesUiInfoLiveData.getUsersWithPermGrantedForApp(
+ packageName: String
+ ): List<UserHandle> {
+ return value
+ ?.filter {
+ packageToPermInfoEntry: Map.Entry<Pair<String, UserHandle>, AppPermGroupUiInfo> ->
+ val appPermGroupUiInfo = packageToPermInfoEntry.value
+
+ appPermGroupUiInfo.isPermissionGranted()
+ }
+ ?.keys
+ ?.filter { packageUser: Pair<String, UserHandle> -> packageUser.first == packageName }
+ ?.map { packageUser: Pair<String, UserHandle> -> packageUser.second }
+ ?: listOf()
+ }
+
+ private fun AppPermGroupUiInfo.isPermissionGranted() =
+ permGrantState == PERMS_ALLOWED_ALWAYS || permGrantState == PERMS_ALLOWED_FOREGROUND_ONLY
+
+ /** All the information necessary to display an app's data sharing update in the UI. */
+ data class AppLocationDataSharingUpdateUiInfo(
+ val packageName: String,
+ val userHandle: UserHandle,
+ val dataSharingUpdateType: DataSharingUpdateType
+ )
+
+ /** LiveData for all data sharing updates to be displayed in the UI. */
+ val appLocationDataSharingUpdateUiInfoLiveData =
+ object : SmartAsyncMediatorLiveData<List<AppLocationDataSharingUpdateUiInfo>>() {
+
+ init {
+ addSource(appDataSharingUpdatesLiveData) { onUpdate() }
+ addSource(locationPermGroupPackagesUiInfoLiveData) { onUpdate() }
+ }
+
+ override suspend fun loadDataAndPostValue(job: Job) {
+ if (locationPermGroupPackagesUiInfoLiveData.isStale) {
+ return
+ }
+
+ if (appDataSharingUpdatesLiveData.isStale) {
+ return
+ }
+
+ postValue(buildAppLocationDataSharingUpdateUiInfoList())
+ }
+ }
+
+ /** Companion object for [AppDataSharingUpdatesViewModel]. */
+ companion object {
+ private val LOG_TAG = AppDataSharingUpdatesViewModel::class.java.simpleName
+ }
+}
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
new file mode 100644
index 000000000..304dc3db4
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt
@@ -0,0 +1,263 @@
+/*
+ * 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.permissioncontroller.permission.ui.model.v34
+
+import android.app.Activity
+import android.app.Application
+import android.content.ActivityNotFoundException
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.os.Build
+import android.os.Bundle
+import android.os.Process
+import android.util.Log
+import androidx.annotation.RequiresApi
+import androidx.lifecycle.ViewModel
+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__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.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.v34.PermissionRationaleActivity
+import com.android.permissioncontroller.permission.utils.KotlinUtils
+import com.android.permissioncontroller.permission.utils.KotlinUtils.getAppStoreIntent
+import com.android.permissioncontroller.permission.utils.v34.SafetyLabelUtils
+import com.android.settingslib.HelpUtils
+
+/**
+ * [ViewModel] for the [PermissionRationaleActivity]. Gets all information required safety label and
+ * links required to inform user of data sharing usages by the app when granting this permission
+ *
+ * @param app: The current application
+ * @param packageName: The packageName permissions are being requested for
+ * @param permissionGroupName: The permission group requested
+ * @param sessionId: A long to identify this session
+ * @param storedState: Previous state, if this activity was stopped and is being recreated
+ */
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+class PermissionRationaleViewModel(
+ private val app: Application,
+ private val packageName: String,
+ private val permissionGroupName: String,
+ private val sessionId: Long,
+ private val storedState: Bundle?
+) : ViewModel() {
+ private val user = Process.myUserHandle()
+ private val safetyLabelInfoLiveData = SafetyLabelInfoLiveData[packageName, user]
+
+ /** Interface for forwarding onActivityResult to this view model */
+ interface ActivityResultCallback {
+ /**
+ * 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")
+ * @return {@code true} if Activity should finish after processing this result
+ */
+ fun shouldFinishActivityForResult(data: Intent?): Boolean
+ }
+ var activityResultCallback: ActivityResultCallback? = null
+
+ /**
+ * A class which represents a permission rationale for permission group, and messages which
+ * should be shown with it.
+ */
+ data class PermissionRationaleInfo(
+ 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 =
+ object : SmartUpdateMediatorLiveData<PermissionRationaleInfo>() {
+
+ init {
+ addSource(safetyLabelInfoLiveData) { onUpdate() }
+
+ // Load package state, if available
+ onUpdate()
+ }
+
+ override fun onUpdate() {
+ if (safetyLabelInfoLiveData.isStale) {
+ return
+ }
+
+ val safetyLabelInfo = safetyLabelInfoLiveData.value
+
+ if (safetyLabelInfo?.safetyLabel == null) {
+ Log.e(LOG_TAG, "Safety label for $packageName not found")
+ value = null
+ return
+ }
+
+ val installSourcePackageName =
+ safetyLabelInfo.installSourceInfo.initiatingPackageName
+ val installSourceLabel: String? =
+ installSourcePackageName?.let {
+ KotlinUtils.getPackageLabel(app, it, Process.myUserHandle())
+ }
+
+ val purposes = SafetyLabelUtils.getSafetyLabelSharingPurposesForGroup(
+ safetyLabelInfo.safetyLabel, permissionGroupName)
+ if (value == null) {
+ logPermissionRationaleDialogViewed(purposes)
+ }
+ value =
+ PermissionRationaleInfo(
+ permissionGroupName,
+ safetyLabelInfo.installSourceInfo.isPreloadedApp,
+ installSourcePackageName,
+ installSourceLabel,
+ purposes)
+ }
+ }
+
+ fun canLinkToAppStore(context: Context, installSourcePackageName: String): Boolean {
+ return getAppStoreIntent(context, installSourcePackageName, packageName) != null
+ }
+
+ fun sendToAppStore(context: Context, installSourcePackageName: String) {
+ logPermissionRationaleDialogActionReported(
+ PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED__BUTTON_PRESSED__INSTALL_SOURCE)
+ val storeIntent = getAppStoreIntent(context, installSourcePackageName, packageName)
+ context.startActivity(storeIntent)
+ }
+
+ /**
+ * Send the user to the AppPermissionFragment
+ *
+ * @param activity The current activity
+ * @param groupName The name of the permission group whose fragment should be opened
+ */
+ fun sendToSettingsForPermissionGroup(activity: Activity, groupName: String) {
+ 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)
+ }
+ }
+ logPermissionRationaleDialogActionReported(
+ PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED__BUTTON_PRESSED__PERMISSION_SETTINGS)
+ startAppPermissionFragment(activity, groupName)
+ }
+
+ /** Returns whether UI can provide link to help center */
+ fun canLinkToHelpCenter(context: Context): Boolean {
+ return !getHelpCenterUrlString(context).isNullOrEmpty()
+ }
+
+ /**
+ * Send the user to the Safety Label Android Help Center
+ *
+ * @param activity The current activity
+ */
+ fun sendToLearnMore(activity: Activity) {
+ if (!canLinkToHelpCenter(activity)) {
+ Log.w(LOG_TAG, "Unable to open help center, no url provided.")
+ return
+ }
+
+ // 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)
+ }
+ logPermissionRationaleDialogActionReported(
+ PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED__BUTTON_PRESSED__HELP_CENTER)
+ try {
+ activity.startActivity(intent)
+ } catch (e: ActivityNotFoundException) {
+ // TODO(b/266755891): show snackbar when help center intent unable to be opened
+ Log.w(LOG_TAG, "Unable to open help center URL.", e)
+ }
+ }
+
+ 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)
+ activity.startActivityForResult(intent, APP_PERMISSION_REQUEST_CODE)
+ }
+
+ private fun logPermissionRationaleDialogViewed(purposes: Set<Int>) {
+ val uid = KotlinUtils.getPackageUid(app, packageName, user) ?: return
+ var purposesPresented = 0
+ // Create bitmask for purposes presented, bit numbers are in accordance with PURPOSE_
+ // constants in [DataPurposeConstants]
+ purposes.forEach { purposeInt ->
+ purposesPresented = purposesPresented or 1.shl(purposeInt)
+ }
+ 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)
+ }
+
+ private fun getHelpCenterUrlString(context: Context): String? {
+ return context.getString(R.string.data_sharing_help_center_link)
+ }
+
+ companion object {
+ private val LOG_TAG = PermissionRationaleViewModel::class.java.simpleName
+
+ const val APP_PERMISSION_REQUEST_CODE = 1
+ }
+}
+
+/** Factory for a [PermissionRationaleViewModel] */
+class PermissionRationaleViewModelFactory(
+ private val app: Application,
+ private val packageName: String,
+ private val permissionGroupName: String,
+ private val sessionId: Long,
+ private val savedState: Bundle?
+) : ViewModelProvider.Factory {
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ @Suppress("UNCHECKED_CAST")
+ return PermissionRationaleViewModel(
+ app, packageName, permissionGroupName, sessionId, savedState)
+ as T
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/package-info.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/package-info.java
new file mode 100644
index 000000000..4e3697cfc
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+@androidx.annotation.RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+package com.android.permissioncontroller.permission.ui.model.v34;
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 a1a291937..e5c63f5ab 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AllAppPermissionsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AllAppPermissionsFragment.java
@@ -48,6 +48,7 @@ import androidx.preference.SwitchPreference;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.model.AppPermissionGroup;
import com.android.permissioncontroller.permission.model.AppPermissions;
+import com.android.permissioncontroller.permission.utils.PermissionMapping;
import com.android.permissioncontroller.permission.utils.Utils;
import java.util.ArrayList;
@@ -169,7 +170,8 @@ public final class AllAppPermissionsFragment extends SettingsWithHeader {
continue;
}
- PermissionGroupInfo group = getGroup(Utils.getGroupOfPermission(perm), pm);
+ PermissionGroupInfo group =
+ getGroup(PermissionMapping.getGroupOfPermission(perm), pm);
if (group != null && group.name.equals(NOTIFICATIONS)) {
// Skip notification group on TV
continue;
@@ -200,9 +202,9 @@ public final class AllAppPermissionsFragment extends SettingsWithHeader {
return 1;
} else if (rKey.equals(KEY_OTHER)) {
return -1;
- } else if (Utils.isModernPermissionGroup(lKey)
- != Utils.isModernPermissionGroup(rKey)) {
- return Utils.isModernPermissionGroup(lKey) ? -1 : 1;
+ } else if (PermissionMapping.isPlatformPermissionGroup(lKey)
+ != PermissionMapping.isPlatformPermissionGroup(rKey)) {
+ return PermissionMapping.isPlatformPermissionGroup(lKey) ? -1 : 1;
}
return lhs.getTitle().toString().compareTo(rhs.getTitle().toString());
}
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 016b7846c..e2df47009 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java
@@ -34,7 +34,6 @@ import static com.android.permissioncontroller.permission.ui.GrantPermissionsVie
import static com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_CALLER_NAME;
import static com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_RESULT_PERMISSION_INTERACTED;
import static com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_RESULT_PERMISSION_RESULT;
-import static com.android.permissioncontroller.permission.ui.handheld.UtilsKt.pressBack;
import android.app.Activity;
import android.app.AlertDialog;
@@ -67,13 +66,13 @@ import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.data.FullStoragePermissionAppsLiveData.FullStoragePackageState;
import com.android.permissioncontroller.permission.model.AppPermissionGroup;
import com.android.permissioncontroller.permission.model.AppPermissions;
-import com.android.permissioncontroller.permission.ui.AdvancedConfirmDialogArgs;
import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler;
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.model.AppPermissionViewModel.ChangeRequest;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModelFactory;
+import com.android.permissioncontroller.permission.ui.v33.AdvancedConfirmDialogArgs;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.Utils;
@@ -272,7 +271,7 @@ public class AppPermissionFragment extends SettingsWithHeader
private void setRadioButtonsState(Map<ButtonType, ButtonState> states) {
if (states == null && mViewModel.getButtonStateLiveData().isInitialized()) {
- pressBack(this);
+ getFragmentManager().popBackStack();
Log.w(LOG_TAG, "invalid package " + mPackageName + " or perm group "
+ mPermGroupName);
Toast.makeText(
@@ -504,6 +503,9 @@ public class AppPermissionFragment extends SettingsWithHeader
AlertDialog.Builder b = new AlertDialog.Builder(getContext())
.setIcon(args.getIconId())
.setMessage(args.getMessageId())
+ .setOnCancelListener((DialogInterface dialog) -> {
+ setRadioButtonsState(mViewModel.getButtonStateLiveData().getValue());
+ })
.setNegativeButton(args.getNegativeButtonTextId(),
(DialogInterface dialog, int which) -> {
setRadioButtonsState(mViewModel.getButtonStateLiveData().getValue());
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionsFragment.java
index f7a2c0a91..0f90cf6fe 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionsFragment.java
@@ -61,9 +61,9 @@ import com.android.permissioncontroller.permission.ui.model.AppPermissionGroupsV
import com.android.permissioncontroller.permission.ui.model.AppPermissionGroupsViewModelFactory;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.LocationUtils;
-import com.android.permissioncontroller.permission.utils.SafetyNetLogger;
import com.android.permissioncontroller.permission.utils.StringUtils;
import com.android.permissioncontroller.permission.utils.Utils;
+import com.android.permissioncontroller.permission.utils.legacy.LegacySafetyNetLogger;
public final class AppPermissionsFragment extends SettingsWithHeader
implements OnPreferenceClickListener {
@@ -377,7 +377,7 @@ public final class AppPermissionsFragment extends SettingsWithHeader
private void logToggledGroups() {
if (mToggledGroups != null) {
- SafetyNetLogger.logPermissionsToggled(mToggledGroups);
+ LegacySafetyNetLogger.logPermissionsToggled(mToggledGroups);
mToggledGroups = null;
}
}
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 fa7f8120b..45dd4c1f2 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/GrantPermissionsViewHandlerImpl.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/GrantPermissionsViewHandlerImpl.java
@@ -100,10 +100,12 @@ public final class GrantPermissionsViewHandlerImpl implements GrantPermissionsVi
mSoftDenyButton.setOnClickListener(this);
mHardDenyButton.setOnClickListener(this);
- mRootView.addOnLayoutChangeListener((view, l, t, r, b, oldL, oldT, oldR, oldB) -> {
- mRootView.setUnrestrictedPreferKeepClearRects(
- Collections.singletonList(new Rect(0, 0, r - l, b - t)));
- });
+ if (SdkLevel.isAtLeastT()) {
+ mRootView.addOnLayoutChangeListener((view, l, t, r, b, oldL, oldT, oldR, oldB) -> {
+ mRootView.setUnrestrictedPreferKeepClearRects(
+ Collections.singletonList(new Rect(0, 0, r - l, b - t)));
+ });
+ }
return mRootView;
}
@@ -144,8 +146,11 @@ public final class GrantPermissionsViewHandlerImpl implements GrantPermissionsVi
@Override
public void updateUi(String groupName, int groupCount, int groupIndex, Icon icon,
- CharSequence message, CharSequence detailMessage, boolean[] buttonVisibilities,
+ CharSequence message, CharSequence detailMessage,
+ CharSequence permissionRationaleMessage, boolean[] buttonVisibilities,
boolean[] locationVisibilities) {
+ // permissionRationaleMessage ignored by television
+
// TODO: Handle detailMessage
mGroupName = groupName;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionAppsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionAppsFragment.java
index a84239405..1109d6389 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionAppsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionAppsFragment.java
@@ -44,8 +44,8 @@ import com.android.permissioncontroller.permission.model.legacy.PermissionApps.C
import com.android.permissioncontroller.permission.model.legacy.PermissionApps.PermissionApp;
import com.android.permissioncontroller.permission.ui.ReviewPermissionsActivity;
import com.android.permissioncontroller.permission.utils.LocationUtils;
-import com.android.permissioncontroller.permission.utils.SafetyNetLogger;
import com.android.permissioncontroller.permission.utils.Utils;
+import com.android.permissioncontroller.permission.utils.legacy.LegacySafetyNetLogger;
public final class PermissionAppsFragment extends SettingsWithHeader implements Callback,
OnPreferenceClickListener {
@@ -432,7 +432,7 @@ public final class PermissionAppsFragment extends SettingsWithHeader implements
private void logToggledGroups() {
if (mToggledGroups != null) {
- SafetyNetLogger.logPermissionsToggled(mToggledGroups);
+ LegacySafetyNetLogger.logPermissionsToggled(mToggledGroups);
mToggledGroups = null;
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/AdvancedConfirmDialogArgs.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/v33/AdvancedConfirmDialogArgs.kt
index 6b26c7e47..b841f3aeb 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/AdvancedConfirmDialogArgs.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/v33/AdvancedConfirmDialogArgs.kt
@@ -1,28 +1,27 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
- * Licensed under the Apache License;
- * Version 2.0 (the "License");
+ * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing;
- * software
- * distributed under the License is distributed on an "AS IS" BASIS;
- *
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND;
- * either express or implied.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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
+package com.android.permissioncontroller.permission.ui.v33
+import android.os.Build
import androidx.annotation.DrawableRes
+import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
data class AdvancedConfirmDialogArgs(
@DrawableRes val iconId: Int = 0,
@StringRes val titleId: Int = 0,
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/widget/SafetyProtectionSectionView.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/v33/widget/SafetyProtectionSectionView.kt
index f1a1c972e..daea1c198 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/widget/SafetyProtectionSectionView.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/v33/widget/SafetyProtectionSectionView.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.ui.widget
+package com.android.permissioncontroller.permission.ui.v33.widget
import android.content.Context
import android.text.Html
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/v34/PermissionRationaleActivity.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/v34/PermissionRationaleActivity.java
new file mode 100644
index 000000000..606ce8157
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/v34/PermissionRationaleActivity.java
@@ -0,0 +1,610 @@
+/*
+ * 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.permissioncontroller.permission.ui.v34;
+
+import static android.Manifest.permission_group.LOCATION;
+import static android.content.Intent.EXTRA_PERMISSION_GROUP_NAME;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+
+import static androidx.core.util.Preconditions.checkStringNotEmpty;
+
+import static com.android.permission.safetylabel.DataPurposeConstants.PURPOSE_ACCOUNT_MANAGEMENT;
+import static com.android.permission.safetylabel.DataPurposeConstants.PURPOSE_ADVERTISING;
+import static com.android.permission.safetylabel.DataPurposeConstants.PURPOSE_ANALYTICS;
+import static com.android.permission.safetylabel.DataPurposeConstants.PURPOSE_APP_FUNCTIONALITY;
+import static com.android.permission.safetylabel.DataPurposeConstants.PURPOSE_DEVELOPER_COMMUNICATIONS;
+import static com.android.permission.safetylabel.DataPurposeConstants.PURPOSE_FRAUD_PREVENTION_SECURITY;
+import static com.android.permission.safetylabel.DataPurposeConstants.PURPOSE_PERSONALIZATION;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED__BUTTON_PRESSED__CANCEL;
+import static com.android.permissioncontroller.permission.ui.model.v34.PermissionRationaleViewModel.APP_PERMISSION_REQUEST_CODE;
+import static com.android.permissioncontroller.permission.ui.v34.PermissionRationaleViewHandler.Result.CANCELLED;
+
+import android.content.Intent;
+import android.content.res.Resources;
+import android.icu.lang.UCharacter;
+import android.os.Build;
+import android.os.Bundle;
+import android.text.Annotation;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
+import android.text.style.BulletSpan;
+import android.text.style.ClickableSpan;
+import android.util.Log;
+import android.util.Pair;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.StringRes;
+import androidx.core.util.Preconditions;
+
+import com.android.permission.safetylabel.DataPurposeConstants.Purpose;
+import com.android.permissioncontroller.Constants;
+import com.android.permissioncontroller.DeviceUtils;
+import com.android.permissioncontroller.R;
+import com.android.permissioncontroller.permission.ui.GrantPermissionsActivity;
+import com.android.permissioncontroller.permission.ui.SettingsActivity;
+import com.android.permissioncontroller.permission.ui.handheld.v34.PermissionRationaleViewHandlerImpl;
+import com.android.permissioncontroller.permission.ui.model.v34.PermissionRationaleViewModel;
+import com.android.permissioncontroller.permission.ui.model.v34.PermissionRationaleViewModel.ActivityResultCallback;
+import com.android.permissioncontroller.permission.ui.model.v34.PermissionRationaleViewModel.PermissionRationaleInfo;
+import com.android.permissioncontroller.permission.ui.model.v34.PermissionRationaleViewModelFactory;
+import com.android.permissioncontroller.permission.utils.KotlinUtils;
+import com.android.permissioncontroller.permission.utils.Utils;
+
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
+
+/**
+ * An activity which displays runtime permission rationale on behalf of an app. This activity is
+ * based on GrantPermissionActivity to keep view behavior and theming consistent.
+ */
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+public class PermissionRationaleActivity extends SettingsActivity implements
+ PermissionRationaleViewHandler.ResultListener {
+
+ private static final String LOG_TAG = PermissionRationaleActivity.class.getSimpleName();
+
+ private static final String KEY_SESSION_ID = PermissionRationaleActivity.class.getName()
+ + "_SESSION_ID";
+
+ /**
+ * [Annotation] key for span annotations replacement within the permission rationale purposes
+ * string resource
+ */
+ public static final String ANNOTATION_ID_KEY = "id";
+ /**
+ * [Annotation] id value for span annotations replacement of link annotations within the
+ * permission rationale purposes string resource
+ */
+ public static final String LINK_ANNOTATION_ID = "link";
+ /**
+ * [Annotation] id value for span annotations replacement of install source annotations within
+ * the permission rationale purposes string resource
+ */
+ public static final String INSTALL_SOURCE_ANNOTATION_ID = "install_source";
+ /**
+ * [Annotation] id value for span annotations replacement of purpose list annotations within
+ * the permission rationale purposes string resource
+ */
+ public static final String PURPOSE_LIST_ANNOTATION_ID = "purpose_list";
+ /**
+ * [Annotation] id value for span annotations replacement of permission name annotations within
+ * the permission rationale purposes string resource
+ */
+ public static final String PERMISSION_NAME_ANNOTATION_ID = "permission_name";
+
+ /**
+ * key to the boolean if to show settings_section on the permission rationale dialog provide via
+ * intent extra
+ */
+ public static final String EXTRA_SHOULD_SHOW_SETTINGS_SECTION =
+ "com.android.permissioncontroller.extra.SHOULD_SHOW_SETTINGS_SECTION";
+
+ // Data class defines these values in a different natural order. Swap advertising and fraud
+ // prevention order for display in permission rationale dialog
+ private static final List<Integer> ORDERED_PURPOSES = Arrays.asList(
+ PURPOSE_APP_FUNCTIONALITY,
+ PURPOSE_ANALYTICS,
+ PURPOSE_DEVELOPER_COMMUNICATIONS,
+ PURPOSE_ADVERTISING,
+ PURPOSE_FRAUD_PREVENTION_SECURITY,
+ PURPOSE_PERSONALIZATION,
+ PURPOSE_ACCOUNT_MANAGEMENT
+ );
+
+ /** Comparator used to update purpose order to expected display order */
+ private static final Comparator<Integer> ORDERED_PURPOSE_COMPARATOR =
+ Comparator.comparingInt(purposeInt -> ORDERED_PURPOSES.indexOf(purposeInt));
+
+ /** Unique Id of a request. Inherited from GrantPermissionDialog if provide via intent extra */
+ private long mSessionId;
+ /** Package that shall have permissions granted */
+ private String mTargetPackage;
+ /** The permission group that initiated the permission rationale details activity */
+ private String mPermissionGroupName;
+ /** The permission rationale info resulting from the specified permission and group */
+ private PermissionRationaleInfo mPermissionRationaleInfo;
+
+ private PermissionRationaleViewHandler mViewHandler;
+ private PermissionRationaleViewModel mViewModel;
+
+ private float mOriginalDimAmount;
+ private View mRootView;
+
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ if (!KotlinUtils.INSTANCE.isPermissionRationaleEnabled()) {
+ Log.e(
+ LOG_TAG,
+ "Permission rationale feature disabled");
+ finishAfterTransition();
+ return;
+ }
+
+ if (icicle == null) {
+ mSessionId =
+ getIntent().getLongExtra(Constants.EXTRA_SESSION_ID, new Random().nextLong());
+ } else {
+ mSessionId = icicle.getLong(KEY_SESSION_ID);
+ }
+
+ getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+
+ mPermissionGroupName = getIntent().getStringExtra(EXTRA_PERMISSION_GROUP_NAME);
+ if (mPermissionGroupName == null) {
+ Log.e(
+ LOG_TAG,
+ "null EXTRA_PERMISSION_GROUP_NAME. Must be set for permission rationale");
+ finishAfterTransition();
+ return;
+ }
+
+ mTargetPackage = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+ if (mTargetPackage == null) {
+ Log.e(LOG_TAG, "null EXTRA_PACKAGE_NAME. Must be set for permission rationale");
+ finishAfterTransition();
+ return;
+ }
+
+ setFinishOnTouchOutside(false);
+
+ setTitle(getTitleResIdForPermissionGroup(mPermissionGroupName));
+
+ if (DeviceUtils.isTelevision(this)
+ || DeviceUtils.isWear(this)
+ || DeviceUtils.isAuto(this)) {
+ finishAfterTransition();
+ } else {
+ boolean shouldShowSettingsSection =
+ getIntent().getBooleanExtra(EXTRA_SHOULD_SHOW_SETTINGS_SECTION, true);
+ mViewHandler = new PermissionRationaleViewHandlerImpl(this, this,
+ shouldShowSettingsSection);
+ }
+
+ PermissionRationaleViewModelFactory factory = new PermissionRationaleViewModelFactory(
+ getApplication(), mTargetPackage, mPermissionGroupName, mSessionId, icicle);
+ mViewModel = factory.create(PermissionRationaleViewModel.class);
+ mViewModel.getPermissionRationaleInfoLiveData()
+ .observe(this, this::onPermissionRationaleInfoLoad);
+
+ mRootView = mViewHandler.createView();
+ mRootView.setVisibility(View.GONE);
+ setContentView(mRootView);
+ Window window = getWindow();
+ WindowManager.LayoutParams layoutParams = window.getAttributes();
+ mOriginalDimAmount = layoutParams.dimAmount;
+ window.setAttributes(layoutParams);
+
+ if (getResources().getBoolean(R.bool.config_useWindowBlur)) {
+ java.util.function.Consumer<Boolean> blurEnabledListener = enabled -> {
+ mViewHandler.onBlurEnabledChanged(window, enabled);
+ };
+ mRootView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ window.getWindowManager().addCrossWindowBlurEnabledListener(
+ blurEnabledListener);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ window.getWindowManager().removeCrossWindowBlurEnabledListener(
+ blurEnabledListener);
+ }
+ });
+ }
+ // Restore UI state after lifecycle events. This has to be before we show the first request,
+ // as the UI behaves differently for updates and initial creations.
+ if (icicle != null) {
+ mViewHandler.loadInstanceState(icicle);
+ }
+ }
+
+ @Override
+ protected void onSaveInstanceState(@NonNull Bundle outState) {
+ super.onSaveInstanceState(outState);
+
+ if (mViewHandler == null) {
+ return;
+ }
+
+ mViewHandler.saveInstanceState(outState);
+
+ outState.putLong(KEY_SESSION_ID, mSessionId);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ ActivityResultCallback callback = mViewModel.getActivityResultCallback();
+ if (callback == null || (requestCode != APP_PERMISSION_REQUEST_CODE)) {
+ return;
+ }
+ boolean shouldFinishActivity = callback.shouldFinishActivityForResult(data);
+ mViewModel.setActivityResultCallback(null);
+
+ if (shouldFinishActivity) {
+ setResultAndFinish(data);
+ }
+ }
+
+ private void setResultAndFinish(Intent result) {
+ setResult(RESULT_OK, result);
+ finishAfterTransition();
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (mViewHandler == null) {
+ return;
+ }
+ mViewHandler.onBackPressed();
+ }
+
+ // LINT.IfChange(dispatchTouchEvent)
+ /**
+ * Used to dismiss dialog when tapping outside of dialog bounds
+ * Follows the same logic as GrantPermissionActivity
+ */
+ @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()))) {
+ //TODO b/278783474: We should make this activity a fragment of the base GrantPermissions
+ // activity
+ GrantPermissionsActivity grantActivity = null;
+ synchronized (GrantPermissionsActivity.sCurrentGrantRequests) {
+ grantActivity = GrantPermissionsActivity.sCurrentGrantRequests
+ .get(new Pair<>(mTargetPackage, getTaskId()));
+ }
+ if (grantActivity != null
+ && getIntent().getBooleanExtra(EXTRA_SHOULD_SHOW_SETTINGS_SECTION, false)) {
+ grantActivity.finishAfterTransition();
+ }
+ if (MotionEvent.ACTION_DOWN == ev.getAction()) {
+ mViewHandler.onCancelled();
+ }
+ finishAfterTransition();
+ }
+ return super.dispatchTouchEvent(ev);
+ }
+ // LINT.ThenChange(GrantPermissionsActivity.java:dispatchTouchEvent)
+
+ @Override
+ public void onPermissionRationaleResult(@Nullable String groupName, int result) {
+ if (result == CANCELLED) {
+ mViewModel.logPermissionRationaleDialogActionReported(
+ PERMISSION_RATIONALE_DIALOG_ACTION_REPORTED__BUTTON_PRESSED__CANCEL);
+ finishAfterTransition();
+ }
+ }
+
+ private void onPermissionRationaleInfoLoad(PermissionRationaleInfo permissionRationaleInfo) {
+ if (!mViewModel.getPermissionRationaleInfoLiveData().isInitialized()) {
+ return;
+ }
+
+ if (permissionRationaleInfo == null) {
+ finishAfterTransition();
+ return;
+ }
+
+ mPermissionRationaleInfo = permissionRationaleInfo;
+ showPermissionRationale();
+ }
+
+ private void showPermissionRationale() {
+ @StringRes int titleResId = getTitleResIdForPermissionGroup(mPermissionGroupName);
+ setTitle(titleResId);
+ CharSequence title = getString(titleResId);
+ CharSequence dataSharingSourceMessage = getDataSharingSourceMessage();
+
+ CharSequence purposeTitle =
+ getString(getPurposeTitleResIdForPermissionGroup(mPermissionGroupName));
+
+ List<Integer> purposeList = new ArrayList<>(mPermissionRationaleInfo.getPurposeSet());
+ Collections.sort(purposeList, ORDERED_PURPOSE_COMPARATOR);
+ List<String> purposeStringList = purposeList.stream()
+ .map(this::getStringForPurpose)
+ .collect(Collectors.toList());
+
+ CharSequence purposeMessage =
+ createPurposeMessageWithBulletSpan(
+ getText(R.string.permission_rationale_purpose_message),
+ purposeStringList);
+
+ CharSequence learnMoreMessage;
+ if (mViewModel.canLinkToHelpCenter(this)) {
+ learnMoreMessage = setLink(
+ getText(R.string.permission_rationale_data_sharing_varies_message),
+ getLearnMoreLink()
+ );
+ } else {
+ learnMoreMessage =
+ getText(R.string.permission_rationale_data_sharing_varies_message_without_link);
+ }
+
+ String groupName = mPermissionRationaleInfo.getGroupName();
+ String permissionGroupLabel =
+ KotlinUtils.INSTANCE.getPermGroupLabel(this, groupName).toString();
+ CharSequence settingsMessage =
+ createSettingsMessageWithSpans(
+ getText(getSettingsMessageResIdForPermissionGroup(groupName)),
+ UCharacter.toLowerCase(permissionGroupLabel),
+ getLinkToSettings()
+ );
+
+ mViewHandler.updateUi(
+ groupName,
+ title,
+ dataSharingSourceMessage,
+ purposeTitle,
+ purposeMessage,
+ learnMoreMessage,
+ settingsMessage
+ );
+
+ getWindow().setDimAmount(mOriginalDimAmount);
+ if (mRootView.getVisibility() == View.GONE) {
+ InputMethodManager manager = getSystemService(InputMethodManager.class);
+ manager.hideSoftInputFromWindow(mRootView.getWindowToken(), 0);
+ mRootView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private CharSequence getDataSharingSourceMessage() {
+ if (mPermissionRationaleInfo.isPreloadedApp()) {
+ return getText(R.string.permission_rationale_data_sharing_device_manufacturer_message);
+ }
+
+ String installSourcePackageName = mPermissionRationaleInfo.getInstallSourcePackageName();
+ CharSequence installSourceLabel = mPermissionRationaleInfo.getInstallSourceLabel();
+ checkStringNotEmpty(installSourcePackageName,
+ "installSourcePackageName cannot be null or empty");
+ checkStringNotEmpty(installSourceLabel, "installSourceLabel cannot be null or empty");
+ return createDataSharingSourceMessageWithSpans(
+ getText(R.string.permission_rationale_data_sharing_source_message),
+ installSourceLabel,
+ getLinkToAppStore(installSourcePackageName));
+ }
+
+ @StringRes
+ private int getTitleResIdForPermissionGroup(String permissionGroupName) {
+ if (LOCATION.equals(permissionGroupName)) {
+ return R.string.permission_rationale_location_title;
+ }
+
+ String exceptionString =
+ String.format("Permission Rationale does not support %s", permissionGroupName);
+ throw new IllegalArgumentException(exceptionString);
+ }
+
+ @StringRes
+ private int getPurposeTitleResIdForPermissionGroup(String permissionGroupName) {
+ if (LOCATION.equals(permissionGroupName)) {
+ return R.string.permission_rationale_location_purpose_title;
+ }
+
+ String exceptionString =
+ String.format("Permission Rationale does not support %s", permissionGroupName);
+ throw new IllegalArgumentException(exceptionString);
+ }
+
+ /**
+ * Returns permission settings message string resource id for the given permission group.
+ *
+ * <p> Supported permission groups: LOCATION
+ *
+ * @param permissionGroupName permission group for which to get a message string id
+ * @throws IllegalArgumentException if passing unsupported permission group
+ */
+ @StringRes
+ private int getSettingsMessageResIdForPermissionGroup(String permissionGroupName) {
+ Preconditions.checkArgument(LOCATION.equals(permissionGroupName),
+ "Permission Rationale does not support %s", permissionGroupName);
+
+ return R.string.permission_rationale_permission_settings_message;
+ }
+
+ private String getStringForPurpose(@Purpose int purpose) {
+ switch (purpose) {
+ case PURPOSE_APP_FUNCTIONALITY:
+ return getString(R.string.permission_rationale_purpose_app_functionality);
+ case PURPOSE_ANALYTICS:
+ return getString(R.string.permission_rationale_purpose_analytics);
+ case PURPOSE_DEVELOPER_COMMUNICATIONS:
+ return getString(R.string.permission_rationale_purpose_developer_communications);
+ case PURPOSE_FRAUD_PREVENTION_SECURITY:
+ return getString(R.string.permission_rationale_purpose_fraud_prevention_security);
+ case PURPOSE_ADVERTISING:
+ return getString(R.string.permission_rationale_purpose_advertising);
+ case PURPOSE_PERSONALIZATION:
+ return getString(R.string.permission_rationale_purpose_personalization);
+ case PURPOSE_ACCOUNT_MANAGEMENT:
+ return getString(R.string.permission_rationale_purpose_account_management);
+ default:
+ throw new IllegalArgumentException("Invalid purpose: " + purpose);
+ }
+ }
+
+ private CharSequence createDataSharingSourceMessageWithSpans(
+ CharSequence baseText,
+ CharSequence installSourceLabel,
+ ClickableSpan link) {
+ CharSequence updatedText =
+ replaceSpan(baseText, INSTALL_SOURCE_ANNOTATION_ID, installSourceLabel);
+ updatedText = setLink(updatedText, link);
+ return updatedText;
+ }
+
+ private CharSequence createPurposeMessageWithBulletSpan(
+ CharSequence baseText,
+ List<String> purposesList) {
+ Resources res = getResources();
+ final int bulletSize =
+ res.getDimensionPixelSize(R.dimen.permission_rationale_purpose_list_bullet_radius);
+ final int bulletIndent =
+ res.getDimensionPixelSize(R.dimen.permission_rationale_purpose_list_bullet_indent);
+
+ final int bulletColor =
+ getColor(Utils.getColorResId(this, android.R.attr.textColorSecondary));
+
+ String purposesString = TextUtils.join("\n", purposesList);
+ SpannableStringBuilder purposesSpan = SpannableStringBuilder.valueOf(purposesString);
+ int spanStart = 0;
+ for (int i = 0; i < purposesList.size(); i++) {
+ final int length = purposesList.get(i).length();
+ purposesSpan.setSpan(new BulletSpan(bulletIndent, bulletColor, bulletSize),
+ spanStart, spanStart + length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ spanStart += length + 1;
+ }
+ CharSequence updatedText = replaceSpan(baseText, PURPOSE_LIST_ANNOTATION_ID, purposesSpan);
+ return updatedText;
+ }
+
+ private CharSequence createSettingsMessageWithSpans(
+ CharSequence baseText,
+ CharSequence permissionName,
+ ClickableSpan link) {
+ CharSequence updatedText =
+ replaceSpan(baseText, PERMISSION_NAME_ANNOTATION_ID, permissionName);
+ updatedText = setLink(updatedText, link);
+ return updatedText;
+ }
+
+ private CharSequence replaceSpan(
+ CharSequence baseText,
+ String annotationId,
+ CharSequence replacementText) {
+ SpannableStringBuilder text = SpannableStringBuilder.valueOf(baseText);
+ Annotation[] annotations = text.getSpans(0, text.length(), Annotation.class);
+
+ for (android.text.Annotation annotation : annotations) {
+ if (!annotation.getKey().equals(ANNOTATION_ID_KEY)
+ || !annotation.getValue().equals(annotationId)) {
+ continue;
+ }
+
+ int spanStart = text.getSpanStart(annotation);
+ int spanEnd = text.getSpanEnd(annotation);
+ text.removeSpan(annotation);
+ text.replace(spanStart, spanEnd, replacementText);
+ break;
+ }
+
+ return text;
+ }
+
+ private CharSequence setLink(CharSequence baseText, ClickableSpan link) {
+ SpannableStringBuilder text = SpannableStringBuilder.valueOf(baseText);
+ Annotation[] annotations = text.getSpans(0, text.length(), Annotation.class);
+
+ for (android.text.Annotation annotation : annotations) {
+ if (!annotation.getKey().equals(ANNOTATION_ID_KEY)
+ || !annotation.getValue().equals(LINK_ANNOTATION_ID)) {
+ continue;
+ }
+
+ int spanStart = text.getSpanStart(annotation);
+ int spanEnd = text.getSpanEnd(annotation);
+ text.removeSpan(annotation);
+ text.setSpan(link, spanStart, spanEnd, 0);
+ break;
+ }
+
+ return text;
+ }
+
+ private ClickableSpan getLinkToAppStore(String installSourcePackageName) {
+ boolean canLinkToAppStore = mViewModel
+ .canLinkToAppStore(PermissionRationaleActivity.this, installSourcePackageName);
+ if (!canLinkToAppStore) {
+ return null;
+ }
+ return new ClickableSpan() {
+ @Override
+ public void onClick(@NonNull View widget) {
+ // TODO(b/259961958): metrics for click events
+ mViewModel.sendToAppStore(PermissionRationaleActivity.this,
+ installSourcePackageName);
+ }
+ };
+ }
+
+ private ClickableSpan getLinkToSettings() {
+ return new ClickableSpan() {
+ @Override
+ public void onClick(@NonNull View widget) {
+ // TODO(b/259961958): metrics for click events
+ mViewModel.sendToSettingsForPermissionGroup(PermissionRationaleActivity.this,
+ mPermissionGroupName);
+ }
+ };
+ }
+
+ private ClickableSpan getLearnMoreLink() {
+ return new ClickableSpan() {
+ @Override
+ public void onClick(@NonNull View widget) {
+ // TODO(b/259961958): metrics for click events
+ mViewModel.sendToLearnMore(PermissionRationaleActivity.this);
+ }
+ };
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/v34/PermissionRationaleViewHandler.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/v34/PermissionRationaleViewHandler.kt
new file mode 100644
index 000000000..0b7537136
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/v34/PermissionRationaleViewHandler.kt
@@ -0,0 +1,104 @@
+/*
+ * 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.permissioncontroller.permission.ui.v34
+
+import android.os.Build
+import android.os.Bundle
+import android.view.View
+import android.view.Window
+import androidx.annotation.IntDef
+import androidx.annotation.RequiresApi
+
+/**
+ * Class for managing the presentation and user interaction of the "permission rationale" user
+ * interface.
+ */
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+interface PermissionRationaleViewHandler {
+ @Retention(AnnotationRetention.SOURCE)
+ @IntDef(Result.CANCELLED)
+ annotation class Result {
+ companion object {
+ const val CANCELLED = -1
+ }
+ }
+
+ /**
+ * Listener interface for getting notified when the user responds to a permission rationale
+ * user action.
+ */
+ interface ResultListener {
+ fun onPermissionRationaleResult(groupName: String?, @Result result: Int)
+ }
+
+ /**
+ * Creates and returns the view hierarchy that is managed by this view handler. This must be
+ * called before [.updateUi].
+ */
+ fun createView(): View
+
+ /**
+ * Updates the view hierarchy to reflect the specified state.
+ *
+ * Note that this must be called at least once before showing the UI to the user to properly
+ * initialize the UI.
+ *
+ * @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
+ * @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
+ * @param settingsMessage the settings link message to display the user
+ */
+ fun updateUi(
+ groupName: String,
+ title: CharSequence,
+ dataSharingSourceMessage: CharSequence,
+ purposeTitle: CharSequence,
+ purposeMessage: CharSequence,
+ learnMoreMessage: CharSequence,
+ settingsMessage: CharSequence
+ )
+
+ /**
+ * Called by [PermissionRationaleActivity] to save the state of this view handler to the
+ * specified bundle.
+ */
+ fun saveInstanceState(outState: Bundle)
+
+ /**
+ * Called by [PermissionRationaleActivity] to load the state of this view handler from the
+ * specified bundle.
+ */
+ fun loadInstanceState(savedInstanceState: Bundle)
+
+ /** Gives a chance for handling the back key. */
+ fun onBackPressed()
+
+ /**
+ * Handles cancel event for the permission rationale dialog.
+ */
+ fun onCancelled() {}
+
+ /**
+ * Called by [PermissionRationaleActivity] to allow the handler to update the ui when blur is
+ * enabled/disabled.
+ */
+ fun onBlurEnabledChanged(window: Window?, enabled: Boolean) {}
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/v34/package-info.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/v34/package-info.java
new file mode 100644
index 000000000..0e68b52e0
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/v34/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+@androidx.annotation.RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+package com.android.permissioncontroller.permission.ui.v34;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/AppPermissionsFragmentWear.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/AppPermissionsFragmentWear.java
index ba5cc58a0..843514b4a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/AppPermissionsFragmentWear.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/AppPermissionsFragmentWear.java
@@ -42,8 +42,8 @@ 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.SafetyNetLogger;
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;
@@ -381,7 +381,7 @@ public final class AppPermissionsFragmentWear extends PreferenceFragmentCompat {
private void logAndClearToggledGroups() {
if (mToggledGroups != null) {
- SafetyNetLogger.logPermissionsToggled(mToggledGroups);
+ LegacySafetyNetLogger.logPermissionsToggled(mToggledGroups);
mToggledGroups = null;
}
}
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 1c0af63cc..ccd1ed42e 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/GrantPermissionsWearViewHandler.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/GrantPermissionsWearViewHandler.java
@@ -96,8 +96,11 @@ public final class GrantPermissionsWearViewHandler implements GrantPermissionsVi
@Override
public void updateUi(String groupName, int groupCount, int groupIndex, Icon icon,
- CharSequence message, CharSequence detailMessage, boolean[] buttonVisibilities,
+ CharSequence message, CharSequence detailMessage,
+ CharSequence permissionRationaleMessage, boolean[] buttonVisibilities,
boolean[] locationVisibilities) {
+ // permissionRationaleMessage ignored by wear
+
// TODO: Handle detailMessage
boolean showDoNotAsk = buttonVisibilities[DENY_AND_DONT_ASK_AGAIN_BUTTON];
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/CollectionUtils.java b/PermissionController/src/com/android/permissioncontroller/permission/utils/CollectionUtils.java
index 6f2a3079d..108120ced 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/CollectionUtils.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/CollectionUtils.java
@@ -16,8 +16,6 @@
package com.android.permissioncontroller.permission.utils;
-import android.util.ArraySet;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -59,29 +57,6 @@ public final class CollectionUtils {
}
/**
- * Remove all values in the array set that do <b>not</b> exist in the given collection.
- *
- * @param <T> the class of the elements to retain and of the {@code ArraySet}
- * @param arraySet the {@code ArraySet} whose elements are to be removed or retained
- * @param valuesToRetain the values to be used to determine which elements to retain
- *
- * @return {@code true} if any values were removed from the array set, {@code false} otherwise.
- *
- * @see ArraySet#retainAll(java.util.Collection)
- */
- @SafeVarargs
- public static <T> boolean retainAll(ArraySet<T> arraySet, T... valuesToRetain) {
- boolean removed = false;
- for (int i = arraySet.size() - 1; i >= 0; i--) {
- if (!ArrayUtils.contains(valuesToRetain, arraySet.valueAt(i))) {
- arraySet.removeAt(i);
- removed = true;
- }
- }
- return removed;
- }
-
- /**
* Return a singleton list containing the element, or an empty list if the element is
* {@code null}.
*
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt
index 43b219a83..7db6e8669 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt
@@ -22,6 +22,8 @@ import android.Manifest.permission.ACCESS_BACKGROUND_LOCATION
import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.Manifest.permission.BACKUP
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.app.ActivityManager
import android.app.AppOpsManager
@@ -47,16 +49,22 @@ import android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE
import android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE
import android.content.pm.PermissionGroupInfo
import android.content.pm.PermissionInfo
+import android.content.pm.ResolveInfo
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.Drawable
+import android.graphics.drawable.Icon
+import android.health.connect.HealthConnectManager
import android.os.Build
import android.os.Bundle
import android.os.UserHandle
import android.permission.PermissionManager
import android.provider.DeviceConfig
import android.provider.Settings
+import android.safetylabel.SafetyLabelConstants.PERMISSION_RATIONALE_ENABLED
+import android.safetylabel.SafetyLabelConstants.SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED
+import android.text.Html
import android.text.TextUtils
import android.util.Log
import androidx.annotation.ChecksSdkIntAtLeast
@@ -66,7 +74,10 @@ import androidx.navigation.NavController
import androidx.preference.Preference
import androidx.preference.PreferenceGroup
import com.android.modules.utils.build.SdkLevel
+import com.android.permissioncontroller.DeviceUtils
+import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.data.LightAppPermGroupLiveData
import com.android.permissioncontroller.permission.data.LightPackageInfoLiveData
import com.android.permissioncontroller.permission.data.get
import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
@@ -75,16 +86,18 @@ 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 kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.async
-import kotlinx.coroutines.launch
+import com.android.safetycenter.resources.SafetyCenterResourcesContext
+import java.time.Duration
import java.util.concurrent.atomic.AtomicReference
import kotlin.coroutines.Continuation
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.async
+import kotlinx.coroutines.launch
/**
* A set of util functions designed to work with kotlin, though they can work with java, as well.
@@ -118,6 +131,203 @@ 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. */
+ 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 location accuracy feature is enabled */
+ private const val PROPERTY_LOCATION_ACCURACY_ENABLED = "location_accuracy_enabled"
+
+ /** 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. */
+ 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.
+ */
+ private const val PROPERTY_SAFETY_LABEL_CHANGES_JOB_DELAY_MILLIS =
+ "safety_label_changes_job_delay_millis"
+
+ /** How often the safety label changes job service will run its job. */
+ private const val PROPERTY_SAFETY_LABEL_CHANGES_JOB_INTERVAL_MILLIS =
+ "safety_label_changes_job_interval_millis"
+
+ /** Whether the safety label changes job should only be run when the device is idle. */
+ private const val PROPERTY_SAFETY_LABEL_CHANGES_JOB_RUN_WHEN_IDLE =
+ "safety_label_changes_job_run_when_idle"
+
+ /** Whether the kill switch is set for [SafetyLabelChangesJobService]. */
+ 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()
+ }
+
+ /**
+ * 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.
+ *
+ * @return whether to show the icons.
+ */
+ @ChecksSdkIntAtLeast(Build.VERSION_CODES.S)
+ fun shouldShowCameraMicIndicators(): Boolean {
+ return isCameraMicIconsFlagEnabled() || isPermissionsHub2FlagEnabled()
+ }
+
+ /**
+ * 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.
+ */
+ @ChecksSdkIntAtLeast(Build.VERSION_CODES.S)
+ fun shouldShowLocationIndicators(): Boolean {
+ return isLocationIndicatorsFlagEnabled() || isPermissionsHub2FlagEnabled()
+ }
+
+ /**
+ * Whether the location accuracy feature is enabled
+ */
+ @ChecksSdkIntAtLeast(Build.VERSION_CODES.S)
+ fun isLocationAccuracyEnabled(): Boolean {
+ return SdkLevel.isAtLeastS() && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_LOCATION_ACCURACY_ENABLED, true)
+ }
+
+ /**
+ * 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)
+ }
+
+ /**
+ * Whether the Photo Picker Prompt is enabled
+ *
+ * @return `true` iff the Location Access Check is enabled.
+ */
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codename = "UpsideDownCake")
+ fun isPhotoPickerPromptEnabled(): 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)
+ }
+
+ /*
+ * Whether we should enable the permission rationale in permission settings and grant dialog
+ *
+ * @return whether the flag is enabled
+ */
+ @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)
+ }
+
+ /**
+ * Whether we should enable the safety label change notifications and data sharing updates UI.
+ */
+ @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) &&
+ !DeviceUtils.isAuto(context) &&
+ !DeviceUtils.isTelevision(context) &&
+ !DeviceUtils.isWear(context)
+ }
+
+ /**
+ * Whether the kill switch is set for [SafetyLabelChangesJobService]. If {@code true}, the
+ * service is effectively disabled and will not run or schedule any jobs.
+ */
+ @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)
+ }
+
+ /** How often the safety label changes job will run. */
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codename = "UpsideDownCake")
+ fun getSafetyLabelChangesJobIntervalMillis(): Long {
+ return DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_SAFETY_LABEL_CHANGES_JOB_INTERVAL_MILLIS,
+ Duration.ofDays(30).toMillis())
+ }
+
+ /** Whether the safety label changes job should only be run when the device is idle. */
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codename = "UpsideDownCake")
+ fun runSafetyLabelChangesJobOnlyWhenDeviceIdle(): Boolean {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_SAFETY_LABEL_CHANGES_JOB_RUN_WHEN_IDLE,
+ 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
@@ -279,7 +489,7 @@ object KotlinUtils {
}
if (icon == null) {
- val groupName = Utils.getGroupOfPermission(permInfo) ?: permInfo.name
+ val groupName = PermissionMapping.getGroupOfPermission(permInfo) ?: permInfo.name
icon = getPermGroupIcon(context, groupName)
}
@@ -385,6 +595,20 @@ object KotlinUtils {
}
/**
+ * 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/*"
+ }
+ if (permissions.contains(READ_MEDIA_VIDEO) && !permissions.contains(READ_MEDIA_IMAGES)) {
+ return "video/*"
+ }
+
+ return null
+ }
+
+ /**
* Determines if an app is R or above, or if it is Q-, and has auto revoke enabled
*
* @param app The currenct application
@@ -494,9 +718,12 @@ object KotlinUtils {
app: Application,
group: LightAppPermGroup,
filterPermissions: List<String> = group.permissions.keys.toList(),
- isOneTime: Boolean = false
+ isOneTime: Boolean = false,
+ userFixed: Boolean = false,
+ withoutAppOps: Boolean = false,
): LightAppPermGroup {
- return grantRuntimePermissions(app, group, false, isOneTime, filterPermissions)
+ return grantRuntimePermissions(app, group, false, isOneTime, userFixed,
+ withoutAppOps, filterPermissions)
}
/**
@@ -518,7 +745,8 @@ object KotlinUtils {
group: LightAppPermGroup,
filterPermissions: List<String> = group.permissions.keys.toList()
): LightAppPermGroup {
- return grantRuntimePermissions(app, group, true, false, filterPermissions)
+ return grantRuntimePermissions(app, group, true, false, false, false,
+ filterPermissions)
}
private fun grantRuntimePermissions(
@@ -526,7 +754,9 @@ object KotlinUtils {
group: LightAppPermGroup,
grantBackground: Boolean,
isOneTime: Boolean = false,
- filterPermissions: List<String> = group.permissions.keys.toList()
+ userFixed: Boolean = false,
+ withoutAppOps: Boolean = false,
+ filterPermissions: List<String> = group.permissions.keys.toList(),
): LightAppPermGroup {
val newPerms = group.permissions.toMutableMap()
var shouldKillForAnyPermission = false
@@ -534,7 +764,8 @@ object KotlinUtils {
val perm = group.permissions[permName] ?: continue
val isBackgroundPerm = permName in group.backgroundPermNames
if (isBackgroundPerm == grantBackground) {
- val (newPerm, shouldKill) = grantRuntimePermission(app, perm, isOneTime, group)
+ val (newPerm, shouldKill) = grantRuntimePermission(app, perm, group, isOneTime,
+ userFixed, withoutAppOps)
newPerms[newPerm.name] = newPerm
shouldKillForAnyPermission = shouldKillForAnyPermission || shouldKill
}
@@ -543,7 +774,7 @@ object KotlinUtils {
val user = UserHandle.getUserHandleForUid(group.packageInfo.uid)
for (groupPerm in group.allPermissions.values) {
var permFlags = groupPerm.flags
- permFlags = permFlags.clearFlag(PackageManager.FLAG_PERMISSION_AUTO_REVOKED)
+ permFlags = permFlags.clearFlag(FLAG_PERMISSION_AUTO_REVOKED)
if (groupPerm.flags != permFlags) {
app.packageManager.updatePermissionFlags(groupPerm.name,
group.packageInfo.packageName, PERMISSION_CONTROLLER_CHANGED_FLAG_MASK,
@@ -581,8 +812,12 @@ object KotlinUtils {
*
* @param app The current application
* @param perm The permission which should be granted.
- * @param group An optional app permission group in which to look for background or foreground
+ * @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 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.
*
* @return a LightPermission and boolean pair <permission with updated state (or the original
* state, if it wasn't changed), should kill app>
@@ -590,8 +825,10 @@ object KotlinUtils {
private fun grantRuntimePermission(
app: Application,
perm: LightPermission,
+ group: LightAppPermGroup,
isOneTime: Boolean,
- group: LightAppPermGroup
+ userFixed: Boolean = false,
+ withoutAppOps: Boolean = false
): Pair<LightPermission, Boolean> {
val pkgInfo = group.packageInfo
val user = UserHandle.getUserHandleForUid(pkgInfo.uid)
@@ -604,6 +841,7 @@ object KotlinUtils {
}
var newFlags = perm.flags
+ var oldFlags = perm.flags
var isGranted = perm.isGrantedIncludingAppOp
var shouldKill = false
@@ -613,6 +851,14 @@ object KotlinUtils {
// TODO 195016052: investigate adding split permission handling
if (supportsRuntime) {
+ // If granting without app ops, explicitly disallow app op first, while setting the
+ // 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)
+ disallowAppOp(app, perm, group)
+ }
app.packageManager.grantRuntimePermission(group.packageName, perm.name, user)
isGranted = true
} else if (affectsAppOp) {
@@ -623,31 +869,39 @@ object KotlinUtils {
shouldKill = true
isGranted = true
}
- newFlags = 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) {
+ if (affectsAppOp && !withoutAppOps) {
allowAppOp(app, perm, group)
}
}
// Granting a permission explicitly means the user already
// reviewed it so clear the review flag on every grant.
- newFlags = newFlags.clearFlag(PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED)
+ newFlags = newFlags.clearFlag(FLAG_PERMISSION_REVIEW_REQUIRED)
// Update the permission flags
- // Now the apps can ask for the permission as the user
- // no longer has it fixed in a denied state.
- newFlags = newFlags.clearFlag(PackageManager.FLAG_PERMISSION_USER_FIXED)
- newFlags = newFlags.setFlag(PackageManager.FLAG_PERMISSION_USER_SET)
- newFlags = newFlags.clearFlag(PackageManager.FLAG_PERMISSION_AUTO_REVOKED)
+ if (!withoutAppOps && !userFixed) {
+ // Now the apps can ask for the permission as the user
+ // no longer has it fixed in a denied state.
+ newFlags = newFlags.clearFlag(FLAG_PERMISSION_USER_FIXED)
+ newFlags = newFlags.setFlag(FLAG_PERMISSION_USER_SET)
+ } else if (userFixed) {
+ newFlags = newFlags.setFlag(FLAG_PERMISSION_USER_FIXED)
+ }
+ newFlags = newFlags.clearFlag(FLAG_PERMISSION_AUTO_REVOKED)
newFlags = if (isOneTime) {
- newFlags.setFlag(PackageManager.FLAG_PERMISSION_ONE_TIME)
+ newFlags.setFlag(FLAG_PERMISSION_ONE_TIME)
} else {
- newFlags.clearFlag(PackageManager.FLAG_PERMISSION_ONE_TIME)
+ newFlags.clearFlag(FLAG_PERMISSION_ONE_TIME)
}
// If we newly grant background access to the fine location, double-guess the user some
@@ -667,7 +921,7 @@ object KotlinUtils {
}
}
- if (perm.flags != newFlags) {
+ if (oldFlags != newFlags) {
app.packageManager.updatePermissionFlags(perm.name, group.packageInfo.packageName,
PERMISSION_CONTROLLER_CHANGED_FLAG_MASK, newFlags, user)
}
@@ -698,9 +952,11 @@ object KotlinUtils {
group: LightAppPermGroup,
userFixed: Boolean = false,
oneTime: Boolean = false,
+ forceRemoveRevokedCompat: Boolean = false,
filterPermissions: List<String> = group.permissions.keys.toList()
): LightAppPermGroup {
- return revokeRuntimePermissions(app, group, false, userFixed, oneTime, filterPermissions)
+ return revokeRuntimePermissions(app, group, false, userFixed, oneTime,
+ forceRemoveRevokedCompat, filterPermissions)
}
/**
@@ -723,9 +979,11 @@ object KotlinUtils {
group: LightAppPermGroup,
userFixed: Boolean = false,
oneTime: Boolean = false,
+ forceRemoveRevokedCompat: Boolean = false,
filterPermissions: List<String> = group.permissions.keys.toList()
): LightAppPermGroup {
- return revokeRuntimePermissions(app, group, true, userFixed, oneTime, filterPermissions)
+ return revokeRuntimePermissions(app, group, true, userFixed, oneTime,
+ forceRemoveRevokedCompat, filterPermissions)
}
private fun revokeRuntimePermissions(
@@ -734,6 +992,7 @@ object KotlinUtils {
revokeBackground: Boolean,
userFixed: Boolean,
oneTime: Boolean,
+ forceRemoveRevokedCompat: Boolean = false,
filterPermissions: List<String>
): LightAppPermGroup {
val wasOneTime = group.isOneTime
@@ -744,7 +1003,8 @@ object KotlinUtils {
val isBackgroundPerm = permName in group.backgroundPermNames
if (isBackgroundPerm == revokeBackground) {
val (newPerm, shouldKill) =
- revokeRuntimePermission(app, perm, userFixed, oneTime, group)
+ revokeRuntimePermission(app, perm, userFixed, oneTime, forceRemoveRevokedCompat,
+ group)
newPerms[newPerm.name] = newPerm
shouldKillForAnyPermission = shouldKillForAnyPermission || shouldKill
}
@@ -766,6 +1026,34 @@ object KotlinUtils {
}
/**
+ * Revoke background permissions
+ *
+ * @param context context
+ * @param packageName Name of the package
+ * @param permissionGroupName Name of the permission group
+ * @param user User handle
+ * @param postRevokeHandler Optional callback that lets us perform an action on revoke
+ */
+ fun revokeBackgroundRuntimePermissions(
+ context: Context,
+ packageName: String,
+ permissionGroupName: String,
+ user: UserHandle,
+ postRevokeHandler: Runnable?
+ ) {
+ GlobalScope.launch(Dispatchers.Main) {
+ val group = LightAppPermGroupLiveData[packageName, permissionGroupName, user]
+ .getInitializedValue()
+ if (group != null) {
+ revokeBackgroundRuntimePermissions(context.application, group)
+ }
+ if (postRevokeHandler != null) {
+ postRevokeHandler.run()
+ }
+ }
+ }
+
+ /**
* Determines if any permissions of a package are granted for one-time only
*
* @param app The current application
@@ -815,6 +1103,7 @@ object KotlinUtils {
perm: LightPermission,
userFixed: Boolean,
oneTime: Boolean,
+ forceRemoveRevokedCompat: Boolean,
group: LightAppPermGroup
): Pair<LightPermission, Boolean> {
// Do not touch permissions fixed by the system.
@@ -830,13 +1119,16 @@ object KotlinUtils {
val affectsAppOp = permissionToOp(perm.name) != null || perm.isBackgroundPermission
- if (perm.isGrantedIncludingAppOp) {
+ if (perm.isGrantedIncludingAppOp || (perm.isCompatRevoked && forceRemoveRevokedCompat)) {
if (supportsRuntime && !isPermissionSplitFromNonRuntime(app, perm.name,
group.packageInfo.targetSdkVersion)) {
// Revoke the permission if needed.
app.packageManager.revokeRuntimePermission(group.packageInfo.packageName,
perm.name, user)
isGranted = false
+ if (forceRemoveRevokedCompat) {
+ newFlags = newFlags.clearFlag(PackageManager.FLAG_PERMISSION_REVOKED_COMPAT)
+ }
} else if (affectsAppOp) {
// If the permission has no corresponding app op, then it is a
// third-party one and we do not offer toggling of such permissions.
@@ -871,6 +1163,27 @@ object KotlinUtils {
PERMISSION_CONTROLLER_CHANGED_FLAG_MASK, newFlags, user)
}
+ // If we revoke background access to the fine location, we trigger a check to remove
+ // notification warning about background location access
+ if (perm.isGrantedIncludingAppOp && !isGranted) {
+ var cancelLocationAccessWarning = false
+ if (perm.name == ACCESS_FINE_LOCATION) {
+ val bgPerm = group.permissions[perm.backgroundPermission]
+ cancelLocationAccessWarning = bgPerm?.isGrantedIncludingAppOp == true
+ } else if (perm.name == ACCESS_BACKGROUND_LOCATION) {
+ val fgPerm = group.permissions[ACCESS_FINE_LOCATION]
+ cancelLocationAccessWarning = fgPerm?.isGrantedIncludingAppOp == true
+ }
+ if (cancelLocationAccessWarning) {
+ // cancel location access warning notification
+ 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
@@ -926,8 +1239,8 @@ object KotlinUtils {
val appOpName = permissionToOp(foregroundPermName) ?: continue
if (fgPerm != null && fgPerm.isGrantedIncludingAppOp) {
- wasChanged = wasChanged || setOpMode(appOpName, uid, packageName, MODE_ALLOWED,
- appOpsManager)
+ wasChanged = setOpMode(appOpName, uid, packageName, MODE_ALLOWED,
+ appOpsManager) || wasChanged
}
}
} else {
@@ -1137,14 +1450,91 @@ object KotlinUtils {
*/
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
fun shouldShowSafetyProtectionResources(context: Context): Boolean {
- return SdkLevel.isAtLeastT() &&
- DeviceConfig.getBoolean(
- 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()
+ return try {
+ SdkLevel.isAtLeastT() &&
+ DeviceConfig.getBoolean(
+ 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) {
+ // We should expect the resources to not exist for non-pixel devices
+ // (except for the OEMs that opt-in)
+ false
+ }
+ }
+
+ fun addHealthPermissions(context: Context) {
+ val permissions = HealthConnectManager.getHealthPermissions(context)
+ PermissionMapping.addHealthPermissionsToPlatform(permissions)
+ }
+
+ /**
+ * Returns an [Intent] to the installer app store for a given package name, or {@code null} if
+ * none found
+ */
+ fun getAppStoreIntent(
+ context: Context,
+ installerPackageName: String?,
+ packageName: String?
+ ): Intent? {
+ 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)
+ return result
+ }
+ return null
+ }
+
+ /**
+ * Verify that a component that supports the intent with action and return a new intent with
+ * same action and resolved class name set. Returns null if no activity resolution.
+ */
+ private fun resolveActivityForIntent(context: Context, intent: Intent): Intent? {
+ val result: ResolveInfo? = context.packageManager.resolveActivity(intent, 0)
+ return if (result != null) {
+ Intent(intent.action)
+ .setClassName(result.activityInfo.packageName, result.activityInfo.name)
+ } else {
+ null
+ }
+ }
+
+ data class NotificationResources(val appLabel: String, val smallIcon: Icon, val color: Int)
+
+ fun getSafetyCenterNotificationResources(context: Context): NotificationResources {
+ val appLabel: String
+ val smallIcon: Icon
+ 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")
+ if (uIcon != null && uColor != null) {
+ appLabel = context.getString(R.string.safety_privacy_qs_tile_title)
+ return NotificationResources(appLabel, uIcon, uColor)
+ }
+ }
+
+ // 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)
+ 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)
+ color = context.getColor(android.R.color.system_notification_accent_color)
+ }
+ return NotificationResources(appLabel, smallIcon, color)
}
}
@@ -1153,15 +1543,16 @@ object KotlinUtils {
*/
suspend fun <T, LD : LiveData<T>> LD.getInitializedValue(
observe: LD.(Observer<T>) -> Unit = { observeForever(it) },
- isInitialized: LD.() -> Boolean = { value != null }
+ isValueInitialized: LD.() -> Boolean = { value != null }
): T {
- return if (isInitialized()) {
- value!!
+ return if (isValueInitialized()) {
+ @Suppress("UNCHECKED_CAST")
+ value as T
} else {
suspendCoroutine { continuation: Continuation<T> ->
val observer = AtomicReference<Observer<T>>()
observer.set(Observer { newValue ->
- if (isInitialized()) {
+ if (isValueInitialized()) {
GlobalScope.launch(Dispatchers.Main) {
observer.getAndSet(null)?.let { observerSnapshot ->
removeObserver(observerSnapshot)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt
new file mode 100644
index 000000000..b06a09b28
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt
@@ -0,0 +1,409 @@
+/*
+ * 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.
+ */
+@file:Suppress("DEPRECATION")
+
+package com.android.permissioncontroller.permission.utils
+
+import android.Manifest
+import android.app.AppOpsManager
+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
+
+/**
+ * This file contains the canonical mapping of permission to permission group, used in the
+ * Permission settings screens and grant dialog. It also includes methods related to that mapping.
+ */
+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))
+
+ @JvmField
+ val SENSOR_DATA_PERMISSIONS: List<String> =
+ listOf(
+ Manifest.permission_group.LOCATION,
+ Manifest.permission_group.CAMERA,
+ Manifest.permission_group.MICROPHONE)
+
+ @JvmField
+ val STORAGE_SUPERGROUP_PERMISSIONS: List<String> =
+ if (!SdkLevel.isAtLeastT()) listOf()
+ else
+ listOf(
+ Manifest.permission_group.STORAGE,
+ Manifest.permission_group.READ_MEDIA_AURAL,
+ Manifest.permission_group.READ_MEDIA_VISUAL)
+
+ val PARTIAL_MEDIA_PERMISSIONS: MutableSet<String> = mutableSetOf()
+
+ /** Mapping permission -> group for all dangerous platform permissions */
+ private val PLATFORM_PERMISSIONS: MutableMap<String, String> = mutableMapOf()
+
+ /** Mapping group -> permissions for all dangerous platform permissions */
+ private val PLATFORM_PERMISSION_GROUPS: MutableMap<String, MutableList<String>> = mutableMapOf()
+
+ /** Set of groups that will be able to receive one-time grant */
+ private val ONE_TIME_PERMISSION_GROUPS: MutableSet<String> = mutableSetOf()
+
+ 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] =
+ Manifest.permission_group.CONTACTS
+ PLATFORM_PERMISSIONS[Manifest.permission.GET_ACCOUNTS] = Manifest.permission_group.CONTACTS
+
+ PLATFORM_PERMISSIONS[Manifest.permission.READ_CALENDAR] = Manifest.permission_group.CALENDAR
+ PLATFORM_PERMISSIONS[Manifest.permission.WRITE_CALENDAR] =
+ Manifest.permission_group.CALENDAR
+
+ // Any updates to the permissions for the SMS permission group must also be made in
+ // Permissions {@link com.android.role.controller.model.Permissions} in the role
+ // library
+ PLATFORM_PERMISSIONS[Manifest.permission.SEND_SMS] = Manifest.permission_group.SMS
+ PLATFORM_PERMISSIONS[Manifest.permission.RECEIVE_SMS] = Manifest.permission_group.SMS
+ PLATFORM_PERMISSIONS[Manifest.permission.READ_SMS] = Manifest.permission_group.SMS
+ PLATFORM_PERMISSIONS[Manifest.permission.RECEIVE_MMS] = Manifest.permission_group.SMS
+ PLATFORM_PERMISSIONS[Manifest.permission.RECEIVE_WAP_PUSH] = Manifest.permission_group.SMS
+ PLATFORM_PERMISSIONS[Manifest.permission.READ_CELL_BROADCASTS] =
+ Manifest.permission_group.SMS
+
+ // If permissions are added to the Storage group, they must be added to the
+ // STORAGE_PERMISSIONS list in PermissionManagerService in frameworks/base
+ PLATFORM_PERMISSIONS[Manifest.permission.READ_EXTERNAL_STORAGE] =
+ Manifest.permission_group.STORAGE
+ PLATFORM_PERMISSIONS[Manifest.permission.WRITE_EXTERNAL_STORAGE] =
+ Manifest.permission_group.STORAGE
+ if (!SdkLevel.isAtLeastT()) {
+ PLATFORM_PERMISSIONS[Manifest.permission.ACCESS_MEDIA_LOCATION] =
+ Manifest.permission_group.STORAGE
+ }
+
+ if (SdkLevel.isAtLeastT()) {
+ PLATFORM_PERMISSIONS[Manifest.permission.READ_MEDIA_AUDIO] =
+ Manifest.permission_group.READ_MEDIA_AURAL
+ PLATFORM_PERMISSIONS[Manifest.permission.READ_MEDIA_IMAGES] =
+ Manifest.permission_group.READ_MEDIA_VISUAL
+ PLATFORM_PERMISSIONS[Manifest.permission.READ_MEDIA_VIDEO] =
+ Manifest.permission_group.READ_MEDIA_VISUAL
+ PLATFORM_PERMISSIONS[Manifest.permission.ACCESS_MEDIA_LOCATION] =
+ Manifest.permission_group.READ_MEDIA_VISUAL
+ }
+
+ if (SdkLevel.isAtLeastU()) {
+ PLATFORM_PERMISSIONS[Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED] =
+ Manifest.permission_group.READ_MEDIA_VISUAL
+ }
+
+ PLATFORM_PERMISSIONS[Manifest.permission.ACCESS_FINE_LOCATION] =
+ Manifest.permission_group.LOCATION
+ PLATFORM_PERMISSIONS[Manifest.permission.ACCESS_COARSE_LOCATION] =
+ Manifest.permission_group.LOCATION
+ PLATFORM_PERMISSIONS[Manifest.permission.ACCESS_BACKGROUND_LOCATION] =
+ Manifest.permission_group.LOCATION
+
+ if (SdkLevel.isAtLeastS()) {
+ PLATFORM_PERMISSIONS[Manifest.permission.BLUETOOTH_ADVERTISE] =
+ Manifest.permission_group.NEARBY_DEVICES
+ PLATFORM_PERMISSIONS[Manifest.permission.BLUETOOTH_CONNECT] =
+ Manifest.permission_group.NEARBY_DEVICES
+ PLATFORM_PERMISSIONS[Manifest.permission.BLUETOOTH_SCAN] =
+ Manifest.permission_group.NEARBY_DEVICES
+ PLATFORM_PERMISSIONS[Manifest.permission.UWB_RANGING] =
+ Manifest.permission_group.NEARBY_DEVICES
+ }
+ if (SdkLevel.isAtLeastT()) {
+ PLATFORM_PERMISSIONS[Manifest.permission.NEARBY_WIFI_DEVICES] =
+ Manifest.permission_group.NEARBY_DEVICES
+ }
+
+ // Any updates to the permissions for the CALL_LOG permission group must also be made in
+ // Permissions {@link com.android.role.controller.model.Permissions} in the role
+ // library
+ PLATFORM_PERMISSIONS[Manifest.permission.READ_CALL_LOG] = Manifest.permission_group.CALL_LOG
+ PLATFORM_PERMISSIONS[Manifest.permission.WRITE_CALL_LOG] =
+ Manifest.permission_group.CALL_LOG
+ PLATFORM_PERMISSIONS[Manifest.permission.PROCESS_OUTGOING_CALLS] =
+ Manifest.permission_group.CALL_LOG
+
+ PLATFORM_PERMISSIONS[Manifest.permission.READ_PHONE_STATE] = Manifest.permission_group.PHONE
+ PLATFORM_PERMISSIONS[Manifest.permission.READ_PHONE_NUMBERS] =
+ Manifest.permission_group.PHONE
+ PLATFORM_PERMISSIONS[Manifest.permission.CALL_PHONE] = Manifest.permission_group.PHONE
+ PLATFORM_PERMISSIONS[Manifest.permission.ADD_VOICEMAIL] = Manifest.permission_group.PHONE
+ PLATFORM_PERMISSIONS[Manifest.permission.USE_SIP] = Manifest.permission_group.PHONE
+ PLATFORM_PERMISSIONS[Manifest.permission.ANSWER_PHONE_CALLS] =
+ Manifest.permission_group.PHONE
+ PLATFORM_PERMISSIONS[Manifest.permission.ACCEPT_HANDOVER] = Manifest.permission_group.PHONE
+
+ PLATFORM_PERMISSIONS[Manifest.permission.RECORD_AUDIO] =
+ Manifest.permission_group.MICROPHONE
+ if (SdkLevel.isAtLeastS()) {
+ PLATFORM_PERMISSIONS[Manifest.permission.RECORD_BACKGROUND_AUDIO] =
+ Manifest.permission_group.MICROPHONE
+ }
+
+ PLATFORM_PERMISSIONS[Manifest.permission.ACTIVITY_RECOGNITION] =
+ Manifest.permission_group.ACTIVITY_RECOGNITION
+
+ PLATFORM_PERMISSIONS[Manifest.permission.CAMERA] = Manifest.permission_group.CAMERA
+ if (SdkLevel.isAtLeastS()) {
+ PLATFORM_PERMISSIONS[Manifest.permission.BACKGROUND_CAMERA] =
+ Manifest.permission_group.CAMERA
+ }
+
+ PLATFORM_PERMISSIONS[Manifest.permission.BODY_SENSORS] = Manifest.permission_group.SENSORS
+
+ if (SdkLevel.isAtLeastT()) {
+ PLATFORM_PERMISSIONS[Manifest.permission.POST_NOTIFICATIONS] =
+ Manifest.permission_group.NOTIFICATIONS
+ PLATFORM_PERMISSIONS[Manifest.permission.BODY_SENSORS_BACKGROUND] =
+ Manifest.permission_group.SENSORS
+ }
+
+ for ((permission, permissionGroup) in PLATFORM_PERMISSIONS) {
+ PLATFORM_PERMISSION_GROUPS.getOrPut(permissionGroup) { mutableListOf() }.add(permission)
+ }
+
+ ONE_TIME_PERMISSION_GROUPS.add(Manifest.permission_group.LOCATION)
+ ONE_TIME_PERMISSION_GROUPS.add(Manifest.permission_group.CAMERA)
+ ONE_TIME_PERMISSION_GROUPS.add(Manifest.permission_group.MICROPHONE)
+
+ if (SdkLevel.isAtLeastU()) {
+ PARTIAL_MEDIA_PERMISSIONS.add(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)
+ PARTIAL_MEDIA_PERMISSIONS.add(Manifest.permission.ACCESS_MEDIA_LOCATION)
+ }
+ }
+
+ /**
+ * Get permission group a platform permission belongs to, or null if the permission is not a
+ * platform permission.
+ *
+ * @param permission the permission to resolve
+ *
+ * @return The group the permission belongs to
+ */
+ @JvmStatic
+ fun getGroupOfPlatformPermission(permission: String): String? {
+ return PLATFORM_PERMISSIONS[permission]
+ }
+
+ /**
+ * 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
+ fun getGroupOfPermission(permission: PermissionInfo): String? {
+ var groupName = getGroupOfPlatformPermission(permission.name)
+ if (groupName == null) {
+ groupName = permission.group
+ }
+ return groupName
+ }
+
+ /**
+ * 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
+ */
+ @JvmStatic
+ fun getPlatformPermissionNamesOfGroup(group: String): List<String> {
+ val permissions = PLATFORM_PERMISSION_GROUPS[group]
+ return permissions ?: emptyList()
+ }
+
+ /**
+ * Get the [infos][PermissionInfo] for all platform permissions belonging to a group.
+ *
+ * @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
+ */
+ @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 {
+ pm.getPermissionInfo(permName, 0)
+ } catch (e: PackageManager.NameNotFoundException) {
+ throw IllegalStateException("$permName not defined by platform", e)
+ }
+ permInfos.add(permInfo)
+ }
+ return permInfos
+ }
+
+ @JvmStatic
+ fun isPlatformPermissionGroup(name: String?): Boolean {
+ return PLATFORM_PERMISSION_GROUPS.containsKey(name)
+ }
+
+ /**
+ * Get the names of the platform permission groups.
+ *
+ * @return the names of the platform permission groups.
+ */
+ @JvmStatic
+ fun getPlatformPermissionGroups(): List<String> {
+ return PLATFORM_PERMISSION_GROUPS.keys.toList()
+ }
+
+ /**
+ * Get the names of the runtime platform permissions
+ *
+ * @return the names of the runtime platform permissions.
+ */
+ @JvmStatic
+ fun getRuntimePlatformPermissionNames(): List<String> {
+ return PLATFORM_PERMISSIONS.keys.toList()
+ }
+
+ /**
+ * Is the permissions a platform runtime permission
+ *
+ * @return the names of the runtime platform permissions.
+ */
+ @JvmStatic
+ fun isRuntimePlatformPermission(permission: String): Boolean {
+ return PLATFORM_PERMISSIONS.containsKey(permission)
+ }
+
+ /**
+ * Whether the permission group supports one-time
+ * @param permissionGroup The permission group to check
+ * @return `true` iff the group supports one-time
+ */
+ @JvmStatic
+ fun supportsOneTimeGrant(permissionGroup: String?): Boolean {
+ return ONE_TIME_PERMISSION_GROUPS.contains(permissionGroup)
+ }
+
+ /**
+ * Adds health permissions as platform permissions.
+ */
+ @JvmStatic
+ fun addHealthPermissionsToPlatform(permissions: Set<String>) {
+ if (permissions.isEmpty()) {
+ Log.w(LOG_TAG, "No health connect permissions found.")
+ return
+ }
+
+ PLATFORM_PERMISSION_GROUPS[HEALTH_PERMISSION_GROUP] = mutableListOf()
+
+ for (permission in permissions) {
+ PLATFORM_PERMISSIONS[permission] = HEALTH_PERMISSION_GROUP
+ PLATFORM_PERMISSION_GROUPS[HEALTH_PERMISSION_GROUP]?.add(permission)
+ HEALTH_PERMISSIONS_SET.add(permission)
+ }
+ }
+
+ /**
+ * Get the permissions that, if granted, are considered a "partial grant" of the
+ * READ_MEDIA_VISUAL permission group. If the app declares READ_MEDIA_VISUAL_USER_SELECTED, then
+ * both READ_MEDIA_VISUAL_USER_SELECTED and ACCESS_MEDIA_LOCATION are considered a partial
+ * 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
+
+ return if (appSupportsPickerPrompt) {
+ PARTIAL_MEDIA_PERMISSIONS
+ } else {
+ setOf(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)
+ }
+ }
+
+ /**
+ * Returns true if the given permission is a health platform permission.
+ */
+ @JvmStatic
+ fun isHealthPermission(permissionName: String): Boolean {
+ return HEALTH_PERMISSIONS_SET.contains(permissionName)
+ }
+
+ /**
+ * Returns the platform permission group for the permission that the provided op backs, if any.
+ */
+ fun getPlatformPermissionGroupForOp(opName: String): String? {
+ // The OPSTR_READ_WRITE_HEALTH_DATA is a special case as unlike other ops, it does not
+ // map to a single permission. However it is safe to retrieve a permission group for it,
+ // as all permissions it maps to, map to the same permission group
+ // HEALTH_PERMISSION_GROUP.
+ if (opName == AppOpsManager.OPSTR_READ_WRITE_HEALTH_DATA) {
+ return HEALTH_PERMISSION_GROUP
+ }
+
+ // The following app ops are special cased as they don't back any permissions on their own,
+ // but do indicate usage of certain permissions.
+ if (opName == AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE) {
+ return Manifest.permission_group.MICROPHONE
+ }
+ if (SdkLevel.isAtLeastT() && opName == AppOpsManager.OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO) {
+ return Manifest.permission_group.MICROPHONE
+ }
+ if (opName == AppOpsManager.OPSTR_PHONE_CALL_CAMERA) {
+ return Manifest.permission_group.CAMERA
+ }
+
+ return AppOpsManager.opToPermission(opName)?.let { getGroupOfPlatformPermission(it) }
+ }
+
+ /**
+ * 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
+ */
+ fun getDataCategoriesForPermissionGroup(permissionGroupName: String): List<String> {
+ return if (isSafetyLabelAwarePermissionGroup(permissionGroupName)) {
+ PERMISSION_GROUPS_TO_DATA_CATEGORIES[permissionGroupName] ?: emptyList()
+ } else {
+ emptyList()
+ }
+ }
+
+ /**
+ * Whether this permission group maps to a SafetyLabel data category.
+ *
+ * @param permissionGroupName the permission group name
+ */
+ @JvmStatic
+ fun isSafetyLabelAwarePermissionGroup(permissionGroupName: String): Boolean {
+ if (!KotlinUtils.isPermissionRationaleEnabled()) {
+ return false
+ }
+
+ return PERMISSION_GROUPS_TO_DATA_CATEGORIES.containsKey(permissionGroupName)
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/SafetyNetLogger.java b/PermissionController/src/com/android/permissioncontroller/permission/utils/SafetyNetLogger.java
index f0227cad5..828857cc6 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/SafetyNetLogger.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/SafetyNetLogger.java
@@ -16,17 +16,11 @@
package com.android.permissioncontroller.permission.utils;
-import android.content.pm.PackageInfo;
-import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.EventLog;
-import com.android.permissioncontroller.permission.model.AppPermissionGroup;
-import com.android.permissioncontroller.permission.model.Permission;
import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup;
import com.android.permissioncontroller.permission.model.livedatatypes.LightPermission;
-import java.util.ArrayList;
import java.util.List;
public final class SafetyNetLogger {
@@ -49,21 +43,6 @@ public final class SafetyNetLogger {
*
* <p>The groups might refer to different permission groups and different apps.
*
- * @param packageInfo The info about the package for which permissions were requested
- * @param groups The permission groups which were requested
- */
- public static void logPermissionsRequested(PackageInfo packageInfo,
- List<AppPermissionGroup> groups) {
- EventLog.writeEvent(SNET_NET_EVENT_LOG_TAG, PERMISSIONS_REQUESTED,
- packageInfo.applicationInfo.uid, buildChangedPermissionForPackageMessage(
- packageInfo.packageName, groups));
- }
-
- /**
- * Log that permission groups have been requested for the purpose of safety net.
- *
- * <p>The groups might refer to different permission groups and different apps.
- *
* @param packageName The name of the package for which permissions were requested
* @param uid The uid of the package
* @param groups The permission groups which were requested
@@ -75,52 +54,6 @@ public final class SafetyNetLogger {
}
/**
- * Log that permission groups have been toggled for the purpose of safety net.
- *
- * <p>The groups might refer to different permission groups and different apps.
- *
- * @param groups The groups toggled
- */
- public static void logPermissionsToggled(ArraySet<AppPermissionGroup> groups) {
- ArrayMap<String, ArrayList<AppPermissionGroup>> groupsByPackage = new ArrayMap<>();
-
- int numGroups = groups.size();
- for (int i = 0; i < numGroups; i++) {
- AppPermissionGroup group = groups.valueAt(i);
-
- ArrayList<AppPermissionGroup> groupsForThisPackage = groupsByPackage.get(
- group.getApp().packageName);
- if (groupsForThisPackage == null) {
- groupsForThisPackage = new ArrayList<>();
- groupsByPackage.put(group.getApp().packageName, groupsForThisPackage);
- }
-
- groupsForThisPackage.add(group);
- if (group.getBackgroundPermissions() != null) {
- groupsForThisPackage.add(group.getBackgroundPermissions());
- }
- }
-
- int numPackages = groupsByPackage.size();
- for (int i = 0; i < numPackages; i++) {
- EventLog.writeEvent(SNET_NET_EVENT_LOG_TAG, PERMISSIONS_TOGGLED,
- android.os.Process.myUid(), buildChangedPermissionForPackageMessage(
- groupsByPackage.keyAt(i), groupsByPackage.valueAt(i)));
- }
- }
-
- /**
- * Log that a permission group has been toggled for the purpose of safety net.
- *
- * @param group The group toggled.
- */
- public static void logPermissionToggled(AppPermissionGroup group) {
- ArraySet groups = new ArraySet<AppPermissionGroup>(1);
- groups.add(group);
- logPermissionsToggled(groups);
- }
-
- /**
* Log that a permission group has been toggled for the purpose of safety net.
*
* @param group The group which was toggled. This group must represent the current state, not
@@ -167,22 +100,6 @@ public final class SafetyNetLogger {
}
}
- private static void buildChangedPermissionForGroup(AppPermissionGroup group,
- StringBuilder builder) {
- int permissionCount = group.getPermissions().size();
- for (int permissionNum = 0; permissionNum < permissionCount; permissionNum++) {
- Permission permission = group.getPermissions().get(permissionNum);
-
- if (builder.length() > 0) {
- builder.append(';');
- }
-
- builder.append(permission.getName()).append('|');
- builder.append(permission.isGrantedIncludingAppOp()).append('|');
- builder.append(permission.getFlags());
- }
- }
-
private static String buildChangedPermissionForPackageMessageNew(String packageName,
List<LightAppPermGroup> groups) {
StringBuilder builder = new StringBuilder();
@@ -193,23 +110,4 @@ public final class SafetyNetLogger {
}
return builder.toString();
}
-
- private static String buildChangedPermissionForPackageMessage(String packageName,
- List<AppPermissionGroup> groups) {
- StringBuilder builder = new StringBuilder();
-
- builder.append(packageName).append(':');
-
- int groupCount = groups.size();
- for (int groupNum = 0; groupNum < groupCount; groupNum++) {
- AppPermissionGroup group = groups.get(groupNum);
-
- buildChangedPermissionForGroup(group, builder);
- if (group.getBackgroundPermissions() != null) {
- buildChangedPermissionForGroup(group.getBackgroundPermissions(), builder);
- }
- }
-
- return builder.toString();
- }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java b/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java
index 48793ab51..d4354bd72 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java
@@ -34,14 +34,17 @@ import static android.Manifest.permission_group.STORAGE;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.OPSTR_LEGACY_STORAGE;
import static android.content.Context.MODE_PRIVATE;
+import static android.content.Intent.EXTRA_PACKAGE_NAME;
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED;
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.os.UserHandle.myUserId;
+import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -52,6 +55,7 @@ import android.app.Application;
import android.app.admin.DevicePolicyManager;
import android.app.role.RoleManager;
import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -65,11 +69,13 @@ import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.SensorPrivacyManager;
+import android.os.Binder;
import android.os.Build;
import android.os.Parcelable;
-import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
@@ -78,12 +84,13 @@ import android.text.Html;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.Log;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
+import androidx.annotation.ChecksSdkIntAtLeast;
+import androidx.annotation.ColorRes;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -107,7 +114,6 @@ import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Calendar;
-import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@@ -129,19 +135,6 @@ public final class Utils {
public static final int LAST_7D_CONTENT_PROVIDER = 5;
public static final int NOT_IN_LAST_7D = 6;
- private static final List<String> SENSOR_DATA_PERMISSIONS = List.of(
- Manifest.permission_group.LOCATION,
- Manifest.permission_group.CAMERA,
- Manifest.permission_group.MICROPHONE
- );
-
- public static final List<String> STORAGE_SUPERGROUP_PERMISSIONS =
- !SdkLevel.isAtLeastT() ? List.of() : List.of(
- Manifest.permission_group.STORAGE,
- Manifest.permission_group.READ_MEDIA_AURAL,
- Manifest.permission_group.READ_MEDIA_VISUAL
- );
-
private static final String LOG_TAG = "Utils";
public static final String OS_PKG = "android";
@@ -163,6 +156,10 @@ public final class Utils {
/** Whether or not app hibernation is enabled on the device **/
public static final String PROPERTY_APP_HIBERNATION_ENABLED = "app_hibernation_enabled";
+ /** Whether the system exempt from hibernation is enabled on the device **/
+ 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";
@@ -178,11 +175,23 @@ public final class Utils {
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";
+
+
/** How frequently to check permission event store to scrub old data */
public static final String PROPERTY_PERMISSION_EVENTS_CHECK_OLD_FREQUENCY_MILLIS =
"permission_events_check_old_frequency_millis";
- /** The time an app needs to be unused in order to be hibernated */
+ /**
+ * Whether to store the exact time for permission changes. Only for use in tests and should
+ * not be modified in prod.
+ */
+ public static final String PROPERTY_PERMISSION_CHANGES_STORE_EXACT_TIME =
+ "permission_changes_store_exact_time";
+
+ /** The max amount of time permission data can stay in the storage before being scrubbed */
public static final String PROPERTY_PERMISSION_DECISIONS_MAX_DATA_AGE_MILLIS =
"permission_decisions_max_data_age_millis";
@@ -212,15 +221,6 @@ public final class Utils {
*/
public static final long ONE_TIME_PERMISSIONS_KILLED_DELAY_MILLIS = 5 * 1000;
- /** Mapping permission -> group for all dangerous platform permissions */
- private static final ArrayMap<String, String> PLATFORM_PERMISSIONS;
-
- /** Mapping group -> permissions for all dangerous platform permissions */
- private static final ArrayMap<String, ArrayList<String>> PLATFORM_PERMISSION_GROUPS;
-
- /** Set of groups that will be able to receive one-time grant */
- private static final ArraySet<String> ONE_TIME_PERMISSION_GROUPS;
-
private static final ArrayMap<String, Integer> PERM_GROUP_REQUEST_RES;
private static final ArrayMap<String, Integer> PERM_GROUP_REQUEST_DETAIL_RES;
private static final ArrayMap<String, Integer> PERM_GROUP_BACKGROUND_REQUEST_RES;
@@ -239,8 +239,6 @@ public final class Utils {
FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
| FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED;
- private static final String SYSTEM_PKG = "android";
-
private static final String SYSTEM_AMBIENT_AUDIO_INTELLIGENCE =
"android.app.role.SYSTEM_AMBIENT_AUDIO_INTELLIGENCE";
private static final String SYSTEM_UI_INTELLIGENCE =
@@ -265,102 +263,6 @@ public final class Utils {
};
static {
- PLATFORM_PERMISSIONS = new ArrayMap<>();
-
- PLATFORM_PERMISSIONS.put(Manifest.permission.READ_CONTACTS, CONTACTS);
- PLATFORM_PERMISSIONS.put(Manifest.permission.WRITE_CONTACTS, CONTACTS);
- PLATFORM_PERMISSIONS.put(Manifest.permission.GET_ACCOUNTS, CONTACTS);
-
- PLATFORM_PERMISSIONS.put(Manifest.permission.READ_CALENDAR, CALENDAR);
- PLATFORM_PERMISSIONS.put(Manifest.permission.WRITE_CALENDAR, CALENDAR);
-
- PLATFORM_PERMISSIONS.put(Manifest.permission.SEND_SMS, SMS);
- PLATFORM_PERMISSIONS.put(Manifest.permission.RECEIVE_SMS, SMS);
- PLATFORM_PERMISSIONS.put(Manifest.permission.READ_SMS, SMS);
- PLATFORM_PERMISSIONS.put(Manifest.permission.RECEIVE_MMS, SMS);
- PLATFORM_PERMISSIONS.put(Manifest.permission.RECEIVE_WAP_PUSH, SMS);
- PLATFORM_PERMISSIONS.put(Manifest.permission.READ_CELL_BROADCASTS, SMS);
-
- // If permissions are added to the Storage group, they must be added to the
- // STORAGE_PERMISSIONS list in PermissionManagerService in frameworks/base
- PLATFORM_PERMISSIONS.put(Manifest.permission.READ_EXTERNAL_STORAGE, STORAGE);
- PLATFORM_PERMISSIONS.put(Manifest.permission.WRITE_EXTERNAL_STORAGE, STORAGE);
- if (!SdkLevel.isAtLeastT()) {
- PLATFORM_PERMISSIONS.put(Manifest.permission.ACCESS_MEDIA_LOCATION, STORAGE);
- }
-
- if (SdkLevel.isAtLeastT()) {
- PLATFORM_PERMISSIONS.put(Manifest.permission.READ_MEDIA_AUDIO, READ_MEDIA_AURAL);
- PLATFORM_PERMISSIONS.put(Manifest.permission.READ_MEDIA_IMAGES, READ_MEDIA_VISUAL);
- PLATFORM_PERMISSIONS.put(Manifest.permission.READ_MEDIA_VIDEO, READ_MEDIA_VISUAL);
- PLATFORM_PERMISSIONS.put(Manifest.permission.ACCESS_MEDIA_LOCATION, READ_MEDIA_VISUAL);
- }
-
- PLATFORM_PERMISSIONS.put(Manifest.permission.ACCESS_FINE_LOCATION, LOCATION);
- PLATFORM_PERMISSIONS.put(Manifest.permission.ACCESS_COARSE_LOCATION, LOCATION);
- PLATFORM_PERMISSIONS.put(Manifest.permission.ACCESS_BACKGROUND_LOCATION, LOCATION);
-
- if (SdkLevel.isAtLeastS()) {
- PLATFORM_PERMISSIONS.put(Manifest.permission.BLUETOOTH_ADVERTISE, NEARBY_DEVICES);
- PLATFORM_PERMISSIONS.put(Manifest.permission.BLUETOOTH_CONNECT, NEARBY_DEVICES);
- PLATFORM_PERMISSIONS.put(Manifest.permission.BLUETOOTH_SCAN, NEARBY_DEVICES);
- PLATFORM_PERMISSIONS.put(Manifest.permission.UWB_RANGING, NEARBY_DEVICES);
- }
- if (SdkLevel.isAtLeastT()) {
- PLATFORM_PERMISSIONS.put(Manifest.permission.NEARBY_WIFI_DEVICES, NEARBY_DEVICES);
- }
-
- PLATFORM_PERMISSIONS.put(Manifest.permission.READ_CALL_LOG, CALL_LOG);
- PLATFORM_PERMISSIONS.put(Manifest.permission.WRITE_CALL_LOG, CALL_LOG);
- PLATFORM_PERMISSIONS.put(Manifest.permission.PROCESS_OUTGOING_CALLS, CALL_LOG);
-
- PLATFORM_PERMISSIONS.put(Manifest.permission.READ_PHONE_STATE, PHONE);
- PLATFORM_PERMISSIONS.put(Manifest.permission.READ_PHONE_NUMBERS, PHONE);
- PLATFORM_PERMISSIONS.put(Manifest.permission.CALL_PHONE, PHONE);
- PLATFORM_PERMISSIONS.put(Manifest.permission.ADD_VOICEMAIL, PHONE);
- PLATFORM_PERMISSIONS.put(Manifest.permission.USE_SIP, PHONE);
- PLATFORM_PERMISSIONS.put(Manifest.permission.ANSWER_PHONE_CALLS, PHONE);
- PLATFORM_PERMISSIONS.put(Manifest.permission.ACCEPT_HANDOVER, PHONE);
-
- PLATFORM_PERMISSIONS.put(Manifest.permission.RECORD_AUDIO, MICROPHONE);
- if (SdkLevel.isAtLeastS()) {
- PLATFORM_PERMISSIONS.put(Manifest.permission.RECORD_BACKGROUND_AUDIO, MICROPHONE);
- }
-
- PLATFORM_PERMISSIONS.put(Manifest.permission.ACTIVITY_RECOGNITION, ACTIVITY_RECOGNITION);
-
- PLATFORM_PERMISSIONS.put(Manifest.permission.CAMERA, CAMERA);
- if (SdkLevel.isAtLeastS()) {
- PLATFORM_PERMISSIONS.put(Manifest.permission.BACKGROUND_CAMERA, CAMERA);
- }
-
- PLATFORM_PERMISSIONS.put(Manifest.permission.BODY_SENSORS, SENSORS);
-
- if (SdkLevel.isAtLeastT()) {
- PLATFORM_PERMISSIONS.put(Manifest.permission.POST_NOTIFICATIONS, NOTIFICATIONS);
- PLATFORM_PERMISSIONS.put(Manifest.permission.BODY_SENSORS_BACKGROUND, SENSORS);
- }
-
- PLATFORM_PERMISSION_GROUPS = new ArrayMap<>();
- int numPlatformPermissions = PLATFORM_PERMISSIONS.size();
- for (int i = 0; i < numPlatformPermissions; i++) {
- String permission = PLATFORM_PERMISSIONS.keyAt(i);
- String permissionGroup = PLATFORM_PERMISSIONS.valueAt(i);
-
- ArrayList<String> permissionsOfThisGroup = PLATFORM_PERMISSION_GROUPS.get(
- permissionGroup);
- if (permissionsOfThisGroup == null) {
- permissionsOfThisGroup = new ArrayList<>();
- PLATFORM_PERMISSION_GROUPS.put(permissionGroup, permissionsOfThisGroup);
- }
-
- permissionsOfThisGroup.add(permission);
- }
-
- ONE_TIME_PERMISSION_GROUPS = new ArraySet<>();
- ONE_TIME_PERMISSION_GROUPS.add(LOCATION);
- ONE_TIME_PERMISSION_GROUPS.add(CAMERA);
- ONE_TIME_PERMISSION_GROUPS.add(MICROPHONE);
PERM_GROUP_REQUEST_RES = new ArrayMap<>();
PERM_GROUP_REQUEST_RES.put(CONTACTS, R.string.permgrouprequest_contacts);
@@ -449,20 +351,19 @@ public final class Utils {
* Creates and caches a PackageContext for the requested user, or returns the previously cached
* value. The package of the PackageContext is the application's package.
*
- * @param app The currently running application
+ * @param context The context of the currently running application
* @param user The desired user for the context
*
* @return The generated or cached Context for the requested user
*
- * @throws PackageManager.NameNotFoundException If the app has no package name attached
+ * @throws RuntimeException If the app has no package name attached, which should never happen
*/
- public static @NonNull Context getUserContext(Application app, UserHandle user) throws
- PackageManager.NameNotFoundException {
+ public static @NonNull Context getUserContext(Context context, UserHandle user) {
if (!sUserContexts.containsKey(user)) {
- sUserContexts.put(user, app.getApplicationContext()
- .createPackageContextAsUser(app.getPackageName(), 0, user));
+ sUserContexts.put(user, context.getApplicationContext()
+ .createContextAsUser(user, 0));
}
- return sUserContexts.get(user);
+ return Preconditions.checkNotNull(sUserContexts.get(user));
}
/**
@@ -518,81 +419,6 @@ public final class Utils {
}
/**
- * Get permission group a platform permission belongs to, or null if the permission is not a
- * platform permission.
- *
- * @param permission the permission to resolve
- *
- * @return The group the permission belongs to
- */
- public static @Nullable String getGroupOfPlatformPermission(@NonNull String permission) {
- return PLATFORM_PERMISSIONS.get(permission);
- }
-
- /**
- * Get name of the permission group a permission belongs to.
- *
- * @param permission the {@link PermissionInfo info} of the permission to resolve
- *
- * @return The group the permission belongs to
- */
- public static @Nullable String getGroupOfPermission(@NonNull PermissionInfo permission) {
- String groupName = Utils.getGroupOfPlatformPermission(permission.name);
- if (groupName == null) {
- groupName = permission.group;
- }
-
- return groupName;
- }
-
- /**
- * 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 is not does not have platform runtime permissions
- */
- public static @NonNull List<String> getPlatformPermissionNamesOfGroup(@NonNull String group) {
- final ArrayList<String> permissions = PLATFORM_PERMISSION_GROUPS.get(group);
- return (permissions != null) ? permissions : Collections.emptyList();
- }
-
- /**
- * Get the {@link PermissionInfo infos} for all platform permissions belonging to a group.
- *
- * @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 is not does not have platform runtime permissions
- */
- public static @NonNull List<PermissionInfo> getPlatformPermissionsOfGroup(
- @NonNull PackageManager pm, @NonNull String group) {
- ArrayList<PermissionInfo> permInfos = new ArrayList<>();
-
- ArrayList<String> permissions = PLATFORM_PERMISSION_GROUPS.get(group);
- if (permissions == null) {
- return Collections.emptyList();
- }
-
- int numPermissions = permissions.size();
- for (int i = 0; i < numPermissions; i++) {
- String permName = permissions.get(i);
- PermissionInfo permInfo;
- try {
- permInfo = pm.getPermissionInfo(permName, 0);
- } catch (PackageManager.NameNotFoundException e) {
- throw new IllegalStateException(permName + " not defined by platform", e);
- }
-
- permInfos.add(permInfo);
- }
-
- return permInfos;
- }
-
- /**
* Get the {@link PermissionInfo infos} for all permission infos belonging to a group.
*
* @param pm Package manager to use to resolve permission infos
@@ -605,7 +431,7 @@ public final class Utils {
@NonNull PackageManager pm, @NonNull String group)
throws PackageManager.NameNotFoundException {
List<PermissionInfo> permissions = pm.queryPermissionsByGroup(group, 0);
- permissions.addAll(getPlatformPermissionsOfGroup(pm, group));
+ permissions.addAll(PermissionMapping.getPlatformPermissionsOfGroup(pm, group));
/*
* If the undefined group is requested, the package manager will return all platform
@@ -615,7 +441,8 @@ public final class Utils {
if (group.equals(Manifest.permission_group.UNDEFINED)) {
List<PermissionInfo> undefinedPerms = new ArrayList<>();
for (PermissionInfo permissionInfo : permissions) {
- String permGroup = getGroupOfPlatformPermission(permissionInfo.name);
+ String permGroup =
+ PermissionMapping.getGroupOfPlatformPermission(permissionInfo.name);
if (permGroup == null || permGroup.equals(Manifest.permission_group.UNDEFINED)) {
undefinedPerms.add(permissionInfo);
}
@@ -640,7 +467,7 @@ public final class Utils {
@NonNull PackageManager pm, @NonNull String group)
throws PackageManager.NameNotFoundException {
List<PermissionInfo> permissions = pm.queryPermissionsByGroup(group, 0);
- permissions.addAll(getPlatformPermissionsOfGroup(pm, group));
+ permissions.addAll(PermissionMapping.getPlatformPermissionsOfGroup(pm, group));
List<PermissionInfo> installedRuntime = new ArrayList<>();
for (PermissionInfo permissionInfo: permissions) {
@@ -659,7 +486,8 @@ public final class Utils {
if (group.equals(Manifest.permission_group.UNDEFINED)) {
List<PermissionInfo> undefinedPerms = new ArrayList<>();
for (PermissionInfo permissionInfo : installedRuntime) {
- String permGroup = getGroupOfPlatformPermission(permissionInfo.name);
+ String permGroup =
+ PermissionMapping.getGroupOfPlatformPermission(permissionInfo.name);
if (permGroup == null || permGroup.equals(Manifest.permission_group.UNDEFINED)) {
undefinedPerms.add(permissionInfo);
}
@@ -776,37 +604,6 @@ public final class Utils {
}
}
- public static boolean isModernPermissionGroup(String name) {
- return PLATFORM_PERMISSION_GROUPS.containsKey(name);
- }
-
- /**
- * Get the names of the platform permission groups.
- *
- * @return the names of the platform permission groups.
- */
- public static List<String> getPlatformPermissionGroups() {
- return new ArrayList<>(PLATFORM_PERMISSION_GROUPS.keySet());
- }
-
- /**
- * Get the names of the runtime platform permissions
- *
- * @return the names of the runtime platform permissions.
- */
- public static List<String> getRuntimePlatformPermissionNames() {
- return new ArrayList<>(PLATFORM_PERMISSIONS.keySet());
- }
-
- /**
- * Is the permissions a platform runtime permission
- *
- * @return the names of the runtime platform permissions.
- */
- public static boolean isRuntimePlatformPermission(@NonNull String permission) {
- return PLATFORM_PERMISSIONS.containsKey(permission);
- }
-
/**
* Should UI show this permission.
*
@@ -824,7 +621,7 @@ public final class Utils {
final boolean isPlatformPermission = group.getDeclaringPackage().equals(OS_PKG);
// Show legacy permissions only if the user chose that.
if (isPlatformPermission
- && !Utils.isModernPermissionGroup(group.getName())) {
+ && !PermissionMapping.isPlatformPermissionGroup(group.getName())) {
return false;
}
return true;
@@ -843,8 +640,17 @@ public final class Utils {
return applyTint(context, context.getDrawable(iconResId), attr);
}
- public static List<ApplicationInfo> getAllInstalledApplications(Context context) {
- return context.getPackageManager().getInstalledApplications(0);
+ /**
+ * Get the color resource id based on the attribute
+ *
+ * @return Resource id for the color
+ */
+ @ColorRes
+ public static int getColorResId(Context context, int attr) {
+ Theme theme = context.getTheme();
+ TypedValue typedValue = new TypedValue();
+ theme.resolveAttribute(attr, typedValue, true);
+ return typedValue.resourceId;
}
/**
@@ -968,12 +774,7 @@ public final class Utils {
}
int targetSdkVersion = pkg.getTargetSdkVersion();
PermissionControllerApplication app = PermissionControllerApplication.get();
- Context context = null;
- try {
- context = Utils.getUserContext(app, UserHandle.getUserHandleForUid(pkg.getUid()));
- } catch (NameNotFoundException e) {
- return true;
- }
+ Context context = Utils.getUserContext(app, UserHandle.getUserHandleForUid(pkg.getUid()));
AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
if (appOpsManager == null) {
return true;
@@ -1062,12 +863,9 @@ public final class Utils {
@NonNull ApplicationInfo appInfo) {
UserHandle user = UserHandle.getUserHandleForUid(appInfo.uid);
try (IconFactory iconFactory = IconFactory.obtain(context)) {
- return iconFactory.createBadgedIconBitmap(
- appInfo.loadUnbadgedIcon(context.getPackageManager()),
- new IconFactory.IconOptions()
- .setShrinkNonAdaptiveIcons(false)
- .setUser(user))
- .newIcon(context);
+ Bitmap iconBmp = iconFactory.createBadgedIconBitmap(
+ appInfo.loadUnbadgedIcon(context.getPackageManager()), user, false).icon;
+ return new BitmapDrawable(context.getResources(), iconBmp);
}
}
@@ -1129,6 +927,22 @@ public final class Utils {
}
/**
+ * Whether we should show health permissions as platform permissions in the various
+ * permission controller UI.
+ */
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codename = "UpsideDownCake")
+ public static boolean isHealthPermissionUiEnabled() {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return SdkLevel.isAtLeastU()
+ && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_HEALTH_PERMISSION_UI_ENABLED, true);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
* Get a device protected storage based shared preferences. Avoid storing sensitive data in it.
*
* @param context the context to get the shared preferences
@@ -1194,15 +1008,6 @@ public final class Utils {
}
/**
- * Whether the permission group supports one-time
- * @param permissionGroup The permission group to check
- * @return {@code true} iff the group supports one-time
- */
- public static boolean supportsOneTimeGrant(String permissionGroup) {
- return ONE_TIME_PERMISSION_GROUPS.contains(permissionGroup);
- }
-
- /**
* The resource id for the request message for a permission group
* @param groupName Permission group name
* @return The id or 0 if the permission group doesn't exist or have a message
@@ -1257,46 +1062,28 @@ public final class Utils {
}
/**
- * Checks whether a package has an active one-time permission according to the system server's
- * flags
+ * Returns a random session ID value that's guaranteed to not be {@code INVALID_SESSION_ID}.
*
- * @param context the {@code Context} to retrieve {@code PackageManager}
- * @param packageName The package to check for
- * @return Whether a package has an active one-time permission
+ * @return A valid session ID.
*/
- public static boolean hasOneTimePermissions(Context context, String packageName) {
- String[] permissions;
- PackageManager pm = context.getPackageManager();
- try {
- permissions = pm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS)
- .requestedPermissions;
- } catch (NameNotFoundException e) {
- Log.w(LOG_TAG, "Checking for one-time permissions in nonexistent package");
- return false;
- }
- if (permissions == null) {
- return false;
- }
- for (String permissionName : permissions) {
- if ((pm.getPermissionFlags(permissionName, packageName, Process.myUserHandle())
- & PackageManager.FLAG_PERMISSION_ONE_TIME) != 0
- && pm.checkPermission(permissionName, packageName)
- == PackageManager.PERMISSION_GRANTED) {
- return true;
- }
+ public static long getValidSessionId() {
+ long sessionId = INVALID_SESSION_ID;
+ while (sessionId == INVALID_SESSION_ID) {
+ sessionId = new Random().nextLong();
}
- return false;
+ return sessionId;
}
/**
- * Returns a random session ID value that's guaranteed to not be {@code INVALID_SESSION_ID}.
+ * Retrieves an existing session ID from the given intent or generates a new one if none is
+ * present.
*
* @return A valid session ID.
*/
- public static long getValidSessionId() {
- long sessionId = INVALID_SESSION_ID;
- while (sessionId == INVALID_SESSION_ID) {
- sessionId = new Random().nextLong();
+ public static long getOrGenerateSessionId(Intent intent) {
+ long sessionId = intent.getLongExtra(EXTRA_SESSION_ID, INVALID_SESSION_ID);
+ if (sessionId == INVALID_SESSION_ID) {
+ sessionId = getValidSessionId();
}
return sessionId;
}
@@ -1330,7 +1117,18 @@ public final class Utils {
// In android TV, parental control accounts are managed profiles
return !userManager.getEnabledProfiles().contains(user)
|| (userManager.isManagedProfile(user.getIdentifier())
- && !DeviceUtils.isTelevision(app));
+ && !DeviceUtils.isTelevision(app));
+ }
+
+ /**
+ * Determines if a given user ID belongs to a managed profile user.
+ * @param userId The user ID to check
+ * @return true if the user is a managed profile
+ */
+ public static boolean isUserManagedProfile(int userId) {
+ return PermissionControllerApplication.get()
+ .getSystemService(UserManager.class)
+ .isManagedProfile(userId);
}
/**
@@ -1339,7 +1137,7 @@ public final class Utils {
public static Set<String> getExemptedPackages(@NonNull RoleManager roleManager) {
Set<String> exemptedPackages = new HashSet<>();
- exemptedPackages.add(SYSTEM_PKG);
+ exemptedPackages.add(OS_PKG);
for (int i = 0; i < EXEMPTED_ROLES.length; i++) {
exemptedPackages.addAll(roleManager.getRoleHolders(EXEMPTED_ROLES[i]));
}
@@ -1378,7 +1176,7 @@ public final class Utils {
lastAccessDateFormatted = DateFormat.getDateFormat(context)
.format(lastAccessTime);
- if (!SENSOR_DATA_PERMISSIONS.contains(groupName)) {
+ if (!PermissionMapping.SENSOR_DATA_PERMISSIONS.contains(groupName)) {
// For content providers we show either the last access is within
// past 24 hours or past 7 days
lastAccessType = isLastAccessWithinPast24h
@@ -1426,6 +1224,28 @@ public final class Utils {
}
/**
+ * Navigate to health connect settings for all apps
+ * @param context The current Context
+ */
+ public static void navigateToHealthConnectSettings(@NonNull Context context) {
+ Intent healthConnectIntent = new Intent(ACTION_MANAGE_HEALTH_PERMISSIONS);
+ context.startActivity(healthConnectIntent);
+ }
+
+ /**
+ * Navigate to health connect settings for an app
+ * @param context The current Context
+ * @param packageName The package's health connect settings to navigate to
+ */
+ public static void navigateToAppHealthConnectSettings(@NonNull Context context,
+ @NonNull String packageName, @NonNull UserHandle user) {
+ Intent appHealthConnectIntent = new Intent(ACTION_MANAGE_HEALTH_PERMISSIONS);
+ appHealthConnectIntent.putExtra(EXTRA_PACKAGE_NAME, packageName);
+ appHealthConnectIntent.putExtra(Intent.EXTRA_USER, user);
+ context.startActivity(appHealthConnectIntent);
+ }
+
+ /**
* Returns if a card should be shown if the sensor is blocked
**/
public static boolean shouldDisplayCardIfBlocked(@NonNull String permissionGroupName) {
@@ -1491,4 +1311,32 @@ public final class Utils {
return dpm.getResources().getString(updatableStringId, () -> context.getString(
defaultStringId, formatArgs), formatArgs);
}
+
+ /**
+ * Get {@link PackageInfo} for this ComponentName.
+ *
+ * @param context The current Context
+ * @param component component to get package info for
+ * @return The package info
+ *
+ * @throws PackageManager.NameNotFoundException if package does not exist
+ */
+ @NonNull
+ public static PackageInfo getPackageInfoForComponentName(@NonNull Context context,
+ @NonNull ComponentName component) throws PackageManager.NameNotFoundException {
+ return context.getPackageManager().getPackageInfo(component.getPackageName(), 0);
+ }
+
+ /**
+ * Return the label to use for this application.
+ *
+ * @param context The current Context
+ * @param applicationInfo The {@link ApplicationInfo} of the application to get the label of.
+ * @return the label associated with this application, or its name if there is no label.
+ */
+ @NonNull
+ public static String getApplicationLabel(@NonNull Context context,
+ @NonNull ApplicationInfo applicationInfo) {
+ return context.getPackageManager().getApplicationLabel(applicationInfo).toString();
+ }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/legacy/LegacySafetyNetLogger.java b/PermissionController/src/com/android/permissioncontroller/permission/utils/legacy/LegacySafetyNetLogger.java
new file mode 100644
index 000000000..0bda36539
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/legacy/LegacySafetyNetLogger.java
@@ -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.utils.legacy;
+
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.EventLog;
+
+import com.android.permissioncontroller.permission.model.AppPermissionGroup;
+import com.android.permissioncontroller.permission.model.Permission;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Legacy SafetyNetLogger that interacts with AppPermissionGroup for TV and wear.
+ */
+public class LegacySafetyNetLogger {
+ // The log tag used by SafetyNet to pick entries from the event log.
+ private static final int SNET_NET_EVENT_LOG_TAG = 0x534e4554;
+
+ // Log tag for the result of permissions toggling.
+ private static final String PERMISSIONS_TOGGLED = "individual_permissions_toggled";
+
+ private LegacySafetyNetLogger() {
+ /* do nothing */
+ }
+
+ /**
+ * Log that permission groups have been toggled for the purpose of safety net.
+ *
+ * <p>The groups might refer to different permission groups and different apps.
+ *
+ * @param groups The groups toggled
+ */
+ public static void logPermissionsToggled(ArraySet<AppPermissionGroup> groups) {
+ ArrayMap<String, ArrayList<AppPermissionGroup>> groupsByPackage = new ArrayMap<>();
+
+ int numGroups = groups.size();
+ for (int i = 0; i < numGroups; i++) {
+ AppPermissionGroup group = groups.valueAt(i);
+
+ ArrayList<AppPermissionGroup> groupsForThisPackage = groupsByPackage.get(
+ group.getApp().packageName);
+ if (groupsForThisPackage == null) {
+ groupsForThisPackage = new ArrayList<>();
+ groupsByPackage.put(group.getApp().packageName, groupsForThisPackage);
+ }
+
+ groupsForThisPackage.add(group);
+ if (group.getBackgroundPermissions() != null) {
+ groupsForThisPackage.add(group.getBackgroundPermissions());
+ }
+ }
+
+ int numPackages = groupsByPackage.size();
+ for (int i = 0; i < numPackages; i++) {
+ EventLog.writeEvent(SNET_NET_EVENT_LOG_TAG, PERMISSIONS_TOGGLED,
+ android.os.Process.myUid(), buildChangedPermissionForPackageMessage(
+ groupsByPackage.keyAt(i), groupsByPackage.valueAt(i)));
+ }
+ }
+
+ private static String buildChangedPermissionForPackageMessage(String packageName,
+ List<AppPermissionGroup> groups) {
+ StringBuilder builder = new StringBuilder();
+
+ builder.append(packageName).append(':');
+
+ int groupCount = groups.size();
+ for (int groupNum = 0; groupNum < groupCount; groupNum++) {
+ AppPermissionGroup group = groups.get(groupNum);
+
+ buildChangedPermissionForGroup(group, builder);
+ if (group.getBackgroundPermissions() != null) {
+ buildChangedPermissionForGroup(group.getBackgroundPermissions(), builder);
+ }
+ }
+
+ return builder.toString();
+ }
+
+ private static void buildChangedPermissionForGroup(AppPermissionGroup group,
+ StringBuilder builder) {
+ int permissionCount = group.getPermissions().size();
+ for (int permissionNum = 0; permissionNum < permissionCount; permissionNum++) {
+ Permission permission = group.getPermissions().get(permissionNum);
+
+ if (builder.length() > 0) {
+ builder.append(';');
+ }
+
+ builder.append(permission.getName()).append('|');
+ builder.append(permission.isGrantedIncludingAppOp()).append('|');
+ builder.append(permission.getFlags());
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/AdminRestrictedPermissionsUtils.java b/PermissionController/src/com/android/permissioncontroller/permission/utils/v31/AdminRestrictedPermissionsUtils.java
index 4ee6411d8..770ee6c95 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/AdminRestrictedPermissionsUtils.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/v31/AdminRestrictedPermissionsUtils.java
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.utils;
+package com.android.permissioncontroller.permission.utils.v31;
import android.Manifest;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.ManagedSubscriptionsPolicy;
import android.content.Context;
import android.os.UserHandle;
import android.os.UserManager;
@@ -55,16 +56,6 @@ public final class AdminRestrictedPermissionsUtils {
}
/**
- * A set of permissions that the managed Profile Owner cannot grant.
- */
- private static final ArraySet<String> MANAGED_PROFILE_OWNER_RESTRICTED_PERMISSIONS =
- new ArraySet<>();
-
- static {
- MANAGED_PROFILE_OWNER_RESTRICTED_PERMISSIONS.add(Manifest.permission.READ_SMS);
- }
-
- /**
* Returns true if the admin may grant this permission, false otherwise.
*/
public static boolean mayAdminGrantPermission(Context context, String permission, int userId) {
@@ -74,9 +65,8 @@ public final class AdminRestrictedPermissionsUtils {
Context userContext = context.createContextAsUser(UserHandle.of(userId), /* flags= */0);
DevicePolicyManager dpm = userContext.getSystemService(DevicePolicyManager.class);
UserManager um = userContext.getSystemService(UserManager.class);
- if (um.isManagedProfile(userId)
- && MANAGED_PROFILE_OWNER_RESTRICTED_PERMISSIONS.contains(permission)) {
- return false;
+ if (um.isManagedProfile(userId) && Manifest.permission.READ_SMS.equals(permission)) {
+ return mayManagedProfileAdminGrantReadSms(dpm);
}
if (!ADMIN_RESTRICTED_SENSORS_PERMISSIONS.contains(permission)) {
return true;
@@ -89,12 +79,13 @@ public final class AdminRestrictedPermissionsUtils {
* Returns true if the admin may grant this permission, false otherwise.
*/
public static boolean mayAdminGrantPermission(String permission,
- boolean canAdminGrantSensorsPermissions, boolean isManagedProfile) {
+ boolean canAdminGrantSensorsPermissions, boolean isManagedProfile,
+ DevicePolicyManager dpm) {
if (!SdkLevel.isAtLeastS()) {
return true;
}
- if (isManagedProfile && MANAGED_PROFILE_OWNER_RESTRICTED_PERMISSIONS.contains(permission)) {
- return false;
+ if (isManagedProfile && Manifest.permission.READ_SMS.equals(permission)) {
+ return mayManagedProfileAdminGrantReadSms(dpm);
}
if (!ADMIN_RESTRICTED_SENSORS_PERMISSIONS.contains(permission)) {
return true;
@@ -102,4 +93,10 @@ public final class AdminRestrictedPermissionsUtils {
return canAdminGrantSensorsPermissions;
}
+
+ private static boolean mayManagedProfileAdminGrantReadSms(DevicePolicyManager dpm) {
+ return SdkLevel.isAtLeastU() && dpm.isOrganizationOwnedDeviceWithManagedProfile()
+ && dpm.getManagedSubscriptionsPolicy().getPolicyType()
+ == ManagedSubscriptionsPolicy.TYPE_ALL_MANAGED_SUBSCRIPTIONS;
+ }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/SubattributionUtils.java b/PermissionController/src/com/android/permissioncontroller/permission/utils/v31/SubattributionUtils.java
index e60b6c18a..8919953b4 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/SubattributionUtils.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/v31/SubattributionUtils.java
@@ -14,9 +14,8 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.utils;
+package com.android.permissioncontroller.permission.utils.v31;
-import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.Attribution;
@@ -25,10 +24,12 @@ import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.Build;
+import androidx.annotation.ChecksSdkIntAtLeast;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.android.modules.utils.build.SdkLevel;
+import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo;
import java.util.HashMap;
import java.util.Map;
@@ -41,6 +42,7 @@ public class SubattributionUtils {
/**
* Returns true if the app supports subattribution.
*/
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.S)
public static boolean isSubattributionSupported(Context context, ApplicationInfo appInfo) {
if (!SdkLevel.isAtLeastS()) {
return false;
@@ -48,14 +50,18 @@ public class SubattributionUtils {
return appInfo.areAttributionsUserVisible();
}
+ /** Returns whether the provided package supports subattribution. */
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.S)
+ public static boolean isSubattributionSupported(LightPackageInfo lightPackageInfo) {
+ return SdkLevel.isAtLeastS() && lightPackageInfo.getAreAttributionsUserVisible();
+ }
+
/**
- * Returns the attribution label map for the package if the app supports subattribtion; Returns
+ * Returns the attribution label map for the package if the app supports subattribution; Returns
* {@code null} otherwise.
*/
@Nullable
- @SuppressLint("NewApi") // isSubattributionSupported checks api level
- public static Map<Integer, String> getAttributionLabels(Context context,
- PackageInfo pkgInfo) {
+ public static Map<Integer, String> getAttributionLabels(Context context, PackageInfo pkgInfo) {
if (!isSubattributionSupported(context, pkgInfo.applicationInfo)) {
return null;
}
@@ -63,11 +69,10 @@ public class SubattributionUtils {
}
/**
- * Returns the attribution label map for the package if the app supports subattribtion; Returns
+ * Returns the attribution label map for the package if the app supports subattribtuion; Returns
* {@code null} otherwise.
*/
@Nullable
- @SuppressLint("NewApi") // isSubattributionSupported checks api level
public static Map<Integer, String> getAttributionLabels(Context context,
ApplicationInfo appInfo) {
if (!isSubattributionSupported(context, appInfo)) {
@@ -106,4 +111,33 @@ public class SubattributionUtils {
}
return attributionLabels;
}
+
+ /** Returns the attribution label map for the package if the app supports subattribution. */
+ @Nullable
+ public static Map<Integer, String> getAttributionLabels(Context context,
+ LightPackageInfo lightPackageInfo) {
+ if (!isSubattributionSupported(lightPackageInfo)) {
+ return null;
+ }
+
+ Context pkgContext;
+ try {
+ pkgContext = context.createPackageContext(lightPackageInfo.getPackageName(), 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
+ }
+
+ Map<Integer, String> attributionLabels = new HashMap<>();
+ for (Map.Entry<String, Integer> attribution :
+ lightPackageInfo.getAttributionTagsToLabels().entrySet()) {
+ int label = attribution.getValue();
+ try {
+ String resourceForLabel = pkgContext.getString(attribution.getValue());
+ attributionLabels.put(label, resourceForLabel);
+ } catch (Resources.NotFoundException e) {
+ // should never happen
+ }
+ }
+ return attributionLabels;
+ }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/v34/SafetyLabelUtils.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/v34/SafetyLabelUtils.kt
new file mode 100644
index 000000000..5dbe203f9
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/v34/SafetyLabelUtils.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.utils.v34
+
+import com.android.permission.safetylabel.DataCategory
+import com.android.permission.safetylabel.DataType
+import com.android.permission.safetylabel.DataTypeConstants
+import com.android.permission.safetylabel.SafetyLabel
+import com.android.permissioncontroller.permission.utils.PermissionMapping
+
+object SafetyLabelUtils {
+ /*
+ * Get the sharing purposes for a SafetyLabel related to a specific permission group.
+ */
+ @JvmStatic
+ fun getSafetyLabelSharingPurposesForGroup(
+ safetyLabel: SafetyLabel,
+ groupName: String
+ ): Set<Int> {
+ val purposeSet = mutableSetOf<Int>()
+ val categoriesForPermission = PermissionMapping
+ .getDataCategoriesForPermissionGroup(groupName)
+ categoriesForPermission.forEach categoryLoop@{ category ->
+ val dataCategory: DataCategory? = safetyLabel.dataLabel.dataShared[category]
+ if (dataCategory == null) {
+ // Continue to next
+ return@categoryLoop
+ }
+ val typesForCategory = DataTypeConstants.getValidDataTypesForCategory(category)
+ typesForCategory.forEach typeLoop@{ type ->
+ val dataType: DataType? = dataCategory.dataTypes[type]
+ if (dataType == null) {
+ // Continue to next
+ return@typeLoop
+ }
+ if (dataType.purposeSet.isNotEmpty()) {
+ purposeSet.addAll(dataType.purposeSet)
+ }
+ }
+ }
+
+ return purposeSet
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySettingsUtil.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySettingsUtil.kt
new file mode 100644
index 000000000..59dbf635d
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySettingsUtil.kt
@@ -0,0 +1,92 @@
+/*
+ * 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.permissioncontroller.privacysources
+
+import android.content.ComponentName
+import android.content.Context
+import android.provider.Settings
+import android.text.TextUtils
+import android.util.Log
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+
+/**
+ * Code reference from https://source.corp.google.com/android/frameworks/base/packages/SettingsLib/
+ * src/com/android/settingslib/accessibility/AccessibilityUtils.java
+ */
+object AccessibilitySettingsUtil {
+ private const val ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR = ':'
+ private val LOG_TAG = AccessibilitySettingsUtil::class.java.simpleName
+ private val lock = Mutex()
+
+ /**
+ * 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)
+ ) {
+ 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())
+
+ Settings.Secure.putString(
+ context.contentResolver,
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ updatedEnabledServices
+ )
+ }
+ }
+
+ /**
+ * @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 enabledServices = mutableSetOf<ComponentName>()
+ if (TextUtils.isEmpty(enabledServicesSetting)) {
+ return enabledServices
+ }
+
+ val colonSplitter: TextUtils.StringSplitter = TextUtils.SimpleStringSplitter(
+ ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR
+ )
+ colonSplitter.setString(enabledServicesSetting)
+
+ for (componentNameString in colonSplitter) {
+ val enabledService = ComponentName.unflattenFromString(
+ componentNameString
+ )
+ if (enabledService != null) {
+ enabledServices.add(enabledService)
+ } else {
+ Log.e(LOG_TAG, "unable to parse accessibility service $componentNameString")
+ }
+ }
+
+ return enabledServices
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySourceService.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySourceService.kt
new file mode 100644
index 000000000..1d5c9c9fa
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySourceService.kt
@@ -0,0 +1,986 @@
+/*
+ * 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.permissioncontroller.privacysources
+
+import android.accessibilityservice.AccessibilityServiceInfo
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.app.job.JobInfo
+import android.app.job.JobParameters
+import android.app.job.JobScheduler
+import android.app.job.JobService
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.SharedPreferences
+import android.os.Build
+import android.os.Bundle
+import android.provider.DeviceConfig
+import android.provider.Settings
+import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetyEvent
+import android.safetycenter.SafetySourceData
+import android.safetycenter.SafetySourceIssue
+import android.service.notification.StatusBarNotification
+import android.util.Log
+import android.view.accessibility.AccessibilityManager
+import androidx.annotation.ChecksSdkIntAtLeast
+import androidx.annotation.GuardedBy
+import androidx.annotation.RequiresApi
+import androidx.annotation.VisibleForTesting
+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.PermissionControllerStatsLog
+import com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION
+import com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__ACTION__CARD_DISMISSED
+import com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__ACTION__CLICKED_CTA1
+import com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__PRIVACY_SOURCE__A11Y_SERVICE
+import com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_NOTIFICATION_INTERACTION
+import com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__ACTION__DISMISSED
+import com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__ACTION__NOTIFICATION_SHOWN
+import com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__PRIVACY_SOURCE__A11Y_SERVICE
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.utils.KotlinUtils
+import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.permission.utils.Utils.getSystemServiceSafe
+import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent
+import java.util.Random
+import java.util.concurrent.TimeUnit
+import java.util.function.BooleanSupplier
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+
+@VisibleForTesting
+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"
+private const val DEBUG = false
+
+@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
+private fun isAccessibilitySourceSupported(): Boolean {
+ return SdkLevel.isAtLeastT()
+}
+
+fun isAccessibilitySourceEnabled(): Boolean {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_SC_ACCESSIBILITY_SOURCE_ENABLED,
+ true
+ )
+}
+
+/**
+ * cts test needs to disable the listener.
+ */
+fun isAccessibilityListenerEnabled(): Boolean {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_SC_ACCESSIBILITY_LISTENER_ENABLED,
+ true
+ )
+}
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+private fun isSafetyCenterEnabled(context: Context): Boolean {
+ return getSystemServiceSafe(context, SafetyCenterManager::class.java)
+ .isSafetyCenterEnabled
+}
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+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)
+
+ @WorkerThread
+ internal suspend fun processAccessibilityJob(
+ params: JobParameters?,
+ jobService: AccessibilityJobService,
+ cancel: BooleanSupplier?
+ ) {
+ lock.withLock {
+ try {
+ var sessionId = Constants.INVALID_SESSION_ID
+ while (sessionId == Constants.INVALID_SESSION_ID) {
+ sessionId = random.nextLong()
+ }
+ if (DEBUG) {
+ Log.v(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.")
+ }
+ jobService.jobFinished(params, false)
+ jobService.clearJob()
+ return
+ }
+
+ val lastShownNotification =
+ sharedPrefs.getLong(KEY_LAST_ACCESSIBILITY_NOTIFICATION_SHOWN, 0)
+ val showNotification = ((System.currentTimeMillis() - lastShownNotification) >
+ getNotificationsIntervalMillis()) && getCurrentNotification() == null
+
+ if (showNotification) {
+ val alreadyNotifiedServices = getNotifiedServices()
+
+ val toBeNotifiedServices = a11yServiceList.filter {
+ !alreadyNotifiedServices.contains(it.id)
+ }
+
+ if (toBeNotifiedServices.isNotEmpty()) {
+ if (DEBUG) {
+ Log.v(LOG_TAG, "sending an accessibility service notification")
+ }
+ val serviceToBeNotified: AccessibilityServiceInfo =
+ toBeNotifiedServices[random.nextInt(toBeNotifiedServices.size)]
+ createPermissionReminderChannel()
+ interruptJobIfCanceled(cancel)
+ sendNotification(serviceToBeNotified, sessionId)
+ }
+ }
+
+ interruptJobIfCanceled(cancel)
+ sendIssuesToSafetyCenter(a11yServiceList, sessionId)
+ jobService.jobFinished(params, false)
+ } catch (ex: InterruptedException) {
+ Log.w(LOG_TAG, "cancel request for safety center accessibility job received.")
+ jobService.jobFinished(params, true)
+ } catch (ex: Exception) {
+ Log.w(LOG_TAG, "could not process safety center accessibility job", ex)
+ jobService.jobFinished(params, false)
+ } finally {
+ jobService.clearJob()
+ }
+ }
+ }
+
+ /**
+ * sends a notification for a given accessibility package
+ */
+ private suspend fun sendNotification(
+ serviceToBeNotified: AccessibilityServiceInfo,
+ sessionId: Long
+ ) {
+ val pkgLabel = serviceToBeNotified.resolveInfo.loadLabel(packageManager)
+ val componentName = ComponentName.unflattenFromString(serviceToBeNotified.id)!!
+ val uid = serviceToBeNotified.resolveInfo.serviceInfo.applicationInfo.uid
+
+ val notificationDeleteIntent =
+ Intent(parentUserContext, AccessibilityNotificationDeleteHandler::class.java).apply {
+ putExtra(Intent.EXTRA_COMPONENT_NAME, componentName)
+ putExtra(Constants.EXTRA_SESSION_ID, sessionId)
+ putExtra(Intent.EXTRA_UID, uid)
+ flags = Intent.FLAG_RECEIVER_FOREGROUND
+ 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 (appLabel, smallIcon, color) =
+ KotlinUtils.getSafetyCenterNotificationResources(parentUserContext)
+ val b: Notification.Builder =
+ Notification.Builder(parentUserContext, Constants.PERMISSION_REMINDER_CHANNEL_ID)
+ .setLocalOnly(true)
+ .setContentTitle(title)
+ .setContentText(summary)
+ // Ensure entire text can be displayed, instead of being truncated to one line
+ .setStyle(Notification.BigTextStyle().bigText(summary))
+ .setSmallIcon(smallIcon)
+ .setColor(color)
+ .setAutoCancel(true)
+ .setDeleteIntent(
+ PendingIntent.getBroadcast(
+ parentUserContext, 0, notificationDeleteIntent,
+ PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_UPDATE_CURRENT or
+ PendingIntent.FLAG_IMMUTABLE
+ )
+ )
+ .setContentIntent(getSafetyCenterActivityIntent(context, uid, sessionId))
+
+ val appNameExtras = Bundle()
+ appNameExtras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, appLabel)
+ b.addExtras(appNameExtras)
+
+ notificationsManager.notify(
+ componentName.flattenToShortString(),
+ Constants.ACCESSIBILITY_CHECK_NOTIFICATION_ID,
+ b.build()
+ )
+
+ sharedPrefsLock.withLock {
+ 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")
+ }
+ PermissionControllerStatsLog.write(
+ PRIVACY_SIGNAL_NOTIFICATION_INTERACTION,
+ PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__PRIVACY_SOURCE__A11Y_SERVICE,
+ uid,
+ PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__ACTION__NOTIFICATION_SHOWN,
+ sessionId
+ )
+ }
+
+ /** 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
+ )
+ notificationsManager.createNotificationChannel(permissionReminderChannel)
+ }
+
+ /**
+ * @param a11yService enabled 3rd party accessibility service
+ * @return safety source issue, shown as the warning card in safety center
+ */
+ private fun createSafetySourceIssue(
+ a11yService: AccessibilityServiceInfo,
+ sessionId: Long
+ ): SafetySourceIssue {
+ val componentName = ComponentName.unflattenFromString(a11yService.id)!!
+ val safetySourceIssueId = "accessibility_${componentName.flattenToString()}"
+ val pkgLabel = a11yService.resolveInfo.loadLabel(packageManager).toString()
+ val uid = a11yService.resolveInfo.serviceInfo.applicationInfo.uid
+
+ 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 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 warningCardDismissIntent =
+ Intent(parentUserContext, AccessibilityWarningCardDismissalReceiver::class.java).apply {
+ flags = Intent.FLAG_RECEIVER_FOREGROUND
+ identifier = componentName.flattenToString()
+ putExtra(Intent.EXTRA_COMPONENT_NAME, componentName)
+ putExtra(Constants.EXTRA_SESSION_ID, sessionId)
+ 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)
+
+ return SafetySourceIssue.Builder(
+ safetySourceIssueId,
+ title,
+ summary,
+ SafetySourceData.SEVERITY_LEVEL_INFORMATION,
+ SC_ACCESSIBILITY_ISSUE_TYPE_ID
+ )
+ .addAction(removeAccessAction)
+ .addAction(accessibilityActivityAction)
+ .setSubtitle(pkgLabel)
+ .setOnDismissPendingIntent(warningCardDismissPendingIntent)
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
+ .build()
+ }
+
+ /**
+ * @return pending intent for remove access button on the warning card.
+ */
+ private fun getRemoveAccessPendingIntent(
+ context: Context,
+ serviceComponentName: ComponentName,
+ safetySourceIssueId: String,
+ uid: Int,
+ sessionId: Long
+ ): PendingIntent {
+ val intent =
+ Intent(parentUserContext, AccessibilityRemoveAccessHandler::class.java).apply {
+ putExtra(Intent.EXTRA_COMPONENT_NAME, serviceComponentName)
+ putExtra(SafetyCenterManager.EXTRA_SAFETY_SOURCE_ISSUE_ID, safetySourceIssueId)
+ putExtra(Constants.EXTRA_SESSION_ID, sessionId)
+ putExtra(Intent.EXTRA_UID, uid)
+ flags = Intent.FLAG_RECEIVER_FOREGROUND
+ identifier = serviceComponentName.flattenToString()
+ }
+
+ return PendingIntent.getBroadcast(
+ context,
+ 0,
+ intent,
+ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
+ )
+ }
+
+ /**
+ * @return pending intent for redirecting user to the accessibility page
+ */
+ private fun getAccessibilityActivityPendingIntent(
+ context: Context,
+ uid: Int,
+ sessionId: Long
+ ): PendingIntent {
+ val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
+ intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ intent.putExtra(Constants.EXTRA_SESSION_ID, sessionId)
+ intent.putExtra(Intent.EXTRA_UID, uid)
+
+ // Start this Settings activity using the same UX that settings slices uses. This allows
+ // settings to correctly support 2-pane layout with as-best-as-possible transition
+ // animation.
+ intent.putExtra(Constants.EXTRA_IS_FROM_SLICE, true)
+ return PendingIntent.getActivity(
+ context,
+ 0,
+ intent,
+ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
+ )
+ }
+
+ /**
+ * @return pending intent to redirect the user to safety center on notification click
+ */
+ private fun getSafetyCenterActivityIntent(
+ context: Context,
+ uid: Int,
+ sessionId: Long
+ ): 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(
+ Constants.EXTRA_PRIVACY_SOURCE,
+ PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__PRIVACY_SOURCE__A11Y_SERVICE
+ )
+ return PendingIntent.getActivity(
+ context,
+ 0,
+ intent,
+ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
+ )
+ }
+
+ private fun sendIssuesToSafetyCenter(
+ a11yServiceList: List<AccessibilityServiceInfo>,
+ sessionId: Long,
+ safetyEvent: SafetyEvent = sourceStateChanged
+ ) {
+ val pendingIssues = a11yServiceList.map { createSafetySourceIssue(it, sessionId) }
+ 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")
+ }
+ safetyCenterManager.setSafetySourceData(
+ SC_ACCESSIBILITY_SOURCE_ID,
+ safetySourceData,
+ safetyEvent
+ )
+ }
+
+ fun sendIssuesToSafetyCenter(
+ a11yServiceList: List<AccessibilityServiceInfo>,
+ safetyEvent: SafetyEvent = sourceStateChanged
+ ) {
+ var sessionId = Constants.INVALID_SESSION_ID
+ while (sessionId == Constants.INVALID_SESSION_ID) {
+ sessionId = random.nextLong()
+ }
+ sendIssuesToSafetyCenter(a11yServiceList, sessionId, safetyEvent)
+ }
+
+ private fun sendIssuesToSafetyCenter(safetyEvent: SafetyEvent = sourceStateChanged) {
+ val enabledServices = getEnabledAccessibilityServices()
+ sendIssuesToSafetyCenter(enabledServices, safetyEvent)
+ }
+
+ /**
+ * If [.cancel] throw an [InterruptedException].
+ */
+ @Throws(InterruptedException::class)
+ private fun interruptJobIfCanceled(cancel: BooleanSupplier?) {
+ if (cancel != null && cancel.asBoolean) {
+ throw InterruptedException()
+ }
+ }
+
+ private val accessibilityManager = getSystemServiceSafe(parentUserContext,
+ AccessibilityManager::class.java)
+
+ /**
+ * @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 {
+ if (installedServices[it] == null) {
+ Log.e(LOG_TAG, "enabled accessibility service ($it) not found in installed" +
+ "services: ${installedServices.keys}")
+ }
+ installedServices[it]
+ }
+
+ return enabledServices.filterNotNull()
+ .filter { !it.isAccessibilityTool }
+ }
+
+ /**
+ * Get currently shown accessibility notification.
+ *
+ * @return The notification or `null` if no notification is currently shown
+ */
+ private fun getCurrentNotification(): StatusBarNotification? {
+ val notifications = notificationsManager.activeNotifications
+ return notifications.firstOrNull { it.id == Constants.ACCESSIBILITY_CHECK_NOTIFICATION_ID }
+ }
+
+ internal suspend fun removeFromNotifiedServices(a11Service: ComponentName) {
+ sharedPrefsLock.withLock {
+ val notifiedServices = getNotifiedServices()
+ val filteredServices = notifiedServices.filter {
+ it != a11Service.flattenToShortString()
+ }.toSet()
+
+ if (filteredServices.size < notifiedServices.size) {
+ sharedPrefs.edit().putStringSet(KEY_ALREADY_NOTIFIED_SERVICES, filteredServices)
+ .apply()
+ }
+ }
+ }
+
+ internal suspend fun markServiceAsNotified(a11Service: ComponentName) {
+ sharedPrefsLock.withLock {
+ val alreadyNotifiedServices = getNotifiedServices()
+ alreadyNotifiedServices.add(a11Service.flattenToShortString())
+ sharedPrefs.edit().putStringSet(KEY_ALREADY_NOTIFIED_SERVICES, alreadyNotifiedServices)
+ .apply()
+ }
+ }
+
+ internal suspend fun updateServiceAsNotified(enabledA11yServices: Set<String>) {
+ sharedPrefsLock.withLock {
+ val alreadyNotifiedServices = getNotifiedServices()
+ val services = alreadyNotifiedServices.filter { enabledA11yServices.contains(it) }
+ if (services.size < alreadyNotifiedServices.size) {
+ sharedPrefs.edit().putStringSet(KEY_ALREADY_NOTIFIED_SERVICES, services.toSet())
+ .apply()
+ }
+ }
+ }
+
+ private fun getNotifiedServices(): MutableSet<String> {
+ return sharedPrefs.getStringSet(KEY_ALREADY_NOTIFIED_SERVICES, mutableSetOf<String>())!!
+ }
+
+ @VisibleForTesting
+ internal fun getSharedPreference(): SharedPreferences {
+ return sharedPrefs
+ }
+
+ /**
+ * 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.
+ */
+ fun removeAccessibilityNotification(a11yEnabledComponents: Set<String>) {
+ val notification = getCurrentNotification() ?: return
+ if (a11yEnabledComponents.contains(notification.tag)) {
+ return
+ }
+ cancelNotification(notification.tag)
+ }
+
+ /**
+ * Remove notification when a package is uninstalled.
+ */
+ private fun removeAccessibilityNotification(pkg: String) {
+ val notification = getCurrentNotification() ?: return
+ val component = ComponentName.unflattenFromString(notification.tag)
+ if (component == null || component.packageName != pkg) {
+ return
+ }
+ cancelNotification(notification.tag)
+ }
+
+ /**
+ * Remove notification for a component, when warning card is dismissed.
+ */
+ fun removeAccessibilityNotification(component: ComponentName) {
+ val notification = getCurrentNotification() ?: return
+ if (component.flattenToShortString() == notification.tag) {
+ cancelNotification(notification.tag)
+ }
+ }
+
+ private fun cancelNotification(notificationTag: String) {
+ getSystemServiceSafe(parentUserContext, NotificationManager::class.java)
+ .cancel(notificationTag, Constants.ACCESSIBILITY_CHECK_NOTIFICATION_ID)
+ }
+
+ internal 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()
+ if (filteredServices.size < notifiedServices.size) {
+ sharedPrefs.edit().putStringSet(
+ KEY_ALREADY_NOTIFIED_SERVICES,
+ filteredServices
+ ).apply()
+ }
+ }
+ }
+
+ companion object {
+ private val LOG_TAG = AccessibilitySourceService::class.java.simpleName
+ private const val SC_ACCESSIBILITY_ISSUE_TYPE_ID = "accessibility_privacy_issue"
+ private const val KEY_LAST_ACCESSIBILITY_NOTIFICATION_SHOWN =
+ "last_accessibility_notification_shown"
+ const val KEY_ALREADY_NOTIFIED_SERVICES = "already_notified_a11y_services"
+ private const val ACCESSIBILITY_PREFERENCES_FILE = "a11y_preferences"
+ private const val SC_ACCESSIBILITY_SHOW_ACCESSIBILITY_ACTIVITY_ACTION_ID =
+ "show_accessibility_apps"
+ private const val PROPERTY_SC_ACCESSIBILITY_JOB_INTERVAL_MILLIS =
+ "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()
+
+ /** lock for processing a job */
+ internal val lock = Mutex()
+
+ /** lock for shared preferences writes */
+ private val sharedPrefsLock = Mutex()
+
+ /**
+ * Get time in between two periodic checks.
+ *
+ * Default: 1 day
+ *
+ * @return The time in between check in milliseconds
+ */
+ fun getJobsIntervalMillis(): Long {
+ return DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_SC_ACCESSIBILITY_JOB_INTERVAL_MILLIS,
+ DEFAULT_SC_ACCESSIBILITY_JOB_INTERVAL_MILLIS
+ )
+ }
+
+ /**
+ * Flexibility of the periodic check.
+ *
+ *
+ * 10% of [.getPeriodicCheckIntervalMillis]
+ *
+ * @return The flexibility of the periodic check in milliseconds
+ */
+ fun getFlexJobsIntervalMillis(): Long {
+ return getJobsIntervalMillis() / 10
+ }
+
+ /**
+ * 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
+ */
+ private fun getNotificationsIntervalMillis(): Long {
+ return getJobsIntervalMillis() - (getFlexJobsIntervalMillis() * 2.1).toLong()
+ }
+ }
+
+ override val shouldProcessProfileRequest: Boolean = false
+
+ override fun safetyCenterEnabledChanged(context: Context, enabled: Boolean) {
+ if (!enabled) { // safety center disabled event
+ removeAccessibilityNotification()
+ }
+ }
+
+ override fun rescanAndPushSafetyCenterData(
+ context: Context,
+ intent: Intent,
+ refreshEvent: RefreshEvent
+ ) {
+ if (DEBUG) {
+ Log.v(LOG_TAG, "rescan and push event from safety center $refreshEvent")
+ }
+ val safetyCenterEvent = getSafetyCenterEvent(refreshEvent, intent)
+ sendIssuesToSafetyCenter(safetyCenterEvent)
+ }
+}
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class AccessibilityPackageResetHandler : BroadcastReceiver() {
+ private val LOG_TAG = AccessibilityPackageResetHandler::class.java.simpleName
+
+ override fun onReceive(context: Context, intent: Intent) {
+ val action = intent.action
+ if (action != Intent.ACTION_PACKAGE_DATA_CLEARED &&
+ action != Intent.ACTION_PACKAGE_FULLY_REMOVED
+ ) {
+ return
+ }
+
+ if (!isAccessibilitySourceSupported() || isProfile(context)) {
+ return
+ }
+
+ val data = Preconditions.checkNotNull(intent.data)
+ 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)
+ }
+ }
+ }
+}
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class AccessibilityNotificationDeleteHandler : BroadcastReceiver() {
+ private val LOG_TAG = AccessibilityNotificationDeleteHandler::class.java.simpleName
+ override fun onReceive(context: Context, intent: Intent) {
+ val sessionId =
+ intent.getLongExtra(Constants.EXTRA_SESSION_ID, Constants.INVALID_SESSION_ID)
+ val uid = intent.getIntExtra(Intent.EXTRA_UID, -1)
+ val coroutineScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
+ coroutineScope.launch(Dispatchers.Default) {
+ if (DEBUG) {
+ Log.v(LOG_TAG, "NOTIF_INTERACTION DISMISSED metric, uid $uid session $sessionId")
+ }
+ PermissionControllerStatsLog.write(
+ PRIVACY_SIGNAL_NOTIFICATION_INTERACTION,
+ PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__PRIVACY_SOURCE__A11Y_SERVICE,
+ uid,
+ PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__ACTION__DISMISSED,
+ sessionId
+ )
+ }
+ }
+}
+
+/**
+ * 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
+
+ override fun onReceive(context: Context, intent: Intent) {
+ val a11yService: ComponentName =
+ Utils.getParcelableExtraSafe<ComponentName>(intent, Intent.EXTRA_COMPONENT_NAME)
+ val sessionId =
+ intent.getLongExtra(Constants.EXTRA_SESSION_ID, Constants.INVALID_SESSION_ID)
+ val uid = intent.getIntExtra(Intent.EXTRA_UID, -1)
+ val coroutineScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
+ coroutineScope.launch(Dispatchers.Default) {
+ if (DEBUG) {
+ Log.v(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()
+ }
+ 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()
+ accessibilityService.sendIssuesToSafetyCenter(a11yEnabledServices, safetyEvent)
+ }
+ if (DEBUG) {
+ Log.v(LOG_TAG, "ISSUE_CARD_INTERACTION CTA1 metric, uid $uid session $sessionId")
+ }
+ PermissionControllerStatsLog.write(
+ PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION,
+ PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__PRIVACY_SOURCE__A11Y_SERVICE,
+ uid,
+ PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__ACTION__CLICKED_CTA1,
+ sessionId
+ )
+ }
+ }
+}
+
+/**
+ * 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
+
+ override fun onReceive(context: Context, intent: Intent) {
+ val componentName =
+ Utils.getParcelableExtraSafe<ComponentName>(intent, Intent.EXTRA_COMPONENT_NAME)
+ val sessionId =
+ intent.getLongExtra(Constants.EXTRA_SESSION_ID, Constants.INVALID_SESSION_ID)
+ val uid = intent.getIntExtra(Intent.EXTRA_UID, -1)
+ val coroutineScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
+ coroutineScope.launch(Dispatchers.Default) {
+ if (DEBUG) {
+ Log.v(LOG_TAG, "removing notification for ${componentName.flattenToShortString()}")
+ }
+ val accessibilityService = AccessibilitySourceService(context)
+ accessibilityService.removeAccessibilityNotification(componentName)
+ accessibilityService.markServiceAsNotified(componentName)
+ }
+
+ if (DEBUG) {
+ Log.v(LOG_TAG, "ISSUE_CARD_INTERACTION DISMISSED metric, uid $uid session $sessionId")
+ }
+ PermissionControllerStatsLog.write(
+ PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION,
+ PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__PRIVACY_SOURCE__A11Y_SERVICE,
+ uid,
+ PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__ACTION__CARD_DISMISSED,
+ sessionId
+ )
+ }
+}
+
+/**
+ * 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() {
+ private val LOG_TAG = AccessibilityOnBootReceiver::class.java.simpleName
+
+ 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")
+ return
+ }
+ if (DEBUG) {
+ Log.v(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 status = jobScheduler.schedule(jobInfo)
+ if (status != JobScheduler.RESULT_SUCCESS) {
+ Log.w(LOG_TAG, "Could not schedule AccessibilityJobService: $status")
+ }
+ }
+ }
+}
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class AccessibilityJobService : JobService() {
+ private val LOG_TAG = AccessibilityJobService::class.java.simpleName
+
+ private var mSourceService: AccessibilitySourceService? = null
+ private val mLock = Object()
+
+ @GuardedBy("mLock")
+ private var mCurrentJob: Job? = null
+
+ override fun onCreate() {
+ super.onCreate()
+ Log.v(LOG_TAG, "accessibility privacy source job created.")
+ mSourceService = AccessibilitySourceService(this)
+ }
+
+ override fun onStartJob(params: JobParameters?): Boolean {
+ Log.v(LOG_TAG, "accessibility privacy source job started.")
+ synchronized(mLock) {
+ if (mCurrentJob != null) {
+ Log.v(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")
+ 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)
+ }
+ }
+ return true
+ }
+
+ override fun onStopJob(params: JobParameters?): Boolean {
+ var job: Job?
+ synchronized(mLock) {
+ job = if (mCurrentJob == null) {
+ return false
+ } else {
+ mCurrentJob
+ }
+ }
+ job?.cancel()
+ return false
+ }
+
+ fun clearJob() {
+ synchronized(mLock) {
+ mCurrentJob = null
+ }
+ }
+}
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class SafetyCenterAccessibilityListener(val context: Context) :
+ AccessibilityManager.AccessibilityServicesStateChangeListener {
+
+ private val LOG_TAG = SafetyCenterAccessibilityListener::class.java.simpleName
+
+ override fun onAccessibilityServicesStateChanged(manager: AccessibilityManager) {
+ if (!isAccessibilityListenerEnabled()) {
+ Log.v(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.")
+ return
+ }
+
+ val coroutineScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
+ coroutineScope.launch(Dispatchers.Default) {
+ if (DEBUG) {
+ Log.v(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()
+ 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
new file mode 100644
index 000000000..0660955ff
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/AutoRevokePrivacySource.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.permissioncontroller.privacysources
+
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import androidx.annotation.RequiresApi
+import com.android.permissioncontroller.Constants
+import com.android.permissioncontroller.hibernation.cancelUnusedAppsNotification
+import com.android.permissioncontroller.hibernation.rescanAndPushDataToSafetyCenter
+import java.util.Random
+
+/**
+ * Privacy source for auto-revoked permissions.
+ */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class AutoRevokePrivacySource : PrivacySource {
+ override val shouldProcessProfileRequest: Boolean = false
+
+ override fun safetyCenterEnabledChanged(context: Context, enabled: Boolean) {
+ cancelUnusedAppsNotification(context)
+ }
+
+ override fun rescanAndPushSafetyCenterData(
+ context: Context,
+ intent: Intent,
+ refreshEvent: SafetyCenterReceiver.RefreshEvent
+ ) {
+ var sessionId = Constants.INVALID_SESSION_ID
+ while (sessionId == Constants.INVALID_SESSION_ID) {
+ sessionId = Random().nextLong()
+ }
+
+ val safetyRefreshEvent = getSafetyCenterEvent(refreshEvent, intent)
+ rescanAndPushDataToSafetyCenter(context, sessionId, safetyRefreshEvent)
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/LocationAccessPrivacySource.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/LocationAccessPrivacySource.kt
new file mode 100644
index 000000000..df35048e5
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/LocationAccessPrivacySource.kt
@@ -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 com.android.permissioncontroller.privacysources
+
+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
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class LocationAccessPrivacySource : PrivacySource {
+ override val shouldProcessProfileRequest: Boolean = false
+
+ override fun safetyCenterEnabledChanged(context: Context, enabled: Boolean) {
+ LocationAccessCheck(context, null).cancelBackgroundAccessWarningNotification()
+ }
+
+ override fun rescanAndPushSafetyCenterData(
+ context: Context,
+ intent: Intent,
+ refreshEvent: RefreshEvent
+ ) {
+ 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
new file mode 100644
index 000000000..91a043a6a
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/NotificationListenerCheck.kt
@@ -0,0 +1,1125 @@
+/*
+ * 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.permissioncontroller.privacysources
+
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.app.PendingIntent.FLAG_IMMUTABLE
+import android.app.PendingIntent.FLAG_ONE_SHOT
+import android.app.PendingIntent.FLAG_UPDATE_CURRENT
+import android.app.job.JobInfo
+import android.app.job.JobParameters
+import android.app.job.JobScheduler
+import android.app.job.JobService
+import android.app.role.RoleManager
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.Context.MODE_PRIVATE
+import android.content.Intent
+import android.content.Intent.EXTRA_COMPONENT_NAME
+import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
+import android.content.Intent.FLAG_RECEIVER_FOREGROUND
+import android.content.SharedPreferences
+import android.content.pm.PackageInfo
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Bundle
+import android.provider.DeviceConfig
+import android.provider.Settings.ACTION_NOTIFICATION_LISTENER_DETAIL_SETTINGS
+import android.provider.Settings.EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME
+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
+import android.service.notification.StatusBarNotification
+import android.util.Log
+import androidx.annotation.ChecksSdkIntAtLeast
+import androidx.annotation.GuardedBy
+import androidx.annotation.RequiresApi
+import androidx.annotation.VisibleForTesting
+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.Constants.KEY_LAST_NOTIFICATION_LISTENER_NOTIFICATION_SHOWN
+import com.android.permissioncontroller.Constants.NOTIFICATION_LISTENER_CHECK_NOTIFICATION_ID
+import com.android.permissioncontroller.Constants.PERIODIC_NOTIFICATION_LISTENER_CHECK_JOB_ID
+import com.android.permissioncontroller.PermissionControllerStatsLog
+import com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION
+import com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__ACTION__CARD_DISMISSED
+import com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__ACTION__CLICKED_CTA1
+import com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__PRIVACY_SOURCE__NOTIFICATION_LISTENER
+import com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_NOTIFICATION_INTERACTION
+import com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__ACTION__DISMISSED
+import com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__ACTION__NOTIFICATION_SHOWN
+import com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__PRIVACY_SOURCE__NOTIFICATION_LISTENER
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.utils.KotlinUtils
+import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.permission.utils.Utils.getSystemServiceSafe
+import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent
+import java.lang.System.currentTimeMillis
+import java.util.Random
+import java.util.concurrent.TimeUnit.DAYS
+import java.util.function.BooleanSupplier
+import kotlinx.coroutines.Dispatchers.Default
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+
+private val TAG = "NotificationListenerCheck"
+private const val DEBUG = false
+const val SC_NLS_SOURCE_ID = "AndroidNotificationListener"
+@VisibleForTesting const val SC_NLS_DISABLE_ACTION_ID = "disable_nls_component"
+
+/** Device config property for whether notification listener check is enabled on the device */
+@VisibleForTesting
+const val 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
+ */
+private const val PROPERTY_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS =
+ "notification_listener_check_interval_millis"
+
+private val DEFAULT_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS = DAYS.toMillis(1)
+
+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)
+}
+
+/**
+ * Get time in between two periodic checks.
+ *
+ * Default: 1 day
+ *
+ * @return The time in between check in milliseconds
+ */
+private fun getPeriodicCheckIntervalMillis(): Long {
+ return DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS,
+ DEFAULT_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS)
+}
+
+/**
+ * Flexibility of the periodic check.
+ *
+ * 10% of [.getPeriodicCheckIntervalMillis]
+ *
+ * @return The flexibility of the periodic check in milliseconds
+ */
+private fun getFlexForPeriodicCheckMillis(): Long {
+ return getPeriodicCheckIntervalMillis() / 10
+}
+
+/**
+ * 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
+ */
+private fun getInBetweenNotificationsMillis(): Long {
+ return getPeriodicCheckIntervalMillis() - (getFlexForPeriodicCheckMillis() * 2.1).toLong()
+}
+
+/** Notification Listener Check requires Android T or later */
+@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
+private fun checkNotificationListenerCheckSupported(): Boolean {
+ return SdkLevel.isAtLeastT()
+}
+
+/**
+ * Returns {@code true} when Notification listener check is supported, feature flag enabled and
+ * Safety Center enabled
+ */
+@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
+private fun checkNotificationListenerCheckEnabled(context: Context): Boolean {
+ return checkNotificationListenerCheckSupported() &&
+ isNotificationListenerCheckFlagEnabled() &&
+ getSystemServiceSafe(context, SafetyCenterManager::class.java).isSafetyCenterEnabled
+}
+
+private fun getSafetySourceIssueIdFromComponentName(componentName: ComponentName): String {
+ return "notification_listener_${componentName.flattenToString()}"
+}
+
+/**
+ * Show notification that double-guesses the user if they really wants to grant notification
+ * listener permission to an app.
+ *
+ * <p>A notification is scheduled periodically, or on demand
+ *
+ * <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.
+ *
+ * @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(
+ context: Context,
+ private val shouldCancel: BooleanSupplier?
+) {
+ private val parentUserContext = Utils.getParentUserContext(context)
+ private val random = Random()
+ private val sharedPrefs: SharedPreferences =
+ parentUserContext.getSharedPreferences(NLS_PREFERENCE_FILE, MODE_PRIVATE)
+
+ // Don't initialize until used. Delegate used for testing
+ @VisibleForTesting
+ val exemptPackagesDelegate = lazy {
+ getExemptedPackages(
+ getSystemServiceSafe(parentUserContext, RoleManager::class.java), parentUserContext)
+ }
+ @VisibleForTesting
+ val exemptPackages: Set<String> by exemptPackagesDelegate
+
+ companion object {
+ @VisibleForTesting const val NLS_PREFERENCE_FILE = "nls_preference"
+ private const val KEY_ALREADY_NOTIFIED_COMPONENTS = "already_notified_services"
+
+ @VisibleForTesting const val SC_NLS_ISSUE_TYPE_ID = "notification_listener_privacy_issue"
+ @VisibleForTesting
+ const val SC_SHOW_NLS_SETTINGS_ACTION_ID = "show_notification_listener_settings"
+
+ private const val SYSTEM_PKG = "android"
+
+ private const val SYSTEM_AMBIENT_AUDIO_INTELLIGENCE =
+ "android.app.role.SYSTEM_AMBIENT_AUDIO_INTELLIGENCE"
+ private const val SYSTEM_UI_INTELLIGENCE = "android.app.role.SYSTEM_UI_INTELLIGENCE"
+ private const val SYSTEM_AUDIO_INTELLIGENCE = "android.app.role.SYSTEM_AUDIO_INTELLIGENCE"
+ private const val SYSTEM_NOTIFICATION_INTELLIGENCE =
+ "android.app.role.SYSTEM_NOTIFICATION_INTELLIGENCE"
+ private const val SYSTEM_TEXT_INTELLIGENCE = "android.app.role.SYSTEM_TEXT_INTELLIGENCE"
+ private const val SYSTEM_VISUAL_INTELLIGENCE = "android.app.role.SYSTEM_VISUAL_INTELLIGENCE"
+
+ // This excludes System intelligence roles
+ private val EXEMPTED_ROLES =
+ arrayOf(
+ SYSTEM_AMBIENT_AUDIO_INTELLIGENCE,
+ SYSTEM_UI_INTELLIGENCE,
+ SYSTEM_AUDIO_INTELLIGENCE,
+ SYSTEM_NOTIFICATION_INTELLIGENCE,
+ SYSTEM_TEXT_INTELLIGENCE,
+ SYSTEM_VISUAL_INTELLIGENCE)
+
+ /** Lock required for all public methods */
+ private val nlsLock = Mutex()
+
+ /** lock for shared preferences writes */
+ private val sharedPrefsLock = Mutex()
+
+ private val sourceStateChangedSafetyEvent =
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
+ }
+
+ /**
+ * Check for enabled notification listeners and notify user if needed.
+ *
+ * <p>Always run async inside a {@NotificationListenerCheckJobService} via coroutine.
+ */
+ @WorkerThread
+ internal suspend fun getEnabledNotificationListenersAndNotifyIfNeeded(
+ params: JobParameters,
+ service: NotificationListenerCheckJobService
+ ) {
+ nlsLock.withLock {
+ try {
+ getEnabledNotificationListenersAndNotifyIfNeededLocked()
+ service.jobFinished(params, false)
+ } catch (e: Exception) {
+ Log.e(TAG, "Could not check for notification listeners", e)
+ service.jobFinished(params, true)
+ } finally {
+ service.clearJob()
+ }
+ }
+ }
+
+ @Throws(InterruptedException::class)
+ private suspend fun getEnabledNotificationListenersAndNotifyIfNeededLocked() {
+ val enabledComponents: List<ComponentName> = getEnabledNotificationListeners()
+
+ // Clear disabled but previously notified components from notified components data
+ removeDisabledComponentsFromNotifiedComponents(enabledComponents)
+ val notifiedComponents =
+ getNotifiedComponents().mapNotNull { ComponentName.unflattenFromString(it) }
+
+ // Filter to unnotified components
+ val unNotifiedComponents = enabledComponents.filter { it !in notifiedComponents }
+ var sessionId = Constants.INVALID_SESSION_ID
+ while (sessionId == Constants.INVALID_SESSION_ID) {
+ sessionId = random.nextLong()
+ }
+ if (DEBUG) {
+ Log.v(
+ TAG,
+ "Found ${enabledComponents.size} enabled notification listeners. " +
+ "${notifiedComponents.size} already notified. ${unNotifiedComponents.size} " +
+ "unnotified, sessionId = $sessionId")
+ }
+
+ throwInterruptedExceptionIfTaskIsCanceled()
+
+ postSystemNotificationIfNeeded(unNotifiedComponents, sessionId)
+ sendIssuesToSafetyCenter(enabledComponents, sessionId)
+ }
+
+ /**
+ * Get the [components][ComponentName] which have enabled notification listeners for the
+ * parent/context user. Excludes exempt packages.
+ *
+ * @throws InterruptedException If [.shouldCancel]
+ */
+ @Throws(InterruptedException::class)
+ private fun getEnabledNotificationListeners(): List<ComponentName> {
+ // Get all enabled NotificationListenerService components for primary user. NLS from managed
+ // profiles are never bound.
+ val enabledNotificationListeners =
+ getSystemServiceSafe(parentUserContext, NotificationManager::class.java)
+ .enabledNotificationListeners
+
+ // Filter to components not in exempt packages
+ val enabledNotificationListenersExcludingExemptPackages =
+ enabledNotificationListeners.filter { !exemptPackages.contains(it.packageName) }
+
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "enabledNotificationListeners=$enabledNotificationListeners\n" +
+ "enabledNotificationListenersExcludingExemptPackages=" +
+ "$enabledNotificationListenersExcludingExemptPackages")
+ }
+
+ throwInterruptedExceptionIfTaskIsCanceled()
+ return enabledNotificationListenersExcludingExemptPackages
+ }
+
+ /** Get all the exempted packages. */
+ private fun getExemptedPackages(roleManager: RoleManager, context: Context): Set<String> {
+ val exemptedPackages: MutableSet<String> = HashSet()
+ exemptedPackages.add(SYSTEM_PKG)
+ EXEMPTED_ROLES.forEach { role -> exemptedPackages.addAll(roleManager.getRoleHolders(role)) }
+ exemptedPackages.addAll(NotificationListenerPregrants(context).pregrantedPackages)
+ return exemptedPackages
+ }
+
+ @VisibleForTesting
+ internal fun getNotifiedComponents(): MutableSet<String> {
+ return sharedPrefs.getStringSet(KEY_ALREADY_NOTIFIED_COMPONENTS, mutableSetOf<String>())!!
+ }
+
+ internal suspend fun removeDisabledComponentsFromNotifiedComponents(
+ enabledComponents: Collection<ComponentName>
+ ) {
+ sharedPrefsLock.withLock {
+ val enabledComponentsStringSet =
+ enabledComponents.map { it.flattenToShortString() }.toSet()
+ val notifiedComponents = getNotifiedComponents()
+ // Filter to only components that have enabled listeners
+ val enabledNotifiedComponents =
+ notifiedComponents.filter { enabledComponentsStringSet.contains(it) }.toSet()
+ sharedPrefs
+ .edit()
+ .putStringSet(KEY_ALREADY_NOTIFIED_COMPONENTS, enabledNotifiedComponents)
+ .apply()
+ }
+ }
+
+ internal suspend fun markComponentAsNotified(component: ComponentName) {
+ sharedPrefsLock.withLock {
+ val notifiedComponents = getNotifiedComponents()
+ notifiedComponents.add(component.flattenToShortString())
+ sharedPrefs
+ .edit()
+ .putStringSet(KEY_ALREADY_NOTIFIED_COMPONENTS, notifiedComponents)
+ .apply()
+ }
+ }
+
+ internal suspend fun removeFromNotifiedComponents(packageName: String) {
+ sharedPrefsLock.withLock {
+ val notifiedComponents = getNotifiedComponents()
+ val filteredServices =
+ notifiedComponents
+ .filter {
+ val notifiedComponentName = ComponentName.unflattenFromString(it)
+ return@filter notifiedComponentName?.packageName != packageName
+ }
+ .toSet()
+ if (filteredServices.size < notifiedComponents.size) {
+ sharedPrefs
+ .edit()
+ .putStringSet(KEY_ALREADY_NOTIFIED_COMPONENTS, filteredServices)
+ .apply()
+ }
+ }
+ }
+
+ internal suspend fun removeFromNotifiedComponents(component: ComponentName) {
+ val componentNameShortString = component.flattenToShortString()
+ sharedPrefsLock.withLock {
+ val notifiedComponents = getNotifiedComponents()
+ val componentRemoved = notifiedComponents.remove(componentNameShortString)
+ if (componentRemoved) {
+ sharedPrefs
+ .edit()
+ .putStringSet(KEY_ALREADY_NOTIFIED_COMPONENTS, notifiedComponents)
+ .apply()
+ }
+ }
+ }
+
+ private fun getLastNotificationShownTimeMillis(): Long {
+ return sharedPrefs.getLong(KEY_LAST_NOTIFICATION_LISTENER_NOTIFICATION_SHOWN, 0)
+ }
+
+ private suspend fun updateLastShownNotificationTime() {
+ sharedPrefsLock.withLock {
+ sharedPrefs
+ .edit()
+ .putLong(KEY_LAST_NOTIFICATION_LISTENER_NOTIFICATION_SHOWN, currentTimeMillis())
+ .apply()
+ }
+ }
+
+ @Throws(InterruptedException::class)
+ private suspend fun postSystemNotificationIfNeeded(
+ components: List<ComponentName>,
+ sessionId: Long
+ ) {
+ val componentsInternal = components.toMutableList()
+
+ // Don't show too many notification within certain timespan
+ if (currentTimeMillis() - getLastNotificationShownTimeMillis() <
+ getInBetweenNotificationsMillis()) {
+ if (DEBUG) {
+ Log.v(
+ TAG,
+ "Notification not posted, within " +
+ "$DEFAULT_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS ms")
+ }
+ return
+ }
+
+ // 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")
+ }
+ return
+ }
+
+ // Get a random package and resolve package info
+ var pkgInfo: PackageInfo? = null
+ var componentToNotifyFor: ComponentName? = null
+ while (pkgInfo == null || componentToNotifyFor == null) {
+ throwInterruptedExceptionIfTaskIsCanceled()
+
+ if (componentsInternal.isEmpty()) {
+ if (DEBUG) {
+ Log.v(TAG, "Notification not posted, no unnotified enabled listeners")
+ }
+ return
+ }
+
+ componentToNotifyFor = componentsInternal[random.nextInt(componentsInternal.size)]
+ try {
+ if (DEBUG) {
+ Log.v(
+ TAG,
+ "Attempting to get PackageInfo for " + componentToNotifyFor.packageName)
+ }
+ pkgInfo =
+ Utils.getPackageInfoForComponentName(parentUserContext, componentToNotifyFor)
+ } catch (e: PackageManager.NameNotFoundException) {
+ if (DEBUG) {
+ Log.w(TAG, "${componentToNotifyFor.packageName} not found")
+ }
+ componentsInternal.remove(componentToNotifyFor)
+ }
+ }
+
+ createPermissionReminderChannel()
+ createNotificationForNotificationListener(componentToNotifyFor, pkgInfo, sessionId)
+
+ // Mark as notified, since we don't get the on-click
+ markComponentAsNotified(componentToNotifyFor)
+ }
+
+ /** Create the channel the notification listener notifications should be posted to. */
+ private fun createPermissionReminderChannel() {
+ val permissionReminderChannel =
+ NotificationChannel(
+ Constants.PERMISSION_REMINDER_CHANNEL_ID,
+ parentUserContext.getString(R.string.permission_reminders),
+ NotificationManager.IMPORTANCE_LOW)
+
+ val notificationManager =
+ getSystemServiceSafe(parentUserContext, NotificationManager::class.java)
+
+ notificationManager.createNotificationChannel(permissionReminderChannel)
+ }
+
+ /**
+ * Create a notification reminding the user that a package has an enabled notification listener.
+ * From this notification the user can directly go to Safety Center to assess issue.
+ *
+ * @param componentName the [ComponentName] of the Notification Listener
+ * @param pkg The [PackageInfo] for the [ComponentName] package
+ */
+ private suspend fun createNotificationForNotificationListener(
+ componentName: ComponentName,
+ pkg: PackageInfo,
+ sessionId: Long
+ ) {
+ val pkgLabel =
+ Utils.getApplicationLabel(parentUserContext, pkg.applicationInfo)
+ val uid = pkg.applicationInfo.uid
+
+ val deletePendingIntent =
+ getNotificationDeletePendingIntent(parentUserContext, componentName, uid, sessionId)
+ val clickPendingIntent =
+ getSafetyCenterActivityPendingIntent(parentUserContext, componentName, uid, sessionId)
+
+ val title =
+ parentUserContext.getString(R.string.notification_listener_reminder_notification_title)
+ val text =
+ parentUserContext.getString(
+ R.string.notification_listener_reminder_notification_content, pkgLabel)
+
+ val (appLabel, smallIcon, color) =
+ KotlinUtils.getSafetyCenterNotificationResources(parentUserContext)
+
+ val b: Notification.Builder =
+ Notification.Builder(parentUserContext, Constants.PERMISSION_REMINDER_CHANNEL_ID)
+ .setLocalOnly(true)
+ .setContentTitle(title)
+ .setContentText(text)
+ // Ensure entire text can be displayed, instead of being truncated to one line
+ .setStyle(Notification.BigTextStyle().bigText(text))
+ .setSmallIcon(smallIcon)
+ .setColor(color)
+ .setAutoCancel(true)
+ .setDeleteIntent(deletePendingIntent)
+ .setContentIntent(clickPendingIntent)
+
+ if (appLabel.isNotEmpty()) {
+ val appNameExtras = Bundle()
+ appNameExtras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, appLabel)
+ b.addExtras(appNameExtras)
+ }
+
+ val notificationManager =
+ getSystemServiceSafe(parentUserContext, NotificationManager::class.java)
+ notificationManager.notify(
+ componentName.flattenToString(), NOTIFICATION_LISTENER_CHECK_NOTIFICATION_ID, b.build())
+
+ if (DEBUG) {
+ Log.v(
+ TAG,
+ "Notification listener check notification shown with component=" +
+ "${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__NOTIFICATION_SHOWN,
+ sessionId)
+ updateLastShownNotificationTime()
+ }
+
+ /** @return [PendingIntent] to safety center */
+ private fun getNotificationDeletePendingIntent(
+ context: Context,
+ componentName: ComponentName,
+ uid: Int,
+ sessionId: Long
+ ): PendingIntent {
+ val intent =
+ Intent(
+ parentUserContext,
+ NotificationListenerCheckNotificationDeleteHandler::class.java)
+ .apply {
+ putExtra(EXTRA_COMPONENT_NAME, componentName)
+ putExtra(Constants.EXTRA_SESSION_ID, sessionId)
+ putExtra(Intent.EXTRA_UID, uid)
+ flags = FLAG_RECEIVER_FOREGROUND
+ identifier = componentName.flattenToString()
+ }
+ return PendingIntent.getBroadcast(
+ context, 0, intent, FLAG_ONE_SHOT or FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE)
+ }
+
+ /** @return [PendingIntent] to safety center */
+ private fun getSafetyCenterActivityPendingIntent(
+ context: Context,
+ componentName: ComponentName,
+ uid: Int,
+ sessionId: Long
+ ): PendingIntent {
+ val intent =
+ Intent(Intent.ACTION_SAFETY_CENTER).apply {
+ putExtra(EXTRA_SAFETY_SOURCE_ID, SC_NLS_SOURCE_ID)
+ putExtra(
+ EXTRA_SAFETY_SOURCE_ISSUE_ID,
+ getSafetySourceIssueIdFromComponentName(componentName))
+ putExtra(EXTRA_COMPONENT_NAME, componentName)
+ putExtra(Constants.EXTRA_SESSION_ID, sessionId)
+ putExtra(Intent.EXTRA_UID, uid)
+ flags = FLAG_ACTIVITY_NEW_TASK
+ identifier = componentName.flattenToString()
+ }
+ return PendingIntent.getActivity(
+ context, 0, intent, FLAG_ONE_SHOT or FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE)
+ }
+
+ /**
+ * Get currently shown notification. We only ever show one notification per profile group. Also
+ * only show notifications on the parent user/profile due to NotificationManager only binding
+ * non-managed NLS.
+ *
+ * @return The notification or `null` if no notification is currently shown
+ */
+ private fun getCurrentlyShownNotificationLocked(): StatusBarNotification? {
+ val notifications =
+ getSystemServiceSafe(parentUserContext, NotificationManager::class.java)
+ .activeNotifications
+
+ return notifications.firstOrNull { it.id == NOTIFICATION_LISTENER_CHECK_NOTIFICATION_ID }
+ }
+
+ /** Remove any posted notifications for this feature */
+ internal fun removeAnyNotification() {
+ cancelNotification()
+ }
+
+ /** Remove notification if present for a package */
+ internal fun removeNotificationsForPackage(pkg: String) {
+ val notification: StatusBarNotification = getCurrentlyShownNotificationLocked() ?: return
+ val notificationComponent = ComponentName.unflattenFromString(notification.tag)
+ if (notificationComponent == null || notificationComponent.packageName != pkg) {
+ return
+ }
+ cancelNotification(notification.tag)
+ }
+
+ /** Remove notification if present for a [ComponentName] */
+ internal fun removeNotificationsForComponent(component: ComponentName) {
+ val notification: StatusBarNotification = getCurrentlyShownNotificationLocked() ?: return
+ val notificationComponent = ComponentName.unflattenFromString(notification.tag)
+ if (notificationComponent == null || notificationComponent != component) {
+ return
+ }
+ cancelNotification(notification.tag)
+ }
+
+ private fun cancelNotification(notificationTag: String) {
+ getSystemServiceSafe(parentUserContext, NotificationManager::class.java)
+ .cancel(notificationTag, NOTIFICATION_LISTENER_CHECK_NOTIFICATION_ID)
+ }
+
+ private fun cancelNotification() {
+ getSystemServiceSafe(parentUserContext, NotificationManager::class.java)
+ .cancel(NOTIFICATION_LISTENER_CHECK_NOTIFICATION_ID)
+ }
+
+ internal fun sendIssuesToSafetyCenter(
+ safetyEvent: SafetyEvent = sourceStateChangedSafetyEvent
+ ) {
+ val enabledComponents = getEnabledNotificationListeners()
+ var sessionId = Constants.INVALID_SESSION_ID
+ while (sessionId == Constants.INVALID_SESSION_ID) {
+ sessionId = random.nextLong()
+ }
+ sendIssuesToSafetyCenter(enabledComponents, sessionId, safetyEvent)
+ }
+
+ private fun sendIssuesToSafetyCenter(
+ enabledComponents: List<ComponentName>,
+ sessionId: Long,
+ safetyEvent: SafetyEvent = sourceStateChangedSafetyEvent
+ ) {
+ val pendingIssues = enabledComponents.mapNotNull { createSafetySourceIssue(it, sessionId) }
+ val dataBuilder = SafetySourceData.Builder()
+ pendingIssues.forEach { dataBuilder.addIssue(it) }
+ val safetySourceData = dataBuilder.build()
+ val safetyCenterManager =
+ getSystemServiceSafe(parentUserContext, SafetyCenterManager::class.java)
+ safetyCenterManager.setSafetySourceData(SC_NLS_SOURCE_ID, safetySourceData, safetyEvent)
+ }
+
+ /**
+ * @param componentName enabled [NotificationListenerService]
+ * @return safety source issue, shown as the warning card in safety center. Null if unable to
+ * create safety source issue
+ */
+ @VisibleForTesting
+ fun createSafetySourceIssue(componentName: ComponentName, sessionId: Long): SafetySourceIssue? {
+ val pkgInfo: PackageInfo
+ try {
+ pkgInfo = Utils.getPackageInfoForComponentName(parentUserContext, componentName)
+ } catch (e: PackageManager.NameNotFoundException) {
+ if (DEBUG) {
+ Log.w(TAG, "${componentName.packageName} not found")
+ }
+ return null
+ }
+ val pkgLabel = Utils.getApplicationLabel(parentUserContext, pkgInfo.applicationInfo)
+ val safetySourceIssueId = getSafetySourceIssueIdFromComponentName(componentName)
+ val uid = pkgInfo.applicationInfo.uid
+
+ val disableNlsPendingIntent =
+ getDisableNlsPendingIntent(
+ 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)
+ .setWillResolve(true)
+ .setSuccessMessage(
+ parentUserContext.getString(
+ R.string.notification_listener_remove_access_success_label))
+ .build()
+
+ val notificationListenerDetailSettingsPendingIntent =
+ getNotificationListenerDetailSettingsPendingIntent(
+ 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)
+ .build()
+
+ val actionCardDismissPendingIntent =
+ getActionCardDismissalPendingIntent(parentUserContext, componentName, uid, sessionId)
+
+ val title =
+ parentUserContext.getString(R.string.notification_listener_reminder_notification_title)
+ val summary =
+ parentUserContext.getString(R.string.notification_listener_warning_card_content)
+
+ return SafetySourceIssue.Builder(
+ safetySourceIssueId,
+ title,
+ summary,
+ SafetySourceData.SEVERITY_LEVEL_INFORMATION,
+ SC_NLS_ISSUE_TYPE_ID)
+ .setSubtitle(pkgLabel)
+ .addAction(disableNlsAction)
+ .addAction(showNotificationListenerSettingsAction)
+ .setOnDismissPendingIntent(actionCardDismissPendingIntent)
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
+ .build()
+ }
+
+ /** @return [PendingIntent] for remove access button on the warning card. */
+ private fun getDisableNlsPendingIntent(
+ context: Context,
+ safetySourceIssueId: String,
+ componentName: ComponentName,
+ uid: Int,
+ sessionId: Long
+ ): PendingIntent {
+ val intent =
+ Intent(context, DisableNotificationListenerComponentHandler::class.java).apply {
+ putExtra(EXTRA_SAFETY_SOURCE_ISSUE_ID, safetySourceIssueId)
+ putExtra(EXTRA_COMPONENT_NAME, componentName)
+ putExtra(Constants.EXTRA_SESSION_ID, sessionId)
+ putExtra(Intent.EXTRA_UID, uid)
+ flags = FLAG_RECEIVER_FOREGROUND
+ identifier = componentName.flattenToString()
+ }
+
+ return PendingIntent.getBroadcast(context, 0, intent, FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT)
+ }
+
+ /** @return [PendingIntent] to Notification Listener Detail Settings page */
+ private fun getNotificationListenerDetailSettingsPendingIntent(
+ context: Context,
+ componentName: ComponentName,
+ uid: Int,
+ sessionId: Long
+ ): PendingIntent {
+ val intent =
+ Intent(ACTION_NOTIFICATION_LISTENER_DETAIL_SETTINGS).apply {
+ flags = FLAG_ACTIVITY_NEW_TASK
+ identifier = componentName.flattenToString()
+ putExtra(
+ 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)
+ }
+ return PendingIntent.getActivity(context, 0, intent, FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT)
+ }
+
+ private fun getActionCardDismissalPendingIntent(
+ context: Context,
+ componentName: ComponentName,
+ uid: Int,
+ sessionId: Long
+ ): PendingIntent {
+ val intent =
+ Intent(context, NotificationListenerActionCardDismissalReceiver::class.java).apply {
+ putExtra(EXTRA_COMPONENT_NAME, componentName)
+ putExtra(Constants.EXTRA_SESSION_ID, sessionId)
+ putExtra(Intent.EXTRA_UID, uid)
+ flags = FLAG_RECEIVER_FOREGROUND
+ identifier = componentName.flattenToString()
+ }
+ return PendingIntent.getBroadcast(context, 0, intent, FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT)
+ }
+
+ /** If [.shouldCancel] throw an [InterruptedException]. */
+ @Throws(InterruptedException::class)
+ private fun throwInterruptedExceptionIfTaskIsCanceled() {
+ if (shouldCancel != null && shouldCancel.asBoolean) {
+ throw InterruptedException()
+ }
+ }
+}
+
+/** Checks if a new notification should be shown. */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class NotificationListenerCheckJobService : JobService() {
+ private var notificationListenerCheckInternal: NotificationListenerCheckInternal? = null
+ private val jobLock = Object()
+
+ /** We currently check if we should show a notification, the task executing the check */
+ @GuardedBy("jobLock") private var addNotificationListenerNotificationIfNeededJob: Job? = null
+
+ override fun onCreate() {
+ super.onCreate()
+ if (DEBUG) Log.d(TAG, "Nls privacy job created")
+ if (!checkNotificationListenerCheckEnabled(this)) {
+ // NotificationListenerCheck not enabled. End job.
+ return
+ }
+
+ notificationListenerCheckInternal =
+ NotificationListenerCheckInternal(
+ this,
+ BooleanSupplier {
+ synchronized(jobLock) {
+ 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 {
+ if (DEBUG) Log.d(TAG, "Nls privacy job started")
+ if (!checkNotificationListenerCheckEnabled(this)) {
+ // NotificationListenerCheck not enabled. End job.
+ return false
+ }
+
+ synchronized(jobLock) {
+ if (addNotificationListenerNotificationIfNeededJob != null) {
+ if (DEBUG) Log.d(TAG, "Job already running")
+ return false
+ }
+ addNotificationListenerNotificationIfNeededJob =
+ GlobalScope.launch(Default) {
+ notificationListenerCheckInternal
+ ?.getEnabledNotificationListenersAndNotifyIfNeeded(
+ params, this@NotificationListenerCheckJobService)
+ ?: jobFinished(params, true)
+ }
+ }
+ return true
+ }
+
+ /**
+ * Abort the check if still running.
+ *
+ * @param params ignored
+ *
+ * @return false
+ */
+ override fun onStopJob(params: JobParameters): Boolean {
+ var job: Job?
+ synchronized(jobLock) {
+ job =
+ if (addNotificationListenerNotificationIfNeededJob == null) {
+ return false
+ } else {
+ addNotificationListenerNotificationIfNeededJob
+ }
+ }
+ job?.cancel()
+ return false
+ }
+
+ fun clearJob() {
+ synchronized(jobLock) { addNotificationListenerNotificationIfNeededJob = null }
+ }
+}
+
+/** On boot set up a periodic job that starts checks. */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class SetupPeriodicNotificationListenerCheck : BroadcastReceiver() {
+
+ override fun onReceive(context: Context, intent: Intent) {
+ if (!checkNotificationListenerCheckSupported()) {
+ // Notification Listener Check not supported. Exit.
+ return
+ }
+
+ if (isProfile(context)) {
+ // Profile parent handles child profiles too.
+ return
+ }
+
+ val jobScheduler = getSystemServiceSafe(context, JobScheduler::class.java)
+ if (jobScheduler.getPendingJob(PERIODIC_NOTIFICATION_LISTENER_CHECK_JOB_ID) == null) {
+ val job =
+ JobInfo.Builder(
+ PERIODIC_NOTIFICATION_LISTENER_CHECK_JOB_ID,
+ 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")
+ } else if (DEBUG) {
+ Log.i(TAG, "Scheduled periodic notification listener check")
+ }
+ }
+ }
+}
+
+/** Handle the case where the notification is swiped away without further interaction. */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class NotificationListenerCheckNotificationDeleteHandler : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (!checkNotificationListenerCheckSupported()) {
+ return
+ }
+
+ val componentName =
+ Utils.getParcelableExtraSafe<ComponentName>(intent, EXTRA_COMPONENT_NAME)
+ val sessionId =
+ intent.getLongExtra(Constants.EXTRA_SESSION_ID, Constants.INVALID_SESSION_ID)
+ val uid = intent.getIntExtra(Intent.EXTRA_UID, -1)
+
+ GlobalScope.launch(Default) {
+ NotificationListenerCheckInternal(context, null).markComponentAsNotified(componentName)
+ }
+ if (DEBUG) {
+ Log.v(
+ TAG,
+ "Notification listener check notification declined with component=" +
+ "${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)
+ }
+}
+
+/** Disable a specified Notification Listener Service component */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class DisableNotificationListenerComponentHandler : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (DEBUG) Log.d(TAG, "DisableComponentHandler.onReceive $intent")
+ val componentName =
+ Utils.getParcelableExtraSafe<ComponentName>(intent, EXTRA_COMPONENT_NAME)
+ val sessionId =
+ intent.getLongExtra(Constants.EXTRA_SESSION_ID, Constants.INVALID_SESSION_ID)
+ val uid = intent.getIntExtra(Intent.EXTRA_UID, -1)
+
+ GlobalScope.launch(Default) {
+ if (DEBUG) {
+ Log.v(
+ TAG,
+ "DisableComponentHandler: disabling $componentName," +
+ "uid=$uid, sessionId=$sessionId")
+ }
+
+ val safetyEventBuilder =
+ try {
+ val notificationManager =
+ getSystemServiceSafe(context, NotificationManager::class.java)
+ disallowNlsLock.withLock {
+ notificationManager.setNotificationListenerAccessGranted(
+ componentName, /* granted= */ false, /* userSet= */ true)
+ }
+
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED)
+ } catch (e: Exception) {
+ Log.w(TAG, "error occurred in disabling notification listener service.", e)
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
+ }
+
+ val safetySourceIssueId: String? = intent.getStringExtra(EXTRA_SAFETY_SOURCE_ISSUE_ID)
+ val safetyEvent =
+ safetyEventBuilder
+ .setSafetySourceIssueId(safetySourceIssueId)
+ .setSafetySourceIssueActionId(SC_NLS_DISABLE_ACTION_ID)
+ .build()
+
+ NotificationListenerCheckInternal(context, null).run {
+ removeNotificationsForComponent(componentName)
+ removeFromNotifiedComponents(componentName)
+ sendIssuesToSafetyCenter(safetyEvent)
+ }
+ PermissionControllerStatsLog.write(
+ PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION,
+ PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__PRIVACY_SOURCE__NOTIFICATION_LISTENER,
+ uid,
+ PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__ACTION__CLICKED_CTA1,
+ sessionId)
+ }
+ }
+
+ companion object {
+ private val disallowNlsLock = Mutex()
+ }
+}
+
+/* A Safety Center action card for a specified component was dismissed */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class NotificationListenerActionCardDismissalReceiver : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (DEBUG) Log.d(TAG, "ActionCardDismissalReceiver.onReceive $intent")
+ val componentName =
+ Utils.getParcelableExtraSafe<ComponentName>(intent, EXTRA_COMPONENT_NAME)
+ val sessionId =
+ intent.getLongExtra(Constants.EXTRA_SESSION_ID, Constants.INVALID_SESSION_ID)
+ val uid = intent.getIntExtra(Intent.EXTRA_UID, -1)
+
+ GlobalScope.launch(Default) {
+ if (DEBUG) {
+ Log.v(
+ TAG,
+ "ActionCardDismissalReceiver: $componentName dismissed," +
+ "uid=$uid, sessionId=$sessionId")
+ }
+ NotificationListenerCheckInternal(context, null).run {
+ removeNotificationsForComponent(componentName)
+ markComponentAsNotified(componentName)
+ }
+ }
+ PermissionControllerStatsLog.write(
+ PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION,
+ PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__PRIVACY_SOURCE__NOTIFICATION_LISTENER,
+ uid,
+ PRIVACY_SIGNAL_ISSUE_CARD_INTERACTION__ACTION__CARD_DISMISSED,
+ sessionId)
+ }
+}
+
+/**
+ * If a package gets removed or the data of the package gets cleared, forget that we showed a
+ * notification for it.
+ */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+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) {
+ return
+ }
+
+ if (!checkNotificationListenerCheckEnabled(context)) {
+ return
+ }
+
+ if (isProfile(context)) {
+ if (DEBUG) {
+ Log.d(TAG, "NotificationListenerCheck only supports parent profile")
+ }
+ return
+ }
+
+ val data = Preconditions.checkNotNull(intent.data)
+ val pkg: String = data.schemeSpecificPart
+
+ if (DEBUG) Log.i(TAG, "Reset $pkg")
+
+ GlobalScope.launch(Default) {
+ NotificationListenerCheckInternal(context, null).run {
+ removeNotificationsForPackage(pkg)
+ removeFromNotifiedComponents(pkg)
+ sendIssuesToSafetyCenter()
+ }
+ }
+ }
+}
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class NotificationListenerPrivacySource : PrivacySource {
+ override val shouldProcessProfileRequest: Boolean = false
+
+ override fun safetyCenterEnabledChanged(context: Context, enabled: Boolean) {
+ NotificationListenerCheckInternal(context, null).run { removeAnyNotification() }
+ }
+
+ override fun rescanAndPushSafetyCenterData(
+ context: Context,
+ intent: Intent,
+ refreshEvent: RefreshEvent
+ ) {
+ if (!isNotificationListenerCheckFlagEnabled()) {
+ return
+ }
+
+ val safetyRefreshEvent = getSafetyCenterEvent(refreshEvent, intent)
+
+ NotificationListenerCheckInternal(context, null).run {
+ sendIssuesToSafetyCenter(safetyRefreshEvent)
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/NotificationListenerPregrants.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/NotificationListenerPregrants.kt
new file mode 100644
index 000000000..aaf2d32e6
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/NotificationListenerPregrants.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.permissioncontroller.privacysources
+
+import android.content.Context
+import androidx.annotation.VisibleForTesting
+import com.android.safetycenter.resources.SafetyCenterResourcesContext
+
+// (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(","))
+ }
+ }
+ val pregrantedPackages: Set<String> by pregrantedPackagesDelegate
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySource.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySource.kt
index 700f0f4b9..e1d615075 100644
--- a/PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySource.kt
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySource.kt
@@ -22,23 +22,28 @@ import android.content.Intent
interface PrivacySource {
/**
+ * It is {@code true} for privacy source that wants to receive broadcasts signals for profiles
+ */
+ val shouldProcessProfileRequest: Boolean
+
+ /**
* Indicates that permission controller has received the safety center enabled changed broadcast
*
* <p> Invoked when {@link SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED} received
*
+ * @param context: Context of the broadcast
* @param enabled: {@code true} if Safety Center now enabled
*/
- fun safetyCenterEnabledChanged(enabled: Boolean)
+ fun safetyCenterEnabledChanged(context: Context, enabled: Boolean)
- /** Indicates that permission controller has received the safety center rescan broadcast.
- * context: Context of the broadcast
- * intent: Intent of the broadcast
- * refreshEvent: Enum explaining why this rescan was triggered. If the value is
- * EVENT_REFRESH_REQUESTED, get the broadcast id using code below,
- * val refreshBroadcastId = intent.getStringExtra(SafetyCenterManager
- * .EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID)
- * and add it to the safety event, when sending SafetyCenterManager#setSafetyCenterUpdate
- * val safetyEvent = SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
+ /**
+ * Indicates that permission controller has received the safety center rescan broadcast.
+ * context: Context of the broadcast intent: Intent of the broadcast refreshEvent: Enum
+ * explaining why this rescan was triggered. If the value is EVENT_REFRESH_REQUESTED, get the
+ * broadcast id using code below, val refreshBroadcastId =
+ * intent.getStringExtra(SafetyCenterManager .EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID) and add
+ * it to the safety event, when sending SafetyCenterManager#setSafetyCenterUpdate val
+ * safetyEvent = SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
* .setRefreshBroadcastId(refreshBroadcastId).build()
*/
fun rescanAndPushSafetyCenterData(
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourceData.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourceData.kt
new file mode 100644
index 000000000..f5903dfc2
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourceData.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.permissioncontroller.privacysources
+
+interface PrivacySourceData {
+
+ fun toStorageData(): String
+
+ 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
new file mode 100644
index 000000000..1eee90e31
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourceStorageRepository.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.permissioncontroller.privacysources
+
+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/PrivacySourcesUtils.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourcesUtils.kt
new file mode 100644
index 000000000..9439e8ee3
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/PrivacySourcesUtils.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:JvmName("PrivacySourcesUtils")
+
+package com.android.permissioncontroller.privacysources
+
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import android.os.UserManager
+import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetyEvent
+import androidx.annotation.RequiresApi
+import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+fun getSafetyCenterEvent(refreshEvent: RefreshEvent, intent: Intent): SafetyEvent {
+ return when (refreshEvent) {
+ RefreshEvent.UNKNOWN ->
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
+ RefreshEvent.EVENT_DEVICE_REBOOTED ->
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build()
+ RefreshEvent.EVENT_REFRESH_REQUESTED -> {
+ val refreshBroadcastId =
+ intent.getStringExtra(SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID)
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
+ .setRefreshBroadcastId(refreshBroadcastId)
+ .build()
+ }
+ }
+}
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+fun isProfile(context: Context): Boolean {
+ val userManager = Utils.getSystemServiceSafe(context, UserManager::class.java)
+ return userManager.isProfile
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/SafetyCenterReceiver.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/SafetyCenterReceiver.kt
index a793ebaee..885b8ea86 100644
--- a/PermissionController/src/com/android/permissioncontroller/privacysources/SafetyCenterReceiver.kt
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/SafetyCenterReceiver.kt
@@ -17,25 +17,54 @@
package com.android.permissioncontroller.privacysources
import android.content.BroadcastReceiver
+import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.Intent.ACTION_BOOT_COMPLETED
+import android.content.pm.PackageManager
+import android.os.Build
+import android.provider.DeviceConfig
import android.safetycenter.SafetyCenterManager
import android.safetycenter.SafetyCenterManager.ACTION_REFRESH_SAFETY_SOURCES
import android.safetycenter.SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED
import android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCE_IDS
+import androidx.annotation.RequiresApi
import com.android.modules.utils.build.SdkLevel
+import com.android.permissioncontroller.Constants.UNUSED_APPS_SAFETY_CENTER_SOURCE_ID
import com.android.permissioncontroller.PermissionControllerApplication
+import com.android.permissioncontroller.permission.service.LocationAccessCheck.BG_LOCATION_SOURCE_ID
+import com.android.permissioncontroller.permission.service.v33.SafetyCenterQsTileService
+import com.android.permissioncontroller.permission.service.v33.SafetyCenterQsTileService.Companion.QS_TILE_COMPONENT_SETTING_FLAGS
import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.privacysources.WorkPolicyInfo.Companion.WORK_POLICY_INFO_SOURCE_ID
+import com.android.permissioncontroller.privacysources.v34.AppDataSharingUpdatesPrivacySource
+import com.android.permissioncontroller.privacysources.v34.AppDataSharingUpdatesPrivacySource.Companion.APP_DATA_SHARING_UPDATES_SOURCE_ID
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.Default
import kotlinx.coroutines.launch
-private fun createMapOfSourceIdsToSources(): Map<String, PrivacySource> = emptyMap()
+private fun createMapOfSourceIdsToSources(context: Context): Map<String, PrivacySource> {
+ val sourceMap: MutableMap<String, PrivacySource> = mutableMapOf()
+ if (SdkLevel.isAtLeastT()) {
+ sourceMap[SC_NLS_SOURCE_ID] = NotificationListenerPrivacySource()
+ sourceMap[WORK_POLICY_INFO_SOURCE_ID] = WorkPolicyInfo.create(context)
+ sourceMap[SC_ACCESSIBILITY_SOURCE_ID] = AccessibilitySourceService(context)
+ sourceMap[BG_LOCATION_SOURCE_ID] = LocationAccessPrivacySource()
+ sourceMap[UNUSED_APPS_SAFETY_CENTER_SOURCE_ID] = AutoRevokePrivacySource()
+ }
+
+ if (SdkLevel.isAtLeastU()) {
+ sourceMap[APP_DATA_SHARING_UPDATES_SOURCE_ID] = AppDataSharingUpdatesPrivacySource()
+ }
+
+ return sourceMap
+}
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
class SafetyCenterReceiver(
- private val getMapOfSourceIdsToSources: () -> Map<String, PrivacySource> =
+ private val getMapOfSourceIdsToSources: (Context) -> Map<String, PrivacySource> =
::createMapOfSourceIdsToSources,
private val dispatcher: CoroutineDispatcher = Default
) : BroadcastReceiver() {
@@ -50,57 +79,90 @@ class SafetyCenterReceiver(
if (!SdkLevel.isAtLeastT()) {
return
}
- val safetyCenterManager: SafetyCenterManager = Utils.getSystemServiceSafe(
- PermissionControllerApplication.get().applicationContext,
- SafetyCenterManager::class.java
- )
+ val safetyCenterManager: SafetyCenterManager =
+ Utils.getSystemServiceSafe(
+ PermissionControllerApplication.get().applicationContext,
+ SafetyCenterManager::class.java
+ )
- if (!safetyCenterManager.isSafetyCenterEnabled &&
- intent.action != ACTION_SAFETY_CENTER_ENABLED_CHANGED) {
- return
- }
-
- val mapOfSourceIdsToSources = getMapOfSourceIdsToSources()
+ val mapOfSourceIdsToSources = getMapOfSourceIdsToSources(context)
when (intent.action) {
ACTION_SAFETY_CENTER_ENABLED_CHANGED -> {
safetyCenterEnabledChanged(
+ context,
safetyCenterManager.isSafetyCenterEnabled,
- mapOfSourceIdsToSources.values)
+ mapOfSourceIdsToSources.values
+ )
}
ACTION_REFRESH_SAFETY_SOURCES -> {
- val sourceIdsExtra = intent.getStringArrayExtra(EXTRA_REFRESH_SAFETY_SOURCE_IDS)
- if (sourceIdsExtra != null && sourceIdsExtra.isNotEmpty()) {
+ if (safetyCenterManager.isSafetyCenterEnabled) {
+ val sourceIdsExtra = intent.getStringArrayExtra(EXTRA_REFRESH_SAFETY_SOURCE_IDS)
+ if (sourceIdsExtra != null && sourceIdsExtra.isNotEmpty()) {
+ refreshSafetySources(
+ context,
+ intent,
+ RefreshEvent.EVENT_REFRESH_REQUESTED,
+ mapOfSourceIdsToSources,
+ sourceIdsExtra.toList()
+ )
+ }
+ }
+ }
+ ACTION_BOOT_COMPLETED -> {
+ updateTileVisibility(context, safetyCenterManager.isSafetyCenterEnabled)
+ if (safetyCenterManager.isSafetyCenterEnabled) {
refreshSafetySources(
context,
intent,
- RefreshEvent.EVENT_REFRESH_REQUESTED,
+ RefreshEvent.EVENT_DEVICE_REBOOTED,
mapOfSourceIdsToSources,
- sourceIdsExtra.toList()
+ mapOfSourceIdsToSources.keys.toList()
)
}
}
- ACTION_BOOT_COMPLETED -> {
- refreshSafetySources(
- context,
- intent,
- RefreshEvent.EVENT_DEVICE_REBOOTED,
- mapOfSourceIdsToSources,
- mapOfSourceIdsToSources.keys.toList()
- )
- }
}
}
private fun safetyCenterEnabledChanged(
+ context: Context,
enabled: Boolean,
privacySources: Collection<PrivacySource>
) {
privacySources.forEach { source ->
CoroutineScope(dispatcher).launch {
- source.safetyCenterEnabledChanged(enabled)
+ if (source.shouldProcessRequest(context)) {
+ source.safetyCenterEnabledChanged(context, enabled)
+ }
}
}
+ updateTileVisibility(context, enabled)
+ }
+
+ private fun updateTileVisibility(context: Context, enabled: Boolean) {
+ val tileComponent = ComponentName(context, SafetyCenterQsTileService::class.java)
+ val wasEnabled =
+ context.packageManager?.getComponentEnabledSetting(tileComponent) !=
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+ val qsTileComponentSettingFlags =
+ DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ QS_TILE_COMPONENT_SETTING_FLAGS,
+ PackageManager.DONT_KILL_APP
+ )
+ if (enabled && !wasEnabled) {
+ context.packageManager.setComponentEnabledSetting(
+ tileComponent,
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ qsTileComponentSettingFlags
+ )
+ } else if (!enabled && wasEnabled) {
+ context.packageManager.setComponentEnabledSetting(
+ tileComponent,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ qsTileComponentSettingFlags
+ )
+ }
}
private fun refreshSafetySources(
@@ -112,9 +174,18 @@ class SafetyCenterReceiver(
) {
for (sourceId in sourceIdsToRefresh) {
CoroutineScope(dispatcher).launch {
- mapOfSourceIdsToSources[sourceId]?.rescanAndPushSafetyCenterData(context, intent,
- refreshEvent)
+ val privacySource = mapOfSourceIdsToSources[sourceId] ?: return@launch
+ if (privacySource.shouldProcessRequest(context)) {
+ privacySource.rescanAndPushSafetyCenterData(context, intent, refreshEvent)
+ }
}
}
}
-} \ No newline at end of file
+
+ private fun PrivacySource.shouldProcessRequest(context: Context): Boolean {
+ if (!isProfile(context)) {
+ return true
+ }
+ return shouldProcessProfileRequest
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/TEST_MAPPING b/PermissionController/src/com/android/permissioncontroller/privacysources/TEST_MAPPING
new file mode 100644
index 000000000..dc01ab3e2
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/TEST_MAPPING
@@ -0,0 +1,40 @@
+{
+ "imports": [
+ {
+ "path": "packages/modules/Permission/SafetyCenter"
+ }
+ ],
+ "presubmit": [
+ {
+ "name": "PermissionControllerMockingTests",
+ "options": [
+ {
+ "include-filter": "com.android.permissioncontroller.tests.mocking.privacysources.NotificationListenerCheckInternalTest"
+ },
+ {
+ "include-filter": "com.android.permissioncontroller.tests.mocking.privacysources.NotificationListenerPrivacySourceTest"
+ },
+ {
+ "include-filter": "com.android.permissioncontroller.tests.mocking.privacysources.AccessibilitySourceServiceTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "CtsPermissionTestCases",
+ "options": [
+ {
+ "include-filter": "android.permission.cts.NotificationListenerCheckTest"
+ },
+ {
+ "include-filter": "android.permission.cts.AccessibilityPrivacySourceTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/TextStorageRepository.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/TextStorageRepository.kt
new file mode 100644
index 000000000..8a8711bb6
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/TextStorageRepository.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.permissioncontroller.privacysources
+
+import android.util.Log
+import java.io.BufferedReader
+import java.io.BufferedWriter
+import java.io.File
+import java.io.FileNotFoundException
+import java.io.FileReader
+import java.io.FileWriter
+import java.io.IOException
+
+class TextStorageRepository(private val file: File) : PrivacySourceStorageRepository {
+
+ val LOG_TAG = TextStorageRepository::class.java.simpleName
+
+ override fun persistData(dataList: List<PrivacySourceData>) {
+ try {
+ writeLines(dataList.map { it.toStorageData() })
+ } catch (ex: IOException) {
+ Log.e(LOG_TAG, "Could not read ${file.absolutePath}", ex)
+ }
+ }
+
+ 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
+ }
+ }.toList()
+ }
+ } catch (ignored: FileNotFoundException) {
+ Log.e(LOG_TAG, "Could not find file ${file.absolutePath}")
+ return emptyList()
+ } catch (ex: IOException) {
+ Log.e(LOG_TAG, "Could not read ${file.absolutePath}", ex)
+ return emptyList()
+ }
+ }
+
+ private fun writeLines(lines: List<String>) {
+ BufferedWriter(FileWriter(file)).use { writer ->
+ lines.forEach {
+ writer.write(it)
+ writer.newLine()
+ }
+ }
+ }
+} \ 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
new file mode 100644
index 000000000..2ab6d37f0
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/WorkPolicyInfo.kt
@@ -0,0 +1,136 @@
+/*
+ * 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.permissioncontroller.privacysources
+
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import android.os.UserHandle
+import android.provider.Settings
+import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetyEvent
+import android.safetycenter.SafetySourceData
+import android.safetycenter.SafetySourceStatus
+import androidx.annotation.RequiresApi
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent
+import com.android.settingslib.utils.WorkPolicyUtils
+
+/**
+ * Work Policy Info for managed devices to show the settings managed by their Organisation's IT
+ * Admin. It is a Privacy Source, and it receives broadcasts from SafetyCenter using
+ * SafetyCenterReceiver.kt
+ *
+ * safetyCenterEnabledChanged and rescanAndPushSafetyCenterData methods checks if the device is
+ * managed and shows the Work Policy Info by pushing the data in SafetyCenter
+ */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class WorkPolicyInfo(private val workPolicyUtils: WorkPolicyUtils) : PrivacySource {
+
+ companion object {
+ const val WORK_POLICY_INFO_SOURCE_ID = "AndroidWorkPolicyInfo"
+ const val WORK_POLICY_TITLE = "SafetyCenter.WORK_POLICY_TITLE"
+ const val WORK_POLICY_SUMMARY = "SafetyCenter.WORK_POLICY_SUMMARY"
+ fun create(context: Context): WorkPolicyInfo {
+ val workPolicyUtils = WorkPolicyUtils(context)
+ return WorkPolicyInfo(workPolicyUtils)
+ }
+ }
+
+ override val shouldProcessProfileRequest: Boolean = false
+
+ override fun safetyCenterEnabledChanged(context: Context, enabled: Boolean) {
+ val intent = Intent(Settings.ACTION_SHOW_WORK_POLICY_INFO)
+ val refreshEvent: RefreshEvent = RefreshEvent.UNKNOWN
+ if (enabled) {
+ rescanAndPushSafetyCenterData(context, intent, refreshEvent)
+ }
+ }
+
+ override fun rescanAndPushSafetyCenterData(
+ context: Context,
+ intent: Intent,
+ refreshEvent: RefreshEvent
+ ) {
+ val safetyCenterManager: SafetyCenterManager =
+ Utils.getSystemServiceSafe(context, SafetyCenterManager::class.java)
+ val safetyEvent: SafetyEvent = createSafetyEventForWorkPolicy(refreshEvent, intent)
+ val safetySourceData: SafetySourceData? = createSafetySourceDataForWorkPolicy(context)
+
+ safetyCenterManager.setSafetySourceData(
+ WORK_POLICY_INFO_SOURCE_ID, safetySourceData, safetyEvent)
+ }
+
+ private fun createSafetySourceDataForWorkPolicy(context: Context): SafetySourceData? {
+ val deviceOwnerIntent = workPolicyUtils.workPolicyInfoIntentDO
+ val profileOwnerIntent = workPolicyUtils.workPolicyInfoIntentPO
+ val pendingIntent =
+ when {
+ deviceOwnerIntent != null -> {
+ PendingIntent.getActivity(
+ context, 0, deviceOwnerIntent, PendingIntent.FLAG_IMMUTABLE)
+ }
+ profileOwnerIntent != null -> {
+ val managedProfileContext =
+ context.createPackageContextAsUser(
+ context.packageName,
+ 0,
+ UserHandle.of(workPolicyUtils.managedProfileUserId))
+ PendingIntent.getActivity(
+ managedProfileContext, 0, profileOwnerIntent, PendingIntent.FLAG_IMMUTABLE)
+ }
+ else -> null
+ }
+ ?: return null
+
+ val safetySourceStatus: SafetySourceStatus =
+ SafetySourceStatus.Builder(
+ Utils.getEnterpriseString(
+ context, WORK_POLICY_TITLE, R.string.work_policy_title),
+ Utils.getEnterpriseString(
+ context, WORK_POLICY_SUMMARY, R.string.work_policy_summary),
+ SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED)
+ .setPendingIntent(pendingIntent)
+ .build()
+
+ return SafetySourceData.Builder().setStatus(safetySourceStatus).build()
+ }
+
+ private fun createSafetyEventForWorkPolicy(
+ refreshEvent: RefreshEvent,
+ intent: Intent
+ ): SafetyEvent {
+ return when (refreshEvent) {
+ RefreshEvent.EVENT_REFRESH_REQUESTED -> {
+ val refreshBroadcastId =
+ intent.getStringExtra(
+ SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID)
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
+ .setRefreshBroadcastId(refreshBroadcastId)
+ .build()
+ }
+ RefreshEvent.EVENT_DEVICE_REBOOTED -> {
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build()
+ }
+ RefreshEvent.UNKNOWN -> {
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
+ }
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/v34/AppDataSharingUpdatesPrivacySource.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/v34/AppDataSharingUpdatesPrivacySource.kt
new file mode 100644
index 000000000..8bedc3979
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/v34/AppDataSharingUpdatesPrivacySource.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.privacysources.v34
+
+import android.app.PendingIntent
+import android.app.PendingIntent.FLAG_IMMUTABLE
+import android.app.PendingIntent.FLAG_UPDATE_CURRENT
+import android.content.Context
+import android.content.Intent
+import android.content.Intent.ACTION_REVIEW_APP_DATA_SHARING_UPDATES
+import android.os.Build
+import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetyEvent
+import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED
+import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED
+import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
+import android.safetycenter.SafetySourceData
+import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_INFORMATION
+import android.safetycenter.SafetySourceStatus
+import androidx.annotation.RequiresApi
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.utils.KotlinUtils
+import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.privacysources.PrivacySource
+import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent
+import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent.EVENT_DEVICE_REBOOTED
+import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent.EVENT_REFRESH_REQUESTED
+import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent.UNKNOWN
+
+/**
+ * Privacy source providing the App Data Sharing Updates page entry to Safety Center.
+ *
+ * The content of the App Data Sharing Updates page is static, however the entry should only be
+ * displayed if the Safety Label Change Notification feature is enabled.
+ */
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+class AppDataSharingUpdatesPrivacySource : PrivacySource {
+
+ override val shouldProcessProfileRequest: Boolean = false
+
+ override fun safetyCenterEnabledChanged(context: Context, enabled: Boolean) {
+ // Do nothing.
+ }
+
+ override fun rescanAndPushSafetyCenterData(
+ context: Context,
+ intent: Intent,
+ refreshEvent: RefreshEvent
+ ) {
+ val safetyCenterManager: SafetyCenterManager =
+ Utils.getSystemServiceSafe(context, SafetyCenterManager::class.java)
+
+ val safetySourceData =
+ if (KotlinUtils.isSafetyLabelChangeNotificationsEnabled(context)) {
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder(
+ context.getString(R.string.data_sharing_updates_title),
+ context.getString(R.string.data_sharing_updates_summary),
+ SEVERITY_LEVEL_INFORMATION)
+ .setPendingIntent(
+ PendingIntent.getActivity(
+ context,
+ /* requestCode= */ 0,
+ Intent(ACTION_REVIEW_APP_DATA_SHARING_UPDATES),
+ FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE))
+ .build(),
+ )
+ .build()
+ } else {
+ null
+ }
+
+ safetyCenterManager.setSafetySourceData(
+ APP_DATA_SHARING_UPDATES_SOURCE_ID,
+ safetySourceData,
+ createSafetyEventForDataSharingUpdates(refreshEvent, intent))
+ }
+
+ private fun createSafetyEventForDataSharingUpdates(
+ refreshEvent: RefreshEvent,
+ intent: Intent
+ ): SafetyEvent {
+ return when (refreshEvent) {
+ EVENT_REFRESH_REQUESTED -> {
+ val refreshBroadcastId =
+ intent.getStringExtra(
+ SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID)
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
+ .setRefreshBroadcastId(refreshBroadcastId)
+ .build()
+ }
+ EVENT_DEVICE_REBOOTED -> {
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build()
+ }
+ UNKNOWN -> {
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
+ }
+ }
+ }
+
+ /** Companion object for [AppDataSharingUpdatesPrivacySource]. */
+ companion object {
+ /** Source id for safety center source for app data sharing updates. */
+ const val APP_DATA_SHARING_UPDATES_SOURCE_ID = "AndroidPrivacyAppDataSharingUpdates"
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/Role.md b/PermissionController/src/com/android/permissioncontroller/role/Role.md
index 9e867e341..bde9f86f0 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/Role.md
+++ b/PermissionController/src/com/android/permissioncontroller/role/Role.md
@@ -61,8 +61,10 @@ is optional and defaults to `false`.
- `label`: The string resource for the label of the role, e.g. `@string/role_sms_label`, which says
"Default SMS app". For default apps, this string will appear in the default app detail page as the
title. This attribute is required if the role is `visible`.
-- `minSdkVersion`: The minimum SDK version for the role to be available, e.g. `31` for Android S.
-This attribute is optional and defaults to `Build.VERSION_CODES.BASE`.
+- `maxSdkVersion`: The maximum 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.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`.
- `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
@@ -86,10 +88,13 @@ defaults to `false`.
- `static`: Whether this role is static, i.e. the role will always be assigned to its default
holders. This attribute is optional and defaults to `false`.
- `systemOnly`: Whether this role only allows system apps to hold it. This attribute is optional and
-defaults to `false.
+defaults to `false`.
- `visible`: Whether this role is visible to users. If a role is invisible (a.k.a. hidden) to users,
users won't be able to find it in Settings, and apps won't be able to request it. The role can still
be managed by system APIs and shell command.
+- `uiBehavior`: Optional name of a [`RoleUiBehavior`](ui/behavior/RoleUiBehavior.java) class to
+control certain role UI behavior in Java code, e.g. `DialerRoleUiBehavior`. This can be useful
+when the XML syntax cannot express certain UI behavior specific to the role.
The following tags can be specified inside a `<role>` tag:
@@ -172,6 +177,7 @@ dumpsys role
You can also manage the role holders with `cmd role`:
```bash
+cmd role get-role-holders [--user USER_ID] ROLE
cmd role add-role-holder [--user USER_ID] ROLE PACKAGE [FLAGS]
cmd role remove-role-holder [--user USER_ID] ROLE PACKAGE [FLAGS]
cmd role clear-role-holders [--user USER_ID] ROLE [FLAGS]
diff --git a/PermissionController/src/com/android/permissioncontroller/role/TEST_MAPPING b/PermissionController/src/com/android/permissioncontroller/role/TEST_MAPPING
index 43d15a49e..d7718a2f2 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/TEST_MAPPING
+++ b/PermissionController/src/com/android/permissioncontroller/role/TEST_MAPPING
@@ -8,5 +8,22 @@
}
]
}
+ ],
+ "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"
+ }
+ ]
+ }
]
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/EncryptionUnawareConfirmationMixin.java b/PermissionController/src/com/android/permissioncontroller/role/model/EncryptionUnawareConfirmationMixin.java
index 3f1e7ed0c..567f1c713 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/EncryptionUnawareConfirmationMixin.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/model/EncryptionUnawareConfirmationMixin.java
@@ -25,6 +25,8 @@ import androidx.annotation.Nullable;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.role.utils.PackageUtils;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.RoleBehavior;
/**
* Mixin for {@link RoleBehavior#getConfirmationMessage(Role, String, Context)}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/RoleParserInitializer.java b/PermissionController/src/com/android/permissioncontroller/role/model/RoleParserInitializer.java
new file mode 100644
index 000000000..b1c9e3e1d
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/model/RoleParserInitializer.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.permissioncontroller.role.model;
+
+import com.android.permissioncontroller.R;
+import com.android.role.controller.model.RoleParser;
+
+/**
+ * Initialize the function to retrieve the roles.xml resource from a context within
+ * PermissionController APK
+ */
+public class RoleParserInitializer {
+
+ /**
+ * Initialize the function to retrieve the roles.xml resource from a context within
+ * PermissionController APK
+ */
+ public static void initialize() {
+ RoleParser.sGetRolesXml = context -> context.getResources().getXml(R.xml.roles);
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/VisibilityMixin.java b/PermissionController/src/com/android/permissioncontroller/role/model/VisibilityMixin.java
index 07afc6031..90cda72ca 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/VisibilityMixin.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/model/VisibilityMixin.java
@@ -23,6 +23,9 @@ import android.util.Log;
import androidx.annotation.NonNull;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.RoleBehavior;
+
/**
* Mixin for {@link RoleBehavior#isVisibleAsUser(Role, UserHandle, Context)} that returns whether
* the role should be visible from a corresponding boolean resource.
diff --git a/PermissionController/src/com/android/permissioncontroller/role/service/RoleControllerServiceImpl.java b/PermissionController/src/com/android/permissioncontroller/role/service/RoleControllerServiceImpl.java
index fbb9c2e2e..c1c7da46a 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/service/RoleControllerServiceImpl.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/service/RoleControllerServiceImpl.java
@@ -29,9 +29,10 @@ import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
import com.android.permissioncontroller.permission.utils.CollectionUtils;
-import com.android.permissioncontroller.role.model.Role;
-import com.android.permissioncontroller.role.model.Roles;
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 java.util.ArrayList;
import java.util.List;
@@ -428,8 +429,8 @@ public class RoleControllerServiceImpl extends RoleControllerService {
return false;
}
ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(packageName, this);
- if (applicationInfo == null || !role.isApplicationVisibleAsUser(applicationInfo,
- Process.myUserHandle(), this)) {
+ if (applicationInfo == null || !RoleUiBehaviorUtils.isApplicationVisibleAsUser(role,
+ applicationInfo, Process.myUserHandle(), this)) {
return false;
}
return true;
@@ -444,7 +445,8 @@ public class RoleControllerServiceImpl extends RoleControllerService {
if (!role.isAvailable(this)) {
return false;
}
- return role.isVisibleAsUser(Process.myUserHandle(), this);
+
+ return RoleUiBehaviorUtils.isVisibleAsUser(role, Process.myUserHandle(), this);
}
private static boolean checkFlags(int flags, int allowedFlags) {
diff --git a/PermissionController/src/com/android/permissioncontroller/role/service/RoleSearchIndexablesProvider.java b/PermissionController/src/com/android/permissioncontroller/role/service/RoleSearchIndexablesProvider.java
index 7201acffc..1c845ee3a 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/service/RoleSearchIndexablesProvider.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/service/RoleSearchIndexablesProvider.java
@@ -27,8 +27,10 @@ import androidx.annotation.Nullable;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.service.BaseSearchIndexablesProvider;
-import com.android.permissioncontroller.role.model.Role;
-import com.android.permissioncontroller.role.model.Roles;
+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;
/**
* {@link android.provider.SearchIndexablesProvider} for roles.
@@ -41,6 +43,12 @@ public class RoleSearchIndexablesProvider extends BaseSearchIndexablesProvider {
public static final String ACTION_MANAGE_SPECIAL_APP_ACCESS =
"com.android.permissioncontroller.settingssearch.action.MANAGE_SPECIAL_APP_ACCESS";
+ @Override
+ public boolean onCreate() {
+ RoleParserInitializer.initialize();
+ return true;
+ }
+
@Nullable
@Override
public Cursor queryRawData(@Nullable String[] projection) {
@@ -53,7 +61,8 @@ public class RoleSearchIndexablesProvider extends BaseSearchIndexablesProvider {
long token = Binder.clearCallingIdentity();
try {
- if (!role.isAvailable(context) || !role.isVisible(context)) {
+ if (!role.isAvailable(context) || !RoleUiBehaviorUtils.isVisible(role,
+ context)) {
continue;
}
} finally {
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppActivity.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppActivity.java
index 0ddb6c3ac..52471cb32 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppActivity.java
@@ -29,10 +29,11 @@ import androidx.fragment.app.Fragment;
import com.android.permissioncontroller.DeviceUtils;
import com.android.permissioncontroller.R;
-import com.android.permissioncontroller.role.model.Role;
-import com.android.permissioncontroller.role.model.Roles;
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.role.controller.model.Role;
+import com.android.role.controller.model.Roles;
/**
* Activity for a default app.
@@ -86,7 +87,8 @@ public class DefaultAppActivity extends SettingsActivity {
finish();
return;
}
- if (!role.isVisibleAsUser(user, this)) {
+
+ if (!RoleUiBehaviorUtils.isVisibleAsUser(role, user, this)) {
Log.e(LOG_TAG, "Role is invisible: " + roleName);
finish();
return;
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java
index b4e4aaa80..06e5ed264 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java
@@ -39,8 +39,9 @@ import androidx.preference.TwoStatePreference;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.utils.Utils;
-import com.android.permissioncontroller.role.model.Role;
-import com.android.permissioncontroller.role.model.Roles;
+import com.android.permissioncontroller.role.utils.RoleUiBehaviorUtils;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.Roles;
import java.util.List;
import java.util.Objects;
@@ -208,7 +209,8 @@ public class DefaultAppChildFragment<PF extends PreferenceFragmentCompat
preference.setChecked(checked);
if (applicationInfo != null) {
- mRole.prepareApplicationPreferenceAsUser(preference, applicationInfo, mUser, context);
+ RoleUiBehaviorUtils.prepareApplicationPreferenceAsUser(mRole, preference,
+ applicationInfo, mUser, context);
}
preferenceScreen.addPreference(preference);
@@ -238,8 +240,9 @@ public class DefaultAppChildFragment<PF extends PreferenceFragmentCompat
mViewModel.setNoneDefaultApp();
} else {
String packageName = key;
- CharSequence confirmationMessage = mRole.getConfirmationMessage(packageName,
- requireContext());
+ CharSequence confirmationMessage =
+ RoleUiBehaviorUtils.getConfirmationMessage(mRole, packageName,
+ requireContext());
if (confirmationMessage != null) {
DefaultAppConfirmationDialogFragment.show(packageName, confirmationMessage, this);
} else {
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java
index 752dfb9cc..3c8af1136 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java
@@ -40,8 +40,9 @@ import androidx.preference.PreferenceScreen;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.utils.Utils;
-import com.android.permissioncontroller.role.model.Role;
-import com.android.permissioncontroller.role.model.Roles;
+import com.android.permissioncontroller.role.utils.RoleUiBehaviorUtils;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.Roles;
import java.util.List;
import java.util.Objects;
@@ -186,8 +187,8 @@ public class DefaultAppListChildFragment<PF extends PreferenceFragmentCompat
preference.setIcon(Utils.getBadgedIcon(context, holderApplicationInfo));
preference.setSummary(Utils.getAppLabel(holderApplicationInfo, context));
}
- role.preparePreferenceAsUser((TwoTargetPreference) preference, user, context);
-
+ RoleUiBehaviorUtils.preparePreferenceAsUser(role, (TwoTargetPreference) preference,
+ user, context);
preferenceGroup.addPreference(preference);
}
}
@@ -198,7 +199,7 @@ public class DefaultAppListChildFragment<PF extends PreferenceFragmentCompat
Context context = requireContext();
Role role = Roles.get(context).get(roleName);
UserHandle user = preference.getExtras().getParcelable(Intent.EXTRA_USER);
- Intent intent = role.getManageIntentAsUser(user, context);
+ Intent intent = RoleUiBehaviorUtils.getManageIntentAsUser(role, user, context);
if (intent == null) {
intent = DefaultAppActivity.createIntent(roleName, user, context);
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java
index 080652055..c89e1f71e 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppViewModel.java
@@ -30,7 +30,7 @@ import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
-import com.android.permissioncontroller.role.model.Role;
+import com.android.role.controller.model.Role;
import java.util.List;
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleActivity.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleActivity.java
index 0d5216991..3a4312c00 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleActivity.java
@@ -34,10 +34,11 @@ import androidx.fragment.app.FragmentActivity;
import com.android.permissioncontroller.PermissionControllerStatsLog;
import com.android.permissioncontroller.permission.utils.CollectionUtils;
-import com.android.permissioncontroller.role.model.Role;
-import com.android.permissioncontroller.role.model.Roles;
import com.android.permissioncontroller.role.model.UserDeniedManager;
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 java.util.List;
import java.util.Objects;
@@ -109,7 +110,7 @@ public class RequestRoleActivity extends FragmentActivity {
return;
}
- if (!role.isVisible(this)) {
+ if (!RoleUiBehaviorUtils.isVisible(role, this)) {
Log.e(LOG_TAG, "Role is invisible: " + mRoleName);
reportRequestResult(
PermissionControllerStatsLog.ROLE_REQUEST_RESULT_REPORTED__RESULT__IGNORED);
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java
index 091a71c7d..a5bd90dc2 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java
@@ -52,10 +52,10 @@ import com.android.permissioncontroller.PermissionControllerStatsLog;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.utils.PackageRemovalMonitor;
import com.android.permissioncontroller.permission.utils.Utils;
-import com.android.permissioncontroller.role.model.Role;
-import com.android.permissioncontroller.role.model.Roles;
import com.android.permissioncontroller.role.model.UserDeniedManager;
import com.android.permissioncontroller.role.utils.PackageUtils;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.Roles;
import java.util.ArrayList;
import java.util.List;
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleViewModel.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleViewModel.java
index d93e8f8d6..ae80f997a 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleViewModel.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleViewModel.java
@@ -23,7 +23,7 @@ import androidx.annotation.NonNull;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
-import com.android.permissioncontroller.role.model.Role;
+import com.android.role.controller.model.Role;
/**
* {@link ViewModel} for a role request.
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleItem.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleItem.java
index 8bca5170c..dab709030 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleItem.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleItem.java
@@ -20,7 +20,7 @@ import android.content.pm.ApplicationInfo;
import androidx.annotation.NonNull;
-import com.android.permissioncontroller.role.model.Role;
+import com.android.role.controller.model.Role;
import java.util.List;
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListLiveData.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListLiveData.java
index 9742ed923..b9011bd78 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListLiveData.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListLiveData.java
@@ -29,9 +29,10 @@ import androidx.annotation.WorkerThread;
import androidx.lifecycle.LiveData;
import com.android.permissioncontroller.AsyncTaskLiveData;
-import com.android.permissioncontroller.role.model.Role;
-import com.android.permissioncontroller.role.model.Roles;
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 java.util.ArrayList;
import java.util.List;
@@ -96,7 +97,7 @@ public class RoleListLiveData extends AsyncTaskLiveData<List<RoleItem>>
continue;
}
- if (!role.isVisibleAsUser(mUser, mContext)) {
+ if (!RoleUiBehaviorUtils.isVisibleAsUser(role, mUser, mContext)) {
continue;
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListSortFunction.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListSortFunction.java
index b3e34236f..ca059aa32 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListSortFunction.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleListSortFunction.java
@@ -20,17 +20,18 @@ import android.content.Context;
import android.icu.text.Collator;
import androidx.annotation.NonNull;
-import androidx.arch.core.util.Function;
+
+import kotlin.jvm.functions.Function1;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
/**
- * A function for {@link androidx.lifecycle.Transformations#map(androidx.lifecycle.LiveData,
- * Function)} that sorts a live data for role list.
+ * A function for {@link androidx.lifecycle#map(androidx.lifecycle.LiveData, Function1)}
+ * that sorts a live data for role list.
*/
-public class RoleListSortFunction implements Function<List<RoleItem>, List<RoleItem>> {
+public class RoleListSortFunction implements Function1<List<RoleItem>, List<RoleItem>> {
@NonNull
private final Comparator<RoleItem> mComparator;
@@ -42,10 +43,9 @@ public class RoleListSortFunction implements Function<List<RoleItem>, List<RoleI
roleItem.getRole().getShortLabelResource()), collator);
}
- @NonNull
@Override
- public List<RoleItem> apply(@NonNull List<RoleItem> input) {
- List<RoleItem> sorted = new ArrayList<>(input);
+ public List<RoleItem> invoke(List<RoleItem> p1) {
+ List<RoleItem> sorted = new ArrayList<>(p1);
sorted.sort(mComparator);
return sorted;
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleLiveData.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleLiveData.java
index 31042f974..3ccb1d8bc 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleLiveData.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleLiveData.java
@@ -29,8 +29,9 @@ import androidx.annotation.WorkerThread;
import androidx.lifecycle.LiveData;
import com.android.permissioncontroller.AsyncTaskLiveData;
-import com.android.permissioncontroller.role.model.Role;
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;
import java.util.List;
@@ -94,7 +95,8 @@ public class RoleLiveData extends AsyncTaskLiveData<List<Pair<ApplicationInfo, B
+ qualifyingPackageName);
continue;
}
- if (!mRole.isApplicationVisibleAsUser(qualifyingApplicationInfo, mUser, mContext)) {
+ if (!RoleUiBehaviorUtils.isApplicationVisibleAsUser(mRole, qualifyingApplicationInfo,
+ mUser, mContext)) {
continue;
}
boolean isHolderApplication = holderPackageNames.contains(qualifyingPackageName);
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleSortFunction.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleSortFunction.java
index 5e74d5e89..10db9dbcd 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleSortFunction.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleSortFunction.java
@@ -23,19 +23,20 @@ import android.os.UserHandle;
import android.util.Pair;
import androidx.annotation.NonNull;
-import androidx.arch.core.util.Function;
import com.android.permissioncontroller.permission.utils.Utils;
+import kotlin.jvm.functions.Function1;
+
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
/**
- * A function for {@link androidx.lifecycle.Transformations#map(androidx.lifecycle.LiveData,
- * Function)} that sorts a live data for role.
+ * A function for {@link androidx.lifecycle#map(androidx.lifecycle.LiveData, Function1)}
+ * that sorts a live data for role.
*/
-public class RoleSortFunction implements Function<List<Pair<ApplicationInfo, Boolean>>,
+public class RoleSortFunction implements Function1<List<Pair<ApplicationInfo, Boolean>>,
List<Pair<ApplicationInfo, Boolean>>> {
@NonNull
@@ -51,11 +52,9 @@ public class RoleSortFunction implements Function<List<Pair<ApplicationInfo, Boo
mComparator = labelComparator.thenComparing(userIdComparator);
}
- @NonNull
@Override
- public List<Pair<ApplicationInfo, Boolean>> apply(
- @NonNull List<Pair<ApplicationInfo, Boolean>> input) {
- List<Pair<ApplicationInfo, Boolean>> sorted = new ArrayList<>(input);
+ public List<Pair<ApplicationInfo, Boolean>> invoke(List<Pair<ApplicationInfo, Boolean>> p1) {
+ List<Pair<ApplicationInfo, Boolean>> sorted = new ArrayList<>(p1);
sorted.sort(mComparator);
return sorted;
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/TwoTargetPreference.java b/PermissionController/src/com/android/permissioncontroller/role/ui/TwoTargetPreference.java
index a6a453aee..23044b833 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/TwoTargetPreference.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/TwoTargetPreference.java
@@ -49,4 +49,7 @@ public interface TwoTargetPreference {
*/
void onSecondTargetClick(@NonNull TwoTargetPreference preference);
}
+
+ /** @see androidx.preference.Preference#setEnabled(boolean) */
+ void setEnabled(boolean enabled);
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoDefaultAppFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoDefaultAppFragment.java
index c86d48db0..dbd4c7c03 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoDefaultAppFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoDefaultAppFragment.java
@@ -27,8 +27,8 @@ import androidx.preference.TwoStatePreference;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.auto.AutoSettingsFrameFragment;
-import com.android.permissioncontroller.role.model.Role;
import com.android.permissioncontroller.role.ui.DefaultAppChildFragment;
+import com.android.role.controller.model.Role;
/** Screen to pick a default app for a particular {@link Role}. */
public class AutoDefaultAppFragment extends AutoSettingsFrameFragment implements
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/AssistantRoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/AssistantRoleUiBehavior.java
new file mode 100644
index 000000000..40bd7a33e
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/AssistantRoleUiBehavior.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.permissioncontroller.role.ui.behavior;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+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;
+
+/***
+ * Class for UI behavior of Assistant 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,
+ @NonNull Context context) {
+ boolean isAutomotive =
+ context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+
+ if (isAutomotive) {
+ return null;
+ }
+
+ return new Intent(Settings.ACTION_VOICE_INPUT_SETTINGS);
+ }
+
+ @Nullable
+ @Override
+ public CharSequence getConfirmationMessage(@NonNull Role role, @NonNull String packageName,
+ @NonNull Context context) {
+ return context.getString(R.string.assistant_confirmation_message);
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/BrowserRoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/BrowserRoleUiBehavior.java
new file mode 100644
index 000000000..018b0db41
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/BrowserRoleUiBehavior.java
@@ -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 com.android.permissioncontroller.role.ui.behavior;
+
+import android.content.Context;
+import android.os.UserHandle;
+
+import androidx.annotation.NonNull;
+
+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);
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/DialerRoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/DialerRoleUiBehavior.java
new file mode 100644
index 000000000..8a5c8bdc7
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/DialerRoleUiBehavior.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.permissioncontroller.role.ui.behavior;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.UserHandle;
+import android.telecom.TelecomManager;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.preference.Preference;
+
+import com.android.permissioncontroller.R;
+import com.android.permissioncontroller.role.model.EncryptionUnawareConfirmationMixin;
+import com.android.role.controller.model.Role;
+
+import java.util.Objects;
+
+/***
+ * Class for UI behavior of Dialer role
+ */
+public class DialerRoleUiBehavior implements RoleUiBehavior {
+
+ @Override
+ public void prepareApplicationPreferenceAsUser(@NonNull Role role,
+ @NonNull Preference preference, @NonNull ApplicationInfo applicationInfo,
+ @NonNull UserHandle user, @NonNull Context context) {
+ RoleUiBehavior.super.prepareApplicationPreferenceAsUser(
+ role, preference, applicationInfo, user, context);
+
+ TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
+ String systemPackageName = telecomManager.getSystemDialerPackage();
+ if (Objects.equals(applicationInfo.packageName, systemPackageName)) {
+ preference.setSummary(R.string.default_app_system_default);
+ } else {
+ preference.setSummary(null);
+ }
+ }
+
+ @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,
+ @NonNull Context context) {
+ return EncryptionUnawareConfirmationMixin.getConfirmationMessage(role, packageName,
+ context);
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/EmergencyRoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/EmergencyRoleUiBehavior.java
new file mode 100644
index 000000000..8a62ee7eb
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/EmergencyRoleUiBehavior.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+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;
+
+/***
+ * Class for UI behavior of Emergency 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,
+ @NonNull Context context) {
+ return EncryptionUnawareConfirmationMixin.getConfirmationMessage(role, packageName,
+ context);
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/HomeRoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/HomeRoleUiBehavior.java
new file mode 100644
index 000000000..36bbd1cb1
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/HomeRoleUiBehavior.java
@@ -0,0 +1,121 @@
+/*
+ * 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.permissioncontroller.role.ui.behavior;
+
+import android.app.admin.DevicePolicyResources;
+import android.app.role.RoleManager;
+import android.content.ActivityNotFoundException;
+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.os.Build;
+import android.os.UserHandle;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+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;
+
+/***
+ * Class for UI behavior of Home role
+ */
+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) {
+ RoleUiBehavior.super.preparePreferenceAsUser(role, preference, user, context);
+
+ TwoTargetPreference.OnSecondTargetClickListener listener = null;
+ RoleManager roleManager = context.getSystemService(RoleManager.class);
+ String packageName = CollectionUtils.firstOrNull(roleManager.getRoleHoldersAsUser(
+ role.getName(), user));
+ if (packageName != null) {
+ Intent intent = new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
+ .setPackage(packageName)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ PackageManager userPackageManager = UserUtils.getUserContext(context, user)
+ .getPackageManager();
+ ResolveInfo resolveInfo = userPackageManager.resolveActivity(intent, 0);
+ if (resolveInfo != null && resolveInfo.activityInfo != null
+ && resolveInfo.activityInfo.exported) {
+ listener = preference2 -> {
+ try {
+ context.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(LOG_TAG, "Cannot start activity for home app preferences", e);
+ }
+ };
+ }
+ }
+ preference.setOnSecondTargetClickListener(listener);
+ }
+
+ @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) {
+ RoleUiBehavior.super.prepareApplicationPreferenceAsUser(
+ role, preference, applicationInfo, user, context);
+
+ boolean missingWorkProfileSupport = isMissingWorkProfileSupport(applicationInfo, context);
+ if (preference.isEnabled()) {
+ preference.setEnabled(!missingWorkProfileSupport);
+ }
+ preference.setSummary(missingWorkProfileSupport ? Utils.getEnterpriseString(context,
+ DevicePolicyResources.Strings.DefaultAppSettings
+ .HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE,
+ R.string.home_missing_work_profile_support) : null);
+ }
+
+ private boolean isMissingWorkProfileSupport(@NonNull ApplicationInfo applicationInfo,
+ @NonNull Context context) {
+ boolean hasWorkProfile = UserUtils.getWorkProfile(context) != null;
+ if (!hasWorkProfile) {
+ return false;
+ }
+ boolean isWorkProfileSupported = applicationInfo.targetSdkVersion
+ >= Build.VERSION_CODES.LOLLIPOP;
+ return !isWorkProfileSupported;
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/RoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/RoleUiBehavior.java
new file mode 100644
index 000000000..13343e926
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/RoleUiBehavior.java
@@ -0,0 +1,133 @@
+/*
+ * 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.permissioncontroller.role.ui.behavior;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.preference.Preference;
+
+import com.android.modules.utils.build.SdkLevel;
+import com.android.permissioncontroller.role.ui.TwoTargetPreference;
+import com.android.role.controller.model.Role;
+
+/***
+ * 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
+ * @param user the user to manage this role for
+ * @param context the {@code Context} to retrieve system services
+ *
+ * @return the {@link Intent} to manage this role, or {@code null} to use the default UI.
+ */
+ @Nullable
+ default Intent getManageIntentAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ return null;
+ }
+
+ /**
+ * Prepare a {@link Preference} for this role.
+ *
+ * @param role the role to prepare the preference for
+ * @param preference the {@link Preference} for this role
+ * @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 UserHandle user,
+ @NonNull Context context) {
+ if (SdkLevel.isAtLeastU() && role.isExclusive()) {
+ final UserManager userManager = context.getSystemService(UserManager.class);
+ preference.setEnabled(!userManager.hasUserRestrictionForUser(
+ UserManager.DISALLOW_CONFIG_DEFAULT_APPS, user));
+ }
+ }
+
+ /**
+ * 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
+ * @param preference the {@link Preference} for this role
+ * @param user the user for this role
+ * @param context the {@code Context} to retrieve system services
+ */
+ default void prepareApplicationPreferenceAsUser(@NonNull Role role,
+ @NonNull Preference preference, @NonNull ApplicationInfo applicationInfo,
+ @NonNull UserHandle user, @NonNull Context context) {
+ if (SdkLevel.isAtLeastU() && role.isExclusive()) {
+ final UserManager userManager = context.getSystemService(UserManager.class);
+ preference.setEnabled(!userManager.hasUserRestrictionForUser(
+ UserManager.DISALLOW_CONFIG_DEFAULT_APPS, user));
+ }
+ }
+
+ /**
+ * Get the confirmation message for adding an application as a holder of this role.
+ *
+ * @param role the role to get confirmation message for
+ * @param packageName the package name of the application to get confirmation message for
+ * @param context the {@code Context} to retrieve system services
+ *
+ * @return the confirmation message, or {@code null} if no confirmation is needed
+ */
+ @Nullable
+ default CharSequence getConfirmationMessage(@NonNull Role role, @NonNull String packageName,
+ @NonNull Context context) {
+ return null;
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/SmsRoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/SmsRoleUiBehavior.java
new file mode 100644
index 000000000..9fc9be3d4
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/SmsRoleUiBehavior.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+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;
+
+/***
+ * Class for UI behavior of SMS 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,
+ @NonNull Context context) {
+ return EncryptionUnawareConfirmationMixin.getConfirmationMessage(role, packageName,
+ context);
+ }
+}
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 2328bb94e..6ed105149 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessActivity.java
@@ -27,11 +27,12 @@ import androidx.fragment.app.Fragment;
import com.android.permissioncontroller.DeviceUtils;
import com.android.permissioncontroller.R;
-import com.android.permissioncontroller.role.model.Role;
-import com.android.permissioncontroller.role.model.Roles;
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;
/**
* Activity for a special app access.
@@ -75,7 +76,8 @@ public class SpecialAppAccessActivity extends SettingsActivity {
finish();
return;
}
- if (!role.isVisible(this)) {
+
+ if (!RoleUiBehaviorUtils.isVisible(role, this)) {
Log.e(LOG_TAG, "Role is invisible: " + roleName);
finish();
return;
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessChildFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessChildFragment.java
index 66e1e53ff..d75747b52 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessChildFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessChildFragment.java
@@ -36,9 +36,10 @@ import androidx.preference.PreferenceScreen;
import androidx.preference.TwoStatePreference;
import com.android.permissioncontroller.permission.utils.Utils;
-import com.android.permissioncontroller.role.model.Role;
-import com.android.permissioncontroller.role.model.Roles;
import com.android.permissioncontroller.role.ui.ManageRoleHolderStateLiveData;
+import com.android.permissioncontroller.role.utils.RoleUiBehaviorUtils;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.Roles;
import java.util.List;
@@ -157,9 +158,8 @@ public class SpecialAppAccessChildFragment<PF extends PreferenceFragmentCompat
preference.setChecked(isHolderPackage);
UserHandle user = UserHandle.getUserHandleForUid(qualifyingApplicationInfo.uid);
- mRole.prepareApplicationPreferenceAsUser(preference, qualifyingApplicationInfo, user,
- context);
-
+ RoleUiBehaviorUtils.prepareApplicationPreferenceAsUser(mRole, preference,
+ qualifyingApplicationInfo, user, context);
preferenceScreen.addPreference(preference);
}
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 52b7aa08d..ec4de84e1 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessListChildFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessListChildFragment.java
@@ -32,10 +32,11 @@ import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
-import com.android.permissioncontroller.role.model.Role;
-import com.android.permissioncontroller.role.model.Roles;
import com.android.permissioncontroller.role.ui.RoleItem;
import com.android.permissioncontroller.role.ui.TwoTargetPreference;
+import com.android.permissioncontroller.role.utils.RoleUiBehaviorUtils;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.Roles;
import java.util.List;
@@ -110,10 +111,9 @@ public class SpecialAppAccessListChildFragment<PF extends PreferenceFragmentComp
preference.setPersistent(false);
preference.setOnPreferenceClickListener(this);
}
-
- role.preparePreferenceAsUser((TwoTargetPreference) preference, Process.myUserHandle(),
+ RoleUiBehaviorUtils.preparePreferenceAsUser(role, (TwoTargetPreference) preference,
+ Process.myUserHandle(),
context);
-
preferenceScreen.addPreference(preference);
}
@@ -126,7 +126,7 @@ public class SpecialAppAccessListChildFragment<PF extends PreferenceFragmentComp
Context context = requireContext();
Role role = Roles.get(context).get(roleName);
UserHandle user = Process.myUserHandle();
- Intent intent = role.getManageIntentAsUser(user, context);
+ Intent intent = RoleUiBehaviorUtils.getManageIntentAsUser(role, user, context);
if (intent == null) {
intent = SpecialAppAccessActivity.createIntent(roleName, context);
}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessViewModel.java b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessViewModel.java
index 03aa5407e..0cc00abc1 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessViewModel.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/SpecialAppAccessViewModel.java
@@ -32,11 +32,11 @@ import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
-import com.android.permissioncontroller.role.model.Role;
import com.android.permissioncontroller.role.ui.ManageRoleHolderStateLiveData;
import com.android.permissioncontroller.role.ui.RoleLiveData;
import com.android.permissioncontroller.role.ui.RoleSortFunction;
import com.android.permissioncontroller.role.utils.UserUtils;
+import com.android.role.controller.model.Role;
import java.util.List;
diff --git a/PermissionController/src/com/android/permissioncontroller/role/utils/PackageUtils.java b/PermissionController/src/com/android/permissioncontroller/role/utils/PackageUtils.java
index 67d9ece44..9aaa07ee0 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/utils/PackageUtils.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/utils/PackageUtils.java
@@ -18,7 +18,6 @@ package com.android.permissioncontroller.role.utils;
import android.content.Context;
import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.UserHandle;
@@ -33,40 +32,6 @@ public final class PackageUtils {
private 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
- *
- * @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();
- try {
- return packageManager.getPackageInfo(packageName, PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | extraFlags);
- } catch (PackageManager.NameNotFoundException e) {
- return null;
- }
- }
-
- /**
- * Retrieve if a package is a system package.
- *
- * @param packageName the name 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;
- }
-
- /**
* Retrieve the {@link ApplicationInfo} of an application.
*
* @param packageName the package name of the application
diff --git a/PermissionController/src/com/android/permissioncontroller/role/utils/RoleManagerCompat.java b/PermissionController/src/com/android/permissioncontroller/role/utils/RoleManagerCompat.java
deleted file mode 100644
index 47f96adfb..000000000
--- a/PermissionController/src/com/android/permissioncontroller/role/utils/RoleManagerCompat.java
+++ /dev/null
@@ -1,42 +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.permissioncontroller.role.utils;
-
-import android.app.role.RoleManager;
-
-import androidx.annotation.NonNull;
-
-import com.android.modules.utils.build.SdkLevel;
-
-/**
- * Helper for accessing features in {@link RoleManager}.
- */
-public class RoleManagerCompat {
-
- private RoleManagerCompat() {}
-
- /**
- * @see RoleManager#isBypassingRoleQualification()
- */
- public static boolean isBypassingRoleQualification(@NonNull RoleManager roleManager) {
- if (SdkLevel.isAtLeastS()) {
- return roleManager.isBypassingRoleQualification();
- } else {
- return false;
- }
- }
-}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java b/PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java
new file mode 100644
index 000000000..e60bc6d76
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/role/utils/RoleUiBehaviorUtils.java
@@ -0,0 +1,151 @@
+/*
+ * 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.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.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.preference.Preference;
+
+import com.android.permissioncontroller.role.ui.TwoTargetPreference;
+import com.android.permissioncontroller.role.ui.behavior.RoleUiBehavior;
+import com.android.role.controller.model.Role;
+
+/**
+ * Utility methods for Role UI behavior
+ */
+public final class RoleUiBehaviorUtils {
+
+ private static final String LOG_TAG = RoleUiBehaviorUtils.class.getSimpleName();
+
+ /**
+ * Get the role ui behavior if available
+ */
+ @Nullable
+ private static RoleUiBehavior getUiBehavior(@NonNull Role role) {
+ String uiBehaviorName = role.getUiBehaviorName();
+ if (uiBehaviorName == null) {
+ return null;
+ }
+ RoleUiBehavior uiBehavior;
+ String uiBehaviorClassName = RoleUiBehavior.class.getPackage().getName() + '.'
+ + uiBehaviorName;
+ try {
+ uiBehavior = (RoleUiBehavior) Class.forName(uiBehaviorClassName).newInstance();
+ } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
+ Log.e(LOG_TAG, "Unable to instantiate UI behavior: " + uiBehaviorClassName, e);
+ return null;
+ }
+ return uiBehavior;
+ }
+
+ /**
+ * @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
+ public static Intent getManageIntentAsUser(@NonNull Role role, @NonNull UserHandle user,
+ @NonNull Context context) {
+ RoleUiBehavior uiBehavior = getUiBehavior(role);
+ if (uiBehavior == null) {
+ return null;
+ }
+ return uiBehavior.getManageIntentAsUser(role, user, context);
+ }
+
+ /**
+ * @see RoleUiBehavior#preparePreferenceAsUser
+ */
+ public static void preparePreferenceAsUser(@NonNull Role role,
+ @NonNull TwoTargetPreference preference, @NonNull UserHandle user,
+ @NonNull Context 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);
+ }
+
+ /**
+ * @see RoleUiBehavior#prepareApplicationPreferenceAsUser
+ */
+ public static void prepareApplicationPreferenceAsUser(@NonNull Role role,
+ @NonNull Preference preference, @NonNull ApplicationInfo applicationInfo,
+ @NonNull UserHandle user, @NonNull Context context) {
+ RoleUiBehavior uiBehavior = getUiBehavior(role);
+ if (uiBehavior == null) {
+ return;
+ }
+ uiBehavior.prepareApplicationPreferenceAsUser(role, preference, applicationInfo, user,
+ context);
+ }
+
+ /**
+ * @see RoleUiBehavior#getConfirmationMessage
+ */
+ @Nullable
+ public static CharSequence getConfirmationMessage(@NonNull Role role,
+ @NonNull String packageName, @NonNull Context context) {
+ RoleUiBehavior uiBehavior = getUiBehavior(role);
+ if (uiBehavior == null) {
+ return null;
+ }
+ return uiBehavior.getConfirmationMessage(role, packageName, context);
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/role/utils/UiUtils.java b/PermissionController/src/com/android/permissioncontroller/role/utils/UiUtils.java
index e3bd2c7d2..e13e55c51 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/utils/UiUtils.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/utils/UiUtils.java
@@ -37,61 +37,6 @@ public class UiUtils {
private UiUtils() {}
/**
- * Convert a dimension value in density independent pixels to pixels.
- *
- * @param dp the dimension value in density independent pixels
- * @param context the context to get the {@link DisplayMetrics}
- * @return the pixels
- *
- * @see TypedValue#complexToDimension(int, DisplayMetrics)
- */
- @Dimension
- public static float dpToPx(@Dimension(unit = Dimension.DP) float dp, @NonNull Context context) {
- DisplayMetrics metrics = context.getResources().getDisplayMetrics();
- return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, metrics);
- }
-
- /**
- * Convert a dimension value in density independent pixels to an integer pixel offset.
- *
- * @param dp the dimension value in density independent pixels
- * @param context the context to get the {@link DisplayMetrics}
- * @return the integer pixel offset
- *
- * @see TypedValue#complexToDimensionPixelOffset(int, DisplayMetrics)
- */
- @Px
- public static int dpToPxOffset(@Dimension(unit = Dimension.DP) float dp,
- @NonNull Context context) {
- return (int) dpToPx(dp, context);
- }
-
- /**
- * Convert a dimension value in density independent pixels to an integer pixel size.
- *
- * @param dp the dimension value in density independent pixels
- * @param context the context to get the {@link DisplayMetrics}
- * @return the integer pixel size
- *
- * @see TypedValue#complexToDimensionPixelSize(int, DisplayMetrics)
- */
- @Px
- public static int dpToPxSize(@Dimension(unit = Dimension.DP) float dp,
- @NonNull Context context) {
- float value = dpToPx(dp, context);
- int size = (int) (value >= 0 ? value + 0.5f : value - 0.5f);
- if (size != 0) {
- return size;
- } else if (value == 0) {
- return 0;
- } else if (value > 0) {
- return 1;
- } else {
- return -1;
- }
- }
-
- /**
* Set whether a view is shown.
*
* @param view the view to be set to shown or not
diff --git a/PermissionController/src/com/android/permissioncontroller/role/utils/UserUtils.java b/PermissionController/src/com/android/permissioncontroller/role/utils/UserUtils.java
index cd7a6b8a5..e89470ff6 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/utils/UserUtils.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/utils/UserUtils.java
@@ -39,16 +39,41 @@ public class UserUtils {
/**
* Check whether a user is a profile.
*
- * @param user the user to check
+ * @param user the user to check
* @param context the {@code Context} to retrieve system services
- *
* @return whether the user is a profile
*/
public static boolean isProfile(@NonNull UserHandle user, @NonNull Context context) {
+ return isManagedProfile(user, context) || isCloneProfile(user, context);
+ }
+
+ /**
+ * Check whether a user is a managed profile.
+ *
+ * @param user the user to check
+ * @param context the {@code Context} to retrieve system services
+ * @return whether the user is a managed profile
+ */
+ public static boolean isManagedProfile(@NonNull UserHandle user, @NonNull Context context) {
Context userContext = getUserContext(context, user);
UserManager userUserManager = userContext.getSystemService(UserManager.class);
- return userUserManager.isManagedProfile(user.getIdentifier()) || (
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && userUserManager.isCloneProfile());
+ return userUserManager.isManagedProfile(user.getIdentifier());
+ }
+
+ /**
+ * Check whether a user is a clone profile.
+ *
+ * @param user the user to check
+ * @param context the {@code Context} to retrieve system services
+ * @return whether the user is a clone profile
+ */
+ public static boolean isCloneProfile(@NonNull UserHandle user, @NonNull Context context) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
+ return false;
+ }
+ Context userContext = getUserContext(context, user);
+ UserManager userUserManager = userContext.getSystemService(UserManager.class);
+ return userUserManager.isCloneProfile();
}
/**
@@ -92,11 +117,7 @@ public class UserUtils {
if (Process.myUserHandle().equals(user)) {
return context;
} else {
- try {
- return context.createPackageContextAsUser(context.getPackageName(), 0, user);
- } catch (PackageManager.NameNotFoundException doesNotHappen) {
- throw new IllegalStateException(doesNotHappen);
- }
+ return context.createContextAsUser(user, 0);
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/SafetyCenterConstants.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/SafetyCenterConstants.java
new file mode 100644
index 000000000..cf96967ff
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/SafetyCenterConstants.java
@@ -0,0 +1,46 @@
+/*
+ * 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.permissioncontroller.safetycenter;
+
+/** App-global constants */
+public class SafetyCenterConstants {
+ /**
+ * Key for the argument noting that it is the quick settings safety center dashboard fragment
+ */
+ public static final String QUICK_SETTINGS_SAFETY_CENTER_FRAGMENT =
+ "QUICK_SETTINGS_SAFETY_CENTER_FRAGMENT";
+
+ public static final String EXPAND_ISSUE_GROUP_QS_FRAGMENT_KEY =
+ "expand_issue_group_qs_fragment_key";
+
+ public static final String EXTRA_NAVIGATION_SOURCE = "navigation_source_intent_extra";
+
+ /** Intent extra indicating whether a subpage in Safety Center was opened from the homepage */
+ public static final String EXTRA_OPENED_FROM_HOMEPAGE = "opened_from_homepage_intent_extra";
+
+ /** Suffix used to identify a source in the Safety Center personal profile */
+ public static final String PERSONAL_PROFILE_SUFFIX = "personal";
+
+ /** Suffix used to identify a source in the Safety Center work profile */
+ public static final String WORK_PROFILE_SUFFIX = "work";
+
+ /** Intent extra representing the preference key of a search result */
+ public static final String EXTRA_SETTINGS_FRAGMENT_ARGS_KEY = ":settings:fragment_args_key";
+
+ /** Identifier for the group of privacy safety sources */
+ public static final String PRIVACY_SOURCES_GROUP_ID = "AndroidPrivacySources";
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/TEST_MAPPING b/PermissionController/src/com/android/permissioncontroller/safetycenter/TEST_MAPPING
index 3985e563c..3cad386bc 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/TEST_MAPPING
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/TEST_MAPPING
@@ -1,7 +1,7 @@
{
- "presubmit": [
+ "imports": [
{
- "name": "CtsSafetyCenterTestCases"
+ "path": "packages/modules/Permission/SafetyCenter"
}
]
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/package-info.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/package-info.java
new file mode 100644
index 000000000..48c750b81
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@NonNullByDefault
+package com.android.permissioncontroller.safetycenter;
+
+import com.android.safetycenter.annotations.NonNullByDefault;
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java
new file mode 100644
index 000000000..e959d20be
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java
@@ -0,0 +1,175 @@
+/*
+ * 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.permissioncontroller.safetycenter.service;
+
+import static android.app.job.JobScheduler.RESULT_SUCCESS;
+import static android.content.Intent.ACTION_BOOT_COMPLETED;
+import static android.safetycenter.SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED;
+import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_OTHER;
+import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_PERIODIC;
+
+import static com.android.permissioncontroller.Constants.SAFETY_CENTER_BACKGROUND_REFRESH_JOB_ID;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.safetycenter.SafetyCenterManager;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import com.android.modules.utils.build.SdkLevel;
+
+/**
+ * Uses {@link android.app.job.JobScheduler} to schedule periodic calls to {@link
+ * SafetyCenterManager#refreshSafetySources} after boot completed if safety center is already
+ * enabled, or after safety center is enabled otherwise.
+ *
+ * <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";
+
+ /** Schedules a periodic background refresh. */
+ public static final class SetupSafetyCenterBackgroundRefreshReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ schedulePeriodicBackgroundRefresh(context, intent.getAction());
+ }
+ }
+
+ /**
+ * Schedules a periodic call to {@link SafetyCenterManager#refreshSafetySources} to be run when
+ * the device is idle, after either {@link android.content.Intent#ACTION_BOOT_COMPLETED} or
+ * {@link android.safetycenter.SafetyCenterManager#ACTION_SAFETY_CENTER_ENABLED_CHANGED}.
+ *
+ * <p>The {@link SafetyCenterManager#isSafetyCenterEnabled} check ensures that jobs are never
+ * scheduled if SafetyCenter is disabled, we check again in {@link
+ * SafetyCenterBackgroundRefreshJobService#onStartJob} in case SafetyCenter becomes disabled
+ * later.
+ *
+ * <p>{@link SafetyCenterJobServiceFlags#areBackgroundRefreshesEnabled} is only checked in
+ * {@link SafetyCenterBackgroundRefreshJobService#onStartJob} as we do not receive a new
+ * broadcast if this flag gets enabled.
+ */
+ private static void schedulePeriodicBackgroundRefresh(
+ Context context, @Nullable String actionString) {
+
+ if (!isActionStringValid(actionString)) {
+ Log.v(TAG, "Ignoring a " + actionString + " broadcast.");
+ return;
+ }
+
+ SafetyCenterManager safetyCenterManager =
+ context.getSystemService(SafetyCenterManager.class);
+ if (safetyCenterManager == null) {
+ Log.w(TAG, "SafetyCenterManager is null, cannot schedule background refresh.");
+ return;
+ }
+
+ JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+ if (jobScheduler == null) {
+ Log.w(TAG, "JobScheduler is null, cannot schedule background refresh.");
+ return;
+ }
+
+ if (!safetyCenterManager.isSafetyCenterEnabled()) {
+ Log.v(
+ TAG,
+ "Received a "
+ + actionString
+ + " broadcast, but safety center is currently disabled. Cancelling any"
+ + " existing job.");
+ jobScheduler.cancel(SAFETY_CENTER_BACKGROUND_REFRESH_JOB_ID);
+ return;
+ }
+
+ 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())
+ .build();
+
+ Log.v(
+ TAG,
+ "Scheduling a periodic background refresh with "
+ + ", interval="
+ + jobInfo.getIntervalMillis()
+ + "requires charging="
+ + jobInfo.isRequireCharging());
+
+ int scheduleResult = jobScheduler.schedule(jobInfo);
+ if (scheduleResult != RESULT_SUCCESS) {
+ Log.e(
+ TAG,
+ "Could not schedule the background refresh job, scheduleResult="
+ + scheduleResult);
+ }
+ }
+
+ @Override
+ 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.");
+ return false; // job is no longer running
+ }
+ SafetyCenterManager safetyCenterManager = this.getSystemService(SafetyCenterManager.class);
+ if (safetyCenterManager == null) {
+ Log.w(TAG, "Safety center manager is null, skipping job.");
+ return false; // job is no longer running
+ }
+ if (!safetyCenterManager.isSafetyCenterEnabled()) {
+ Log.v(TAG, "Safety center is not enabled, skipping job.");
+ return false; // job is no longer running
+ }
+
+ Log.v(TAG, "Background refresh job has started.");
+ safetyCenterManager.refreshSafetySources(getRefreshReason());
+ return false; // job is no longer running
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ return false; // never want job to be rescheduled
+ }
+
+ private static boolean isActionStringValid(@Nullable String actionString) {
+ return ACTION_BOOT_COMPLETED.equals(actionString)
+ || ACTION_SAFETY_CENTER_ENABLED_CHANGED.equals(actionString);
+ }
+
+ private static int getRefreshReason() {
+ if (SdkLevel.isAtLeastU()) {
+ return REFRESH_REASON_PERIODIC;
+ }
+ return REFRESH_REASON_OTHER;
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterJobServiceFlags.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterJobServiceFlags.java
new file mode 100644
index 000000000..bdca4d77d
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterJobServiceFlags.java
@@ -0,0 +1,61 @@
+/*
+ * 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.permissioncontroller.safetycenter.service;
+
+import android.app.job.JobService;
+import android.provider.DeviceConfig;
+
+import java.time.Duration;
+
+/** A class so that the Safety Center {@link JobService} can access {@link DeviceConfig} flags. */
+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";
+
+ /** Returns whether background refreshes should be enabled. */
+ static boolean areBackgroundRefreshesEnabled() {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_BACKGROUND_REFRESH_IS_ENABLED, true);
+ }
+
+ /**
+ * Returns the interval that should be used when scheduling periodic background refresh jobs.
+ */
+ static Duration getPeriodicBackgroundRefreshInterval() {
+ return Duration.ofMillis(
+ DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ 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
new file mode 100644
index 000000000..8e5e63452
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterSearchIndexablesProvider.kt
@@ -0,0 +1,336 @@
+/*
+ * 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.permissioncontroller.safetycenter.service
+
+import android.content.Context
+import android.content.Intent
+import android.content.res.Resources
+import android.database.Cursor
+import android.database.MatrixCursor
+import android.os.Build
+import android.os.UserManager
+import android.provider.SearchIndexablesContract.INDEXABLES_RAW_COLUMNS
+import android.provider.SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS
+import android.provider.SearchIndexablesContract.NonIndexableKey
+import android.provider.SearchIndexablesContract.RawData.COLUMN_INTENT_ACTION
+import android.provider.SearchIndexablesContract.RawData.COLUMN_KEY
+import android.provider.SearchIndexablesContract.RawData.COLUMN_KEYWORDS
+import android.provider.SearchIndexablesContract.RawData.COLUMN_RANK
+import android.provider.SearchIndexablesContract.RawData.COLUMN_SCREEN_TITLE
+import android.provider.SearchIndexablesContract.RawData.COLUMN_TITLE
+import android.safetycenter.SafetyCenterEntry
+import android.safetycenter.SafetyCenterEntryOrGroup
+import android.safetycenter.SafetyCenterManager
+import android.safetycenter.config.SafetySource
+import android.safetycenter.config.SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY
+import android.safetycenter.config.SafetySourcesGroup
+import android.safetycenter.config.SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_HIDDEN
+import android.safetycenter.config.SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATEFUL
+import android.safetycenter.config.SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATELESS
+import androidx.annotation.RequiresApi
+import com.android.modules.utils.build.SdkLevel
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.service.BaseSearchIndexablesProvider
+import com.android.permissioncontroller.safetycenter.SafetyCenterConstants.PERSONAL_PROFILE_SUFFIX
+import com.android.permissioncontroller.safetycenter.SafetyCenterConstants.WORK_PROFILE_SUFFIX
+import com.android.permissioncontroller.safetycenter.ui.SafetyCenterUiFlags
+import com.android.permissioncontroller.safetycenter.ui.model.PrivacyControlsViewModel.Pref
+import com.android.safetycenter.internaldata.SafetyCenterBundles
+import com.android.safetycenter.internaldata.SafetyCenterEntryId
+import com.android.safetycenter.internaldata.SafetyCenterIds
+import com.android.safetycenter.resources.SafetyCenterResourcesContext
+
+/** [android.provider.SearchIndexablesProvider] for Safety Center. */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class SafetyCenterSearchIndexablesProvider : BaseSearchIndexablesProvider() {
+
+ override fun queryRawData(projection: Array<out String>?): Cursor {
+ val cursor = MatrixCursor(INDEXABLES_RAW_COLUMNS)
+ if (!SdkLevel.isAtLeastT()) {
+ return cursor
+ }
+
+ val context = requireContext()
+ val safetyCenterManager =
+ context.getSystemService(SafetyCenterManager::class.java) ?: return cursor
+ val resourcesContext = SafetyCenterResourcesContext(context)
+
+ val screenTitle = context.getString(R.string.safety_center_dashboard_page_title)
+
+ safetyCenterManager.safetySourcesGroupsWithEntries.forEach { safetySourcesGroup ->
+ if (
+ SdkLevel.isAtLeastU() &&
+ safetySourcesGroup.type == SAFETY_SOURCES_GROUP_TYPE_STATEFUL
+ ) {
+ cursor.addSafetySourcesGroupRow(safetySourcesGroup, resourcesContext, screenTitle)
+ }
+ safetySourcesGroup.safetySources
+ .asSequence()
+ .filter { it.type != SAFETY_SOURCE_TYPE_ISSUE_ONLY }
+ .forEach { safetySource ->
+ cursor.addSafetySourceRow(
+ context,
+ safetySource,
+ resourcesContext,
+ safetyCenterManager,
+ screenTitle
+ )
+ }
+ }
+
+ if (SdkLevel.isAtLeastU()) {
+ cursor.indexPrivacyControls(context, screenTitle)
+ }
+ return cursor
+ }
+
+ override fun queryNonIndexableKeys(projection: Array<out String>?): Cursor {
+ val cursor = MatrixCursor(NON_INDEXABLES_KEYS_COLUMNS)
+ if (!SdkLevel.isAtLeastT()) {
+ return cursor
+ }
+
+ val context = requireContext()
+ val safetyCenterManager =
+ context.getSystemService(SafetyCenterManager::class.java) ?: return cursor
+ val userManager = context.getSystemService(UserManager::class.java) ?: return cursor
+ val keysToRemove = mutableSetOf<String>()
+
+ if (safetyCenterManager.isSafetyCenterEnabled) {
+ // SafetyCenterStaticEntry doesn't provide an ID, so we never remove these entries from
+ // search as we have no way to know if they're actually surfaced in the UI on T.
+ // On U+, we implemented a workaround that provides an ID for these entries using
+ // SafetyCenterData#getExtras().
+ collectAllRemovableKeys(
+ safetyCenterManager,
+ keysToRemove,
+ staticEntryGroupsAreRemovable = SdkLevel.isAtLeastU()
+ )
+ keepActiveEntriesFromRemoval(safetyCenterManager, userManager, keysToRemove)
+ } else {
+ collectAllRemovableKeys(
+ safetyCenterManager,
+ keysToRemove,
+ staticEntryGroupsAreRemovable = true
+ )
+ }
+
+ if (shouldRemovePrivacyControlKeys(safetyCenterManager)) {
+ keysToRemove.addAll(privacyControlKeys)
+ }
+
+ keysToRemove.forEach { key -> cursor.newRow().add(NonIndexableKey.COLUMN_KEY_VALUE, key) }
+ return cursor
+ }
+
+ private fun MatrixCursor.addSafetySourcesGroupRow(
+ safetySourcesGroups: SafetySourcesGroup,
+ resourcesContext: SafetyCenterResourcesContext,
+ screenTitle: String,
+ ) {
+ val groupTitle =
+ resourcesContext.getNotEmptyStringOrNull(safetySourcesGroups.titleResId) ?: return
+
+ newRow()
+ .add(COLUMN_RANK, 0)
+ .add(COLUMN_TITLE, groupTitle)
+ .add(COLUMN_KEYWORDS, groupTitle)
+ .add(COLUMN_KEY, safetySourcesGroups.id)
+ .add(COLUMN_INTENT_ACTION, Intent.ACTION_SAFETY_CENTER)
+ .add(COLUMN_SCREEN_TITLE, screenTitle)
+ }
+
+ private fun MatrixCursor.addSafetySourceRow(
+ context: Context,
+ safetySource: SafetySource,
+ resourcesContext: SafetyCenterResourcesContext,
+ safetyCenterManager: SafetyCenterManager,
+ screenTitle: String,
+ ) {
+ val searchTerms = resourcesContext.getNotEmptyStringOrNull(safetySource.searchTermsResId)
+ var isPersonalEntryAdded = false
+ var isWorkEntryAdded = false
+
+ fun MatrixCursor.addIndexableRow(title: CharSequence, isWorkProfile: Boolean) =
+ newRow()
+ .add(COLUMN_RANK, 0)
+ .add(COLUMN_TITLE, title)
+ .add(COLUMN_KEYWORDS, searchTerms?.let { "$title, $it" } ?: title)
+ .add(COLUMN_KEY, safetySource.id.addSuffix(isWorkProfile))
+ .add(COLUMN_INTENT_ACTION, Intent.ACTION_SAFETY_CENTER)
+ .add(COLUMN_SCREEN_TITLE, screenTitle)
+
+ if (safetySource.id == BIOMETRIC_SOURCE_ID) {
+ // correct Biometric Unlock title is only available when
+ // Biometric SafetySource have sent the data to SafetyCenter
+ context.getSystemService(UserManager::class.java)?.let { userManager ->
+ safetyCenterManager.safetyEntries
+ .associateBy { it.entryId }
+ .filter { it.key.safetySourceId == BIOMETRIC_SOURCE_ID }
+ .forEach {
+ val isWorkProfile = userManager.isManagedProfile(it.key.userId)
+ if (isWorkProfile) {
+ isWorkEntryAdded = true
+ } else {
+ isPersonalEntryAdded = true
+ }
+ addIndexableRow(it.value.title, isWorkProfile)
+ }
+ }
+ }
+
+ if (!isPersonalEntryAdded) {
+ resourcesContext.getNotEmptyStringOrNull(safetySource.titleResId)?.let {
+ addIndexableRow(title = it, isWorkProfile = false)
+ }
+ }
+
+ if (!isWorkEntryAdded && safetySource.profile == SafetySource.PROFILE_ALL) {
+ resourcesContext.getNotEmptyStringOrNull(safetySource.titleForWorkResId)?.let {
+ addIndexableRow(title = it, isWorkProfile = true)
+ }
+ }
+ }
+
+ private fun Context.getNotEmptyStringOrNull(resId: Int): String? =
+ if (resId != Resources.ID_NULL) {
+ getString(resId).takeIf { it.isNotEmpty() }
+ } else {
+ null
+ }
+
+ private fun String.addSuffix(isWorkProfile: Boolean): String =
+ "${this}_${if (isWorkProfile) WORK_PROFILE_SUFFIX else PERSONAL_PROFILE_SUFFIX}"
+
+ private val SafetyCenterManager.safetySourcesGroupsWithEntries: Sequence<SafetySourcesGroup>
+ get() =
+ safetyCenterConfig?.safetySourcesGroups?.asSequence()?.filter {
+ it.type != SAFETY_SOURCES_GROUP_TYPE_HIDDEN
+ }
+ ?: emptySequence()
+
+ private fun collectAllRemovableKeys(
+ safetyCenterManager: SafetyCenterManager,
+ keysToRemove: MutableSet<String>,
+ staticEntryGroupsAreRemovable: Boolean
+ ) {
+ safetyCenterManager.safetySourcesGroupsWithEntries
+ .filter {
+ it.type != SAFETY_SOURCES_GROUP_TYPE_STATELESS || staticEntryGroupsAreRemovable
+ }
+ .forEach { safetySourcesGroup ->
+ if (
+ SdkLevel.isAtLeastU() &&
+ safetySourcesGroup.type == SAFETY_SOURCES_GROUP_TYPE_STATEFUL
+ ) {
+ keysToRemove.add(safetySourcesGroup.id)
+ }
+ safetySourcesGroup.safetySources
+ .asSequence()
+ .filter { it.type != SAFETY_SOURCE_TYPE_ISSUE_ONLY }
+ .forEach { safetySource ->
+ keysToRemove.add(safetySource.id.addSuffix(isWorkProfile = false))
+ if (safetySource.profile == SafetySource.PROFILE_ALL) {
+ keysToRemove.add(safetySource.id.addSuffix(isWorkProfile = true))
+ }
+ }
+ }
+ }
+
+ private fun keepActiveEntriesFromRemoval(
+ safetyCenterManager: SafetyCenterManager,
+ userManager: UserManager,
+ keysToRemove: MutableSet<String>
+ ) {
+ val safetyCenterData = safetyCenterManager.safetyCenterData
+ safetyCenterData.entriesOrGroups.forEach { entryOrGroup ->
+ val entryGroup = entryOrGroup.entryGroup
+ if (entryGroup != null && SafetyCenterUiFlags.getShowSubpages()) {
+ keysToRemove.remove(entryGroup.id)
+ }
+ entryOrGroup.entries.forEach {
+ keepEntryFromRemoval(it.entryId, userManager, keysToRemove)
+ }
+ }
+ if (!SdkLevel.isAtLeastU()) {
+ return
+ }
+ safetyCenterData.staticEntryGroups
+ .asSequence()
+ .flatMap { it.staticEntries.asSequence() }
+ .forEach { staticEntry ->
+ val entryId = SafetyCenterBundles.getStaticEntryId(safetyCenterData, staticEntry)
+ if (entryId != null) {
+ keepEntryFromRemoval(entryId, userManager, keysToRemove)
+ }
+ }
+ }
+
+ private fun keepEntryFromRemoval(
+ entryId: SafetyCenterEntryId,
+ userManager: UserManager,
+ keysToRemove: MutableSet<String>
+ ) {
+ val isWorkProfile = userManager.isManagedProfile(entryId.userId)
+ keysToRemove.remove(entryId.safetySourceId.addSuffix(isWorkProfile))
+ }
+
+ private val SafetyCenterManager.safetyEntriesOrGroups: Sequence<SafetyCenterEntryOrGroup>
+ get() = safetyCenterData.entriesOrGroups.asSequence()
+
+ private val SafetyCenterManager.safetyEntries: Sequence<SafetyCenterEntry>
+ get() = safetyEntriesOrGroups.flatMap { it.entries }
+
+ private val SafetyCenterEntryOrGroup.entries: Sequence<SafetyCenterEntry>
+ get() =
+ entryGroup?.entries?.asSequence() ?: entry?.let { sequenceOf(it) } ?: emptySequence()
+
+ private val SafetyCenterEntry.entryId: SafetyCenterEntryId
+ get() = SafetyCenterIds.entryIdFromString(id)
+
+ companion object {
+ private const val BIOMETRIC_SOURCE_ID = "AndroidBiometrics"
+
+ private val privacyControlKeys: List<String>
+ get() = Pref.values().map { it.key }
+
+ private fun MatrixCursor.indexPrivacyControls(context: Context, screenTitle: String) {
+ for (pref in Pref.values()) {
+ val preferenceTitle = context.getString(pref.titleResId)
+ newRow()
+ .add(COLUMN_RANK, 0)
+ .add(COLUMN_TITLE, preferenceTitle)
+ .add(COLUMN_KEY, pref.key)
+ .add(COLUMN_KEYWORDS, preferenceTitle)
+ .add(COLUMN_INTENT_ACTION, Intent.ACTION_SAFETY_CENTER)
+ .add(COLUMN_SCREEN_TITLE, screenTitle)
+ }
+ }
+
+ private fun shouldRemovePrivacyControlKeys(
+ safetyCenterManager: SafetyCenterManager
+ ): Boolean {
+ if (!SdkLevel.isAtLeastU()) {
+ // The keys were never added in the first place, no need to remove.
+ return false
+ }
+ val safetyCenterDisabled = !safetyCenterManager.isSafetyCenterEnabled
+ val subpagesDisabled = !SafetyCenterUiFlags.getShowSubpages()
+ return safetyCenterDisabled || subpagesDisabled
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/service/package-info.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/service/package-info.java
new file mode 100644
index 000000000..d6b130cf3
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/service/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@NonNullByDefault
+package com.android.permissioncontroller.safetycenter.service;
+
+import com.android.safetycenter.annotations.NonNullByDefault;
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ClickableDisabledSwitchPreference.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ClickableDisabledSwitchPreference.java
new file mode 100644
index 000000000..79fc41249
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ClickableDisabledSwitchPreference.java
@@ -0,0 +1,123 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui;
+
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.RequiresApi;
+import androidx.fragment.app.Fragment;
+import androidx.preference.PreferenceViewHolder;
+import androidx.preference.SwitchPreference;
+
+import com.android.permissioncontroller.R;
+import com.android.permissioncontroller.safetycenter.ui.model.PrivacyControlsViewModel;
+import com.android.permissioncontroller.safetycenter.ui.model.PrivacyControlsViewModel.Pref;
+import com.android.permissioncontroller.safetycenter.ui.model.PrivacyControlsViewModel.PrefState;
+
+/**
+ * A preference that can be set to appear disabled, but remain clickable. However, the setChecked
+ * method will not register any changes while it appears disabled.
+ */
+@RequiresApi(TIRAMISU)
+public class ClickableDisabledSwitchPreference extends SwitchPreference {
+
+ private boolean mAppearDisabled;
+
+ public ClickableDisabledSwitchPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public ClickableDisabledSwitchPreference(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+ if (holder.itemView instanceof ViewGroup) {
+ applyEnableStateToChildren((ViewGroup) holder.itemView);
+ }
+ }
+
+ @Override
+ public void setChecked(boolean checked) {
+ if (mAppearDisabled) {
+ return;
+ }
+ super.setChecked(checked);
+ }
+
+ /**
+ * Set this preference to appear disabled. It will remain clickable, but will be frozen in its
+ * current checked state.
+ */
+ private void setAppearDisabled(boolean appearDisabled) {
+ if (appearDisabled == mAppearDisabled) {
+ return;
+ }
+ mAppearDisabled = appearDisabled;
+ notifyChanged();
+ }
+
+ private void applyEnableStateToChildren(ViewGroup viewGroup) {
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
+ View child = viewGroup.getChildAt(i);
+ child.setEnabled(!mAppearDisabled);
+ if (child instanceof ViewGroup) {
+ applyEnableStateToChildren((ViewGroup) child);
+ }
+ }
+ }
+
+ /**
+ * Sets the state of this switch preference based on restrictions enforced by the admin
+ *
+ * @param prefState a map of the preferences and their current toggle state
+ * @param prefType represents the type of privacy control toggle
+ * @param viewModel model used to talk to the backing service
+ * @param fragment represents the fragment containing this preference
+ */
+ public void setupState(
+ PrefState prefState,
+ Pref prefType,
+ PrivacyControlsViewModel viewModel,
+ Fragment fragment) {
+ setVisible(prefState.getVisible());
+ setChecked(prefState.getChecked());
+ setAppearDisabled(prefState.getAdmin() != null);
+ setOnPreferenceClickListener(
+ (v) -> {
+ viewModel.handlePrefClick(fragment, prefType, prefState.getAdmin());
+ return true;
+ });
+
+ if (prefState.getAdmin() != null && prefState.getChecked()) {
+ setSummary(R.string.enabled_by_admin);
+ } else if (prefState.getAdmin() != null) {
+ setSummary(R.string.disabled_by_admin);
+ } else if (prefType.equals(Pref.MIC)) {
+ setSummary(R.string.mic_toggle_description);
+ } else if (prefType.equals(Pref.CAMERA)) {
+ setSummary(R.string.perm_toggle_description);
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/CollapsableGroupCardHelper.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/CollapsableGroupCardHelper.kt
new file mode 100644
index 000000000..cdc5cc1f3
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/CollapsableGroupCardHelper.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.permissioncontroller.safetycenter.ui
+
+import android.os.Build
+import android.os.Bundle
+import androidx.annotation.RequiresApi
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+internal class CollapsableGroupCardHelper {
+
+ private val expandedGroups = mutableSetOf<CharSequence>()
+
+ private companion object {
+ private const val EXPANDED_ENTRY_GROUPS_SAVED_INSTANCE_STATE_KEY =
+ "expanded_entry_groups_saved_instance_state_key"
+ }
+
+ fun restoreState(state: Bundle?) {
+ state?.getCharSequenceArray(EXPANDED_ENTRY_GROUPS_SAVED_INSTANCE_STATE_KEY)?.let {
+ expandedGroups.clear()
+ expandedGroups.addAll(it)
+ }
+ }
+
+ fun saveState(outState: Bundle) {
+ outState.putCharSequenceArray(
+ EXPANDED_ENTRY_GROUPS_SAVED_INSTANCE_STATE_KEY,
+ expandedGroups.toTypedArray()
+ )
+ }
+
+ fun onGroupCollapsed(groupId: String) {
+ expandedGroups.remove(groupId)
+ }
+
+ fun onGroupExpanded(groupId: String) {
+ expandedGroups.add(groupId)
+ }
+
+ fun isGroupExpanded(groupId: CharSequence): Boolean =
+ expandedGroups.contains(groupId)
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/CollapsableIssuesCardHelper.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/CollapsableIssuesCardHelper.kt
new file mode 100644
index 000000000..149503c70
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/CollapsableIssuesCardHelper.kt
@@ -0,0 +1,463 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui
+
+import android.content.Context
+import android.content.Intent
+import android.content.Intent.ACTION_SAFETY_CENTER
+import android.os.Build
+import android.os.Bundle
+import android.safetycenter.SafetyCenterIssue
+import android.safetycenter.SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK
+import androidx.annotation.RequiresApi
+import androidx.fragment.app.FragmentManager
+import androidx.preference.PreferenceGroup
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.safetycenter.SafetyCenterConstants.EXPAND_ISSUE_GROUP_QS_FRAGMENT_KEY
+import com.android.permissioncontroller.safetycenter.ui.model.ActionId
+import com.android.permissioncontroller.safetycenter.ui.model.IssueId
+import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterViewModel
+import com.android.safetycenter.internaldata.SafetyCenterIds
+import com.android.safetycenter.internaldata.SafetyCenterIssueKey
+import kotlin.math.max
+
+/**
+ * Helper class to hide issue cards if over a predefined limit and handle revealing hidden issue
+ * cards when the more issues preference is clicked
+ */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class CollapsableIssuesCardHelper(
+ val safetyCenterViewModel: SafetyCenterViewModel,
+ val sameTaskIssueIds: List<String>
+) {
+ private var isQuickSettingsFragment: Boolean = false
+ private var issueCardsExpanded: Boolean = false
+ private var focusedSafetyCenterIssueKey: SafetyCenterIssueKey? = null
+ private var previousMoreIssuesCardData: MoreIssuesCardData? = null
+
+ fun setFocusedIssueKey(safetyCenterIssueKey: SafetyCenterIssueKey?) {
+ focusedSafetyCenterIssueKey = safetyCenterIssueKey
+ }
+
+ /**
+ * Sets QuickSetting specific state for use to determine correct issue section expansion state
+ * as well ass more issues card icon values
+ *
+ * <p> Note the issueCardsExpanded value set here may be overridden here by calls to
+ * restoreState
+ *
+ * @param isQuickSettingsFragment {@code true} if CollapsableIssuesCardHelper is being used in
+ * quick settings fragment
+ * @param issueCardsExpanded Whether issue cards should be expanded or not when added to
+ * preference screen
+ */
+ fun setQuickSettingsState(isQuickSettingsFragment: Boolean, issueCardsExpanded: Boolean) {
+ this.isQuickSettingsFragment = isQuickSettingsFragment
+ this.issueCardsExpanded = issueCardsExpanded
+ }
+
+ /** Restore previously saved state from [Bundle] */
+ fun restoreState(state: Bundle?) {
+ if (state == null) {
+ return
+ }
+ // Apply the previously saved state
+ issueCardsExpanded = state.getBoolean(EXPAND_ISSUE_GROUP_SAVED_INSTANCE_STATE_KEY, false)
+ }
+
+ /** Save current state to provided [Bundle] */
+ fun saveState(outState: Bundle) =
+ outState.putBoolean(EXPAND_ISSUE_GROUP_SAVED_INSTANCE_STATE_KEY, issueCardsExpanded)
+
+ /**
+ * Add the [IssueCardPreference] managed by this helper to the specified [PreferenceGroup]
+ *
+ * @param context Current context
+ * @param safetyCenterViewModel {@link SafetyCenterViewModel} used when executing issue actions
+ * @param dialogFragmentManager fragment manager use for issue dismissal
+ * @param issuesPreferenceGroup Preference group to add preference to
+ * @param issues {@link List} of {@link SafetyCenterIssue} to add to the preference fragment
+ * @param dismissedIssues {@link List} of dismissed {@link SafetyCenterIssue} to add
+ * @param resolvedIssues {@link Map} of issue id to action ids of resolved issues
+ */
+ fun addIssues(
+ context: Context,
+ safetyCenterViewModel: SafetyCenterViewModel,
+ dialogFragmentManager: FragmentManager,
+ issuesPreferenceGroup: PreferenceGroup,
+ issues: List<SafetyCenterIssue>?,
+ dismissedIssues: List<SafetyCenterIssue>?,
+ resolvedIssues: Map<IssueId, ActionId>,
+ launchTaskId: Int
+ ) {
+ val (reorderedIssues, numberOfIssuesToShowWhenCollapsed) =
+ maybeReorderFocusedSafetyCenterIssueInList(issues)
+
+ val onlyDismissedIssuesAreCollapsed =
+ reorderedIssues.size <= numberOfIssuesToShowWhenCollapsed
+
+ val issueCardPreferences: List<IssueCardPreference> =
+ reorderedIssues.mapToIssueCardPreferences(
+ resolvedIssues,
+ launchTaskId,
+ context,
+ safetyCenterViewModel,
+ dialogFragmentManager,
+ areDismissed = false
+ ) { index ->
+ when (index) {
+ in 0 until numberOfIssuesToShowWhenCollapsed ->
+ PositionInCardList.LIST_START_END
+ this.size - 1 -> PositionInCardList.CARD_START_LIST_END
+ else -> PositionInCardList.CARD_START_END
+ }
+ }
+
+ val dismissedIssueCardPreferences: List<IssueCardPreference> =
+ dismissedIssues.mapToIssueCardPreferences(
+ resolvedIssues,
+ launchTaskId,
+ context,
+ safetyCenterViewModel,
+ dialogFragmentManager,
+ areDismissed = true
+ ) { index ->
+ when {
+ onlyDismissedIssuesAreCollapsed && index == size - 1 ->
+ PositionInCardList.CARD_START_LIST_END
+ onlyDismissedIssuesAreCollapsed -> PositionInCardList.CARD_START_END
+ size == 1 -> PositionInCardList.LIST_START_END
+ index == 0 -> PositionInCardList.LIST_START_CARD_END
+ index == size - 1 -> PositionInCardList.CARD_START_LIST_END
+ else -> PositionInCardList.CARD_START_END
+ }
+ }
+
+ val nextMoreIssuesCardData =
+ createMoreIssuesCardData(
+ issueCardPreferences,
+ dismissedIssueCardPreferences,
+ numberOfIssuesToShowWhenCollapsed
+ )
+
+ val moreIssuesCardPreference =
+ createMoreIssuesCardPreference(
+ context,
+ dismissedOnly = onlyDismissedIssuesAreCollapsed,
+ staticHeader = false,
+ issuesPreferenceGroup,
+ previousMoreIssuesCardData,
+ nextMoreIssuesCardData,
+ numberOfIssuesToShowWhenCollapsed
+ )
+
+ val dismissedIssuesHeaderCardPreference =
+ if (!onlyDismissedIssuesAreCollapsed && dismissedIssueCardPreferences.isNotEmpty()) {
+ createMoreIssuesCardPreference(
+ context,
+ dismissedOnly = false,
+ staticHeader = true,
+ issuesPreferenceGroup,
+ previousMoreIssuesCardData,
+ nextMoreIssuesCardData,
+ numberOfIssuesToShowWhenCollapsed
+ )
+ } else {
+ null
+ }
+
+ // Keep track of previously presented more issues data to assist with transitions
+ previousMoreIssuesCardData = nextMoreIssuesCardData
+
+ addIssuesToPreferenceGroupAndSetVisibility(
+ issuesPreferenceGroup,
+ issueCardPreferences,
+ dismissedIssueCardPreferences,
+ moreIssuesCardPreference,
+ dismissedIssuesHeaderCardPreference,
+ numberOfIssuesToShowWhenCollapsed,
+ issueCardsExpanded
+ )
+ }
+
+ private fun List<SafetyCenterIssue>?.mapToIssueCardPreferences(
+ resolvedIssues: Map<IssueId, ActionId>,
+ launchTaskId: Int,
+ context: Context,
+ safetyCenterViewModel: SafetyCenterViewModel,
+ dialogFragmentManager: FragmentManager,
+ areDismissed: Boolean,
+ position: List<SafetyCenterIssue>.(index: Int) -> PositionInCardList
+ ): List<IssueCardPreference> =
+ this?.mapIndexed { index: Int, issue: SafetyCenterIssue ->
+ val resolvedActionId: ActionId? = resolvedIssues[issue.id]
+ val resolvedTaskId = getLaunchTaskIdForIssue(issue, launchTaskId)
+ val positionInCardList = position(index)
+ IssueCardPreference(
+ context,
+ safetyCenterViewModel,
+ issue,
+ resolvedActionId,
+ dialogFragmentManager,
+ resolvedTaskId,
+ areDismissed,
+ positionInCardList
+ )
+ }
+ ?: emptyList()
+
+ data class ReorderedSafetyCenterIssueList(
+ val issues: List<SafetyCenterIssue>,
+ val numberOfIssuesToShowWhenCollapsed: Int
+ )
+ private fun maybeReorderFocusedSafetyCenterIssueInList(
+ issues: List<SafetyCenterIssue>?
+ ): ReorderedSafetyCenterIssueList {
+ if (issues == null) {
+ return ReorderedSafetyCenterIssueList(
+ emptyList(),
+ numberOfIssuesToShowWhenCollapsed = 0
+ )
+ }
+ val mutableIssuesList = issues.toMutableList()
+ val focusedIssue: SafetyCenterIssue? =
+ focusedSafetyCenterIssueKey?.let { findAndRemoveIssueInList(it, mutableIssuesList) }
+
+ // If focused issue preference found, place at/near top of list and return new list and
+ // correct number of issue to show while collapsed
+ if (focusedIssue != null) {
+ val focusedIssuePlacement = getFocusedIssuePlacement(focusedIssue, mutableIssuesList)
+ mutableIssuesList.add(focusedIssuePlacement.index, focusedIssue)
+ return ReorderedSafetyCenterIssueList(
+ mutableIssuesList.toList(),
+ focusedIssuePlacement.numberForShownIssuesCollapsed
+ )
+ }
+
+ return ReorderedSafetyCenterIssueList(issues, DEFAULT_NUMBER_SHOWN_ISSUES_COLLAPSED)
+ }
+
+ private fun findAndRemoveIssueInList(
+ focusedIssueKey: SafetyCenterIssueKey,
+ issues: MutableList<SafetyCenterIssue>
+ ): SafetyCenterIssue? {
+ issues.forEachIndexed { index, issue ->
+ val issueKey = SafetyCenterIds.issueIdFromString(issue.id).safetyCenterIssueKey
+ if (focusedIssueKey == issueKey) {
+ // Remove focused issue from current placement in list and exit loop
+ issues.removeAt(index)
+ return issue
+ }
+ }
+
+ return null
+ }
+
+ /** Defines indices and number of shown issues for use when prioritizing focused issues */
+ private enum class FocusedIssuePlacement(
+ val index: Int,
+ val numberForShownIssuesCollapsed: Int
+ ) {
+ FOCUSED_ISSUE_INDEX_0(0, DEFAULT_NUMBER_SHOWN_ISSUES_COLLAPSED),
+ FOCUSED_ISSUE_INDEX_1(1, DEFAULT_NUMBER_SHOWN_ISSUES_COLLAPSED + 1)
+ }
+
+ private fun getFocusedIssuePlacement(
+ issue: SafetyCenterIssue,
+ issueList: List<SafetyCenterIssue>
+ ): FocusedIssuePlacement {
+ return if (issueList.isEmpty() || issueList[0].severityLevel <= issue.severityLevel) {
+ FocusedIssuePlacement.FOCUSED_ISSUE_INDEX_0
+ } else {
+ FocusedIssuePlacement.FOCUSED_ISSUE_INDEX_1
+ }
+ }
+
+ private fun createMoreIssuesCardData(
+ issueCardPreferences: List<IssueCardPreference>,
+ dismissedIssueCardPreferences: List<IssueCardPreference>,
+ numberOfIssuesToShowWhenCollapsed: Int
+ ): MoreIssuesCardData {
+ val numberOfHiddenIssue: Int =
+ getNumberOfHiddenIssues(
+ issueCardPreferences,
+ dismissedIssueCardPreferences,
+ numberOfIssuesToShowWhenCollapsed
+ )
+ val firstHiddenIssueSeverityLevel: Int =
+ if (issueCardPreferences.size <= numberOfIssuesToShowWhenCollapsed) {
+ getFirstHiddenIssueSeverityLevel(dismissedIssueCardPreferences, 0)
+ } else {
+ getFirstHiddenIssueSeverityLevel(
+ issueCardPreferences,
+ numberOfIssuesToShowWhenCollapsed
+ )
+ }
+
+ return MoreIssuesCardData(
+ firstHiddenIssueSeverityLevel,
+ numberOfHiddenIssue,
+ issueCardsExpanded
+ )
+ }
+
+ private fun createMoreIssuesCardPreference(
+ context: Context,
+ dismissedOnly: Boolean,
+ staticHeader: Boolean,
+ issuesPreferenceGroup: PreferenceGroup,
+ previousMoreIssuesCardData: MoreIssuesCardData?,
+ nextMoreIssuesCardData: MoreIssuesCardData,
+ numberOfIssuesToShowWhenCollapsed: Int
+ ): MoreIssuesCardPreference {
+ val overrideChevronIconResId =
+ if (isQuickSettingsFragment) R.drawable.ic_chevron_right else null
+
+ return MoreIssuesCardPreference(
+ context,
+ overrideChevronIconResId,
+ previousMoreIssuesCardData,
+ nextMoreIssuesCardData,
+ dismissedOnly,
+ staticHeader
+ ) {
+ if (isQuickSettingsFragment) {
+ goToSafetyCenter(context)
+ } else {
+ setExpanded(
+ issuesPreferenceGroup,
+ !issueCardsExpanded,
+ numberOfIssuesToShowWhenCollapsed
+ )
+ }
+ safetyCenterViewModel.interactionLogger.record(Action.MORE_ISSUES_CLICKED)
+ }
+ }
+
+ private fun setExpanded(
+ issuesPreferenceGroup: PreferenceGroup,
+ isExpanded: Boolean,
+ numberOfIssuesToShowWhenCollapsed: Int
+ ) {
+ if (issueCardsExpanded == isExpanded) {
+ return
+ }
+
+ val numberOfPreferences = issuesPreferenceGroup.preferenceCount
+ for (i in 0 until numberOfPreferences) {
+ when (val preference = issuesPreferenceGroup.getPreference(i)) {
+ // IssueCardPreference can all be visible now
+ is IssueCardPreference ->
+ preference.isVisible = isExpanded || i < numberOfIssuesToShowWhenCollapsed
+ // MoreIssuesCardPreference must be hidden after expansion of issues
+ is MoreIssuesCardPreference -> {
+ if (preference.isStaticHeader) {
+ preference.isVisible = isExpanded
+ } else {
+ previousMoreIssuesCardData?.let {
+ val newMoreIssuesCardData = it.copy(isExpanded = isExpanded)
+ preference.setNewMoreIssuesCardData(newMoreIssuesCardData)
+ previousMoreIssuesCardData = newMoreIssuesCardData
+ }
+ }
+ preference.isVisible = isExpanded || !preference.isStaticHeader
+ }
+ // Other types are undefined, no-op
+ else -> continue
+ }
+ }
+ issueCardsExpanded = isExpanded
+ }
+
+ private fun goToSafetyCenter(context: Context) {
+ // Navigate to Safety center with issues expanded
+ val safetyCenterIntent = Intent(ACTION_SAFETY_CENTER)
+ safetyCenterIntent.putExtra(EXPAND_ISSUE_GROUP_QS_FRAGMENT_KEY, true)
+ NavigationSource.QUICK_SETTINGS_TILE.addToIntent(safetyCenterIntent)
+ context.startActivity(safetyCenterIntent)
+ }
+
+ companion object {
+ private const val EXPAND_ISSUE_GROUP_SAVED_INSTANCE_STATE_KEY =
+ "expand_issue_group_saved_instance_state_key"
+ private const val DEFAULT_NUMBER_SHOWN_ISSUES_COLLAPSED = 1
+
+ private fun getNumberOfHiddenIssues(
+ issueCardPreferences: List<IssueCardPreference>,
+ dismissedIssueCardPreferences: List<IssueCardPreference>,
+ numberOfIssuesToShowWhenCollapsed: Int
+ ): Int =
+ max(0, issueCardPreferences.size - numberOfIssuesToShowWhenCollapsed) +
+ dismissedIssueCardPreferences.size
+
+ private fun getFirstHiddenIssueSeverityLevel(
+ issueCardPreferences: List<IssueCardPreference>,
+ numberOfIssuesToShowWhenCollapsed: Int
+ ): Int {
+ // Index of first hidden issue (zero based) is equal to number of shown issues when
+ // collapsed
+ val indexOfFirstHiddenIssue: Int = numberOfIssuesToShowWhenCollapsed
+ val firstHiddenIssue: IssueCardPreference? =
+ issueCardPreferences.getOrNull(indexOfFirstHiddenIssue)
+ // If no first hidden issue, default to ISSUE_SEVERITY_LEVEL_OK
+ return firstHiddenIssue?.severityLevel ?: ISSUE_SEVERITY_LEVEL_OK
+ }
+
+ private fun addIssuesToPreferenceGroupAndSetVisibility(
+ issuesPreferenceGroup: PreferenceGroup,
+ issueCardPreferences: List<IssueCardPreference>,
+ dismissedIssueCardPreferences: List<IssueCardPreference>,
+ moreIssuesCardPreference: MoreIssuesCardPreference,
+ dismissedIssuesHeaderPreference: MoreIssuesCardPreference?,
+ numberOfIssuesToShowWhenCollapsed: Int,
+ issueCardsExpanded: Boolean
+ ) {
+ // Index of first hidden issue (zero based) is equal to number of shown issues when
+ // collapsed
+ val indexOfFirstHiddenIssue: Int = numberOfIssuesToShowWhenCollapsed
+ issueCardPreferences.forEachIndexed { index, issueCardPreference ->
+ if (index == indexOfFirstHiddenIssue) {
+ issuesPreferenceGroup.addPreference(moreIssuesCardPreference)
+ }
+ issueCardPreference.isVisible =
+ index < indexOfFirstHiddenIssue || issueCardsExpanded
+ issuesPreferenceGroup.addPreference(issueCardPreference)
+ }
+ if (dismissedIssueCardPreferences.isNotEmpty()) {
+ if (issueCardPreferences.size <= numberOfIssuesToShowWhenCollapsed) {
+ issuesPreferenceGroup.addPreference(moreIssuesCardPreference)
+ }
+ dismissedIssuesHeaderPreference?.let {
+ it.isVisible = issueCardsExpanded
+ issuesPreferenceGroup.addPreference(it)
+ }
+ dismissedIssueCardPreferences.forEach {
+ it.isVisible = issueCardsExpanded
+ issuesPreferenceGroup.addPreference(it)
+ }
+ }
+ }
+ }
+
+ private fun getLaunchTaskIdForIssue(issue: SafetyCenterIssue, taskId: Int): Int? {
+ val issueId: String =
+ SafetyCenterIds.issueIdFromString(issue.id)
+ .getSafetyCenterIssueKey()
+ .getSafetySourceId()
+ return if (sameTaskIssueIds.contains(issueId)) taskId else null
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ComparablePreference.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ComparablePreference.kt
new file mode 100644
index 000000000..1950a0976
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ComparablePreference.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.permissioncontroller.safetycenter.ui
+
+import androidx.preference.Preference
+
+/** 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. */
+ fun isSameItem(preference: Preference): Boolean
+
+ /** 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
new file mode 100644
index 000000000..55d27dbb3
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ComparablePreferenceCategory.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui
+
+import android.content.Context
+import android.text.TextUtils
+import android.util.AttributeSet
+import android.util.TypedValue
+import androidx.preference.Preference
+import androidx.preference.PreferenceCategory
+import com.android.permissioncontroller.R
+
+/** A {@link PreferenceCategory} that implements {@link ComparablePreference} interface. */
+internal class ComparablePreferenceCategory @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = getAttr(
+ context,
+ R.attr.preferenceCategoryStyle,
+ android.R.attr.preferenceCategoryStyle),
+ defStyleRes: Int = 0
+) : PreferenceCategory(context, attrs, defStyleAttr, defStyleRes), ComparablePreference {
+
+ private companion object {
+ /* PreferenceCategory falls back to using TypedArrayUtils.getAttr()
+ * when no defStyleAttr is set. This method reuses the logic
+ * from library-private TypedArrayUtils. */
+ private fun getAttr(context: Context, attr: Int, fallbackAttr: Int): Int {
+ val value = TypedValue()
+ context.theme.resolveAttribute(attr, value, true)
+ return if (value.resourceId != 0) attr else fallbackAttr
+ }
+ }
+
+ override fun isSameItem(preference: Preference): Boolean =
+ preference is ComparablePreferenceCategory && TextUtils.equals(key, preference.key)
+
+ override fun hasSameContents(preference: Preference): Boolean =
+ preference is ComparablePreferenceCategory && TextUtils.equals(title, preference.title)
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/EqualWidthContainer.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/EqualWidthContainer.kt
new file mode 100644
index 000000000..6f56874eb
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/EqualWidthContainer.kt
@@ -0,0 +1,49 @@
+package com.android.permissioncontroller.safetycenter.ui
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View.MeasureSpec.EXACTLY
+import android.widget.LinearLayout
+import android.widget.Space
+import androidx.core.view.children
+
+/**
+ * A [LinearLayout] that requires all its children (except [Space]s) to be the same width. The
+ * layout is horizontal, unless the buttons don't fit in which case it moves to vertical.
+ *
+ * Assumes its children are all WRAP_CONTENT width and that it is some fixed width (either
+ * MATCH_PARENT or sized by constraint - not WRAP_CONTENT itself).
+ */
+class EqualWidthContainer @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
+ LinearLayout(context, attrs) {
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ // super.onMeasure will cause all children to be measured in the default way
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+
+ // Separate children into spaces and non-spaces
+ val (spaces, nonSpaceItems) = children.partition { it is Space }
+ val neededWidthPerNonSpaceItem =
+ try {
+ nonSpaceItems.maxOf { it.measuredWidth }
+ } catch (e: NoSuchElementException) {
+ 0
+ }
+ val neededWidth = neededWidthPerNonSpaceItem * nonSpaceItems.count()
+
+ // Switch between horizontal or vertical layout as needed
+ val availableWidth =
+ MeasureSpec.getSize(widthMeasureSpec) - spaces.sumOf { it.measuredWidth }
+ orientation = if (neededWidth <= availableWidth) HORIZONTAL else VERTICAL
+
+ // Measure again now orientation has changed
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+
+ // Re-measure all the children with EXACT width (using previously calculated height)
+ nonSpaceItems.forEach {
+ it.measure(
+ MeasureSpec.makeMeasureSpec(neededWidthPerNonSpaceItem, EXACTLY),
+ MeasureSpec.makeMeasureSpec(it.measuredHeight, EXACTLY))
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/HighlightablePreferenceGroupAdapter.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/HighlightablePreferenceGroupAdapter.java
new file mode 100644
index 000000000..c6cfa3a9a
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/HighlightablePreferenceGroupAdapter.java
@@ -0,0 +1,234 @@
+/*
+ * 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.safetycenter.ui;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ArgbEvaluator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.View;
+
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceGroupAdapter;
+import androidx.preference.PreferenceViewHolder;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.permissioncontroller.R;
+
+import com.google.android.material.appbar.AppBarLayout;
+
+/**
+ * {@link PreferenceGroupAdapter} used to scroll and highlight a search result. Note: this has been
+ * ported over from the Settings module, so refer to that before making any changes here.
+ *
+ * @see com.android.settings.widget.HighlightablePreferenceGroupAdapter
+ */
+public class HighlightablePreferenceGroupAdapter extends PreferenceGroupAdapter {
+
+ private static final String TAG = "HighlightableAdapter";
+ private static final long DELAY_COLLAPSE_DURATION_MILLIS = 300L;
+ private static final long DELAY_HIGHLIGHT_DURATION_MILLIS = 600L;
+ private static final long HIGHLIGHT_DURATION = 15000L;
+ private static final long HIGHLIGHT_FADE_OUT_DURATION = 500L;
+ private static final long HIGHLIGHT_FADE_IN_DURATION = 200L;
+
+ private final int mHighlightColor;
+ private boolean mFadeInAnimated;
+
+ private final int mNormalBackgroundRes;
+ private final String mHighlightKey;
+ private boolean mHighlightRequested;
+ private int mHighlightPosition = RecyclerView.NO_POSITION;
+
+ public HighlightablePreferenceGroupAdapter(
+ PreferenceGroup preferenceGroup, String key, boolean highlightRequested) {
+ super(preferenceGroup);
+ mHighlightKey = key;
+ mHighlightRequested = highlightRequested;
+ final Context context = preferenceGroup.getContext();
+ final TypedValue outValue = new TypedValue();
+ context.getTheme()
+ .resolveAttribute(
+ android.R.attr.selectableItemBackground, outValue, true /* resolveRefs */);
+ mNormalBackgroundRes = outValue.resourceId;
+ mHighlightColor = context.getColor(R.color.preference_highlight_color);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder, int position) {
+ super.onBindViewHolder(holder, position);
+ updateBackground(holder, position);
+ }
+
+ private void updateBackground(PreferenceViewHolder holder, int position) {
+ View v = holder.itemView;
+ if (position == mHighlightPosition
+ && (mHighlightKey != null
+ && TextUtils.equals(mHighlightKey, getItem(position).getKey()))) {
+ // This position should be highlighted. If it's highlighted before - skip animation.
+ addHighlightBackground(holder, !mFadeInAnimated);
+ } else if (Boolean.TRUE.equals(v.getTag(R.id.preference_highlighted))) {
+ // View with highlight is reused for a view that should not have highlight
+ removeHighlightBackground(holder, false /* animate */);
+ }
+ }
+
+ /**
+ * A function can highlight a specific setting in recycler view. note: Before highlighting a
+ * setting, screen collapses tool bar with an animation.
+ */
+ public void requestHighlight(View root, RecyclerView recyclerView, AppBarLayout appBarLayout) {
+ if (mHighlightRequested || recyclerView == null || TextUtils.isEmpty(mHighlightKey)) {
+ return;
+ }
+ final int position = getPreferenceAdapterPosition(mHighlightKey);
+ if (position < 0) {
+ return;
+ }
+
+ // Highlight request accepted
+ mHighlightRequested = true;
+ // Collapse app bar after 300 milliseconds.
+ if (appBarLayout != null) {
+ root.postDelayed(
+ () -> {
+ appBarLayout.setExpanded(false, true);
+ },
+ DELAY_COLLAPSE_DURATION_MILLIS);
+ }
+
+ // Remove the animator as early as possible to avoid a RecyclerView crash.
+ recyclerView.setItemAnimator(null);
+ // Scroll to correct position after 600 milliseconds.
+ root.postDelayed(
+ () -> {
+ if (ensureHighlightPosition()) {
+ recyclerView.smoothScrollToPosition(mHighlightPosition);
+ }
+ },
+ DELAY_HIGHLIGHT_DURATION_MILLIS);
+
+ // Highlight preference after 900 milliseconds.
+ root.postDelayed(
+ () -> {
+ if (ensureHighlightPosition()) {
+ notifyItemChanged(mHighlightPosition);
+ }
+ },
+ DELAY_COLLAPSE_DURATION_MILLIS + DELAY_HIGHLIGHT_DURATION_MILLIS);
+ }
+
+ /**
+ * Make sure we highlight the real-wanted position in case of preference position already
+ * changed when the delay time comes.
+ */
+ private boolean ensureHighlightPosition() {
+ if (TextUtils.isEmpty(mHighlightKey)) {
+ return false;
+ }
+ final int position = getPreferenceAdapterPosition(mHighlightKey);
+ final boolean allowHighlight = position >= 0;
+ if (allowHighlight && mHighlightPosition != position) {
+ Log.w(TAG, "EnsureHighlight: position has changed since last highlight request");
+ // Make sure RecyclerView always uses latest correct position to avoid exceptions.
+ mHighlightPosition = position;
+ }
+ return allowHighlight;
+ }
+
+ public boolean isHighlightRequested() {
+ return mHighlightRequested;
+ }
+
+ /** Remove the highlighted background with a delay */
+ public void requestRemoveHighlightDelayed(PreferenceViewHolder holder) {
+ final View v = holder.itemView;
+ v.postDelayed(
+ () -> {
+ mHighlightPosition = RecyclerView.NO_POSITION;
+ removeHighlightBackground(holder, true /* animate */);
+ },
+ HIGHLIGHT_DURATION);
+ }
+
+ private void addHighlightBackground(PreferenceViewHolder holder, boolean animate) {
+ final View v = holder.itemView;
+ v.setTag(R.id.preference_highlighted, true);
+ if (!animate) {
+ v.setBackgroundColor(mHighlightColor);
+ Log.d(TAG, "AddHighlight: Not animation requested - setting highlight background");
+ requestRemoveHighlightDelayed(holder);
+ return;
+ }
+ mFadeInAnimated = true;
+ final int colorFrom = mNormalBackgroundRes;
+ final int colorTo = mHighlightColor;
+ final ValueAnimator fadeInLoop =
+ ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
+ fadeInLoop.setDuration(HIGHLIGHT_FADE_IN_DURATION);
+ fadeInLoop.addUpdateListener(
+ animator -> v.setBackgroundColor((int) animator.getAnimatedValue()));
+ fadeInLoop.setRepeatMode(ValueAnimator.REVERSE);
+ fadeInLoop.setRepeatCount(4);
+ fadeInLoop.start();
+ Log.d(TAG, "AddHighlight: starting fade in animation");
+ holder.setIsRecyclable(false);
+ requestRemoveHighlightDelayed(holder);
+ }
+
+ private void removeHighlightBackground(PreferenceViewHolder holder, boolean animate) {
+ final View v = holder.itemView;
+ if (!animate) {
+ v.setTag(R.id.preference_highlighted, false);
+ v.setBackgroundResource(mNormalBackgroundRes);
+ Log.d(TAG, "RemoveHighlight: No animation requested - setting normal background");
+ return;
+ }
+
+ if (!Boolean.TRUE.equals(v.getTag(R.id.preference_highlighted))) {
+ // Not highlighted, no-op
+ Log.d(TAG, "RemoveHighlight: Not highlighted - skipping");
+ return;
+ }
+ int colorFrom = mHighlightColor;
+ int colorTo = mNormalBackgroundRes;
+
+ v.setTag(R.id.preference_highlighted, false);
+ final ValueAnimator colorAnimation =
+ ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
+ colorAnimation.setDuration(HIGHLIGHT_FADE_OUT_DURATION);
+ colorAnimation.addUpdateListener(
+ animator -> v.setBackgroundColor((int) animator.getAnimatedValue()));
+ colorAnimation.addListener(
+ new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Animation complete - the background is now white. Change to
+ // mNormalBackgroundRes
+ // so it is white and has ripple on touch.
+ v.setBackgroundResource(mNormalBackgroundRes);
+ holder.setIsRecyclable(true);
+ }
+ });
+ colorAnimation.start();
+ Log.d(TAG, "Starting fade out animation");
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/InteractionLogger.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/InteractionLogger.kt
new file mode 100644
index 000000000..58bec87b8
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/InteractionLogger.kt
@@ -0,0 +1,444 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui
+
+import android.Manifest.permission_group.CAMERA as PERMISSION_GROUP_CAMERA
+import android.Manifest.permission_group.LOCATION as PERMISSION_GROUP_LOCATION
+import android.Manifest.permission_group.MICROPHONE as PERMISSION_GROUP_MICROPHONE
+import android.content.Intent
+import android.os.Build
+import android.permission.PermissionGroupUsage
+import android.permission.PermissionManager
+import android.safetycenter.SafetyCenterEntry
+import android.safetycenter.SafetyCenterIssue
+import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_ISSUE_ID
+import android.safetycenter.SafetyCenterStatus
+import android.safetycenter.config.SafetyCenterConfig
+import android.safetycenter.config.SafetySource
+import androidx.annotation.RequiresApi
+import com.android.permissioncontroller.Constants
+import com.android.permissioncontroller.PermissionControllerStatsLog
+import com.android.permissioncontroller.PermissionControllerStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ISSUE_STATE__ACTIVE
+import com.android.permissioncontroller.PermissionControllerStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ISSUE_STATE__DISMISSED
+import com.android.permissioncontroller.PermissionControllerStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ISSUE_STATE__ISSUE_STATE_UNKNOWN
+import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.safetycenter.SafetyCenterConstants
+import com.android.permissioncontroller.safetycenter.SafetyCenterConstants.EXTRA_SETTINGS_FRAGMENT_ARGS_KEY
+import com.android.safetycenter.internaldata.SafetyCenterIds
+import java.math.BigInteger
+import java.security.MessageDigest
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+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
+ var navigationSensor: Sensor = Sensor.UNKNOWN
+ var groupId: String? = null
+
+ private val viewedIssueIds: MutableSet<String> = mutableSetOf()
+
+ constructor(
+ safetyCenterConfig: SafetyCenterConfig?
+ ) : this(extractNoLogSourceIds(safetyCenterConfig))
+
+ fun record(action: Action) {
+ writeAtom(action)
+ }
+
+ fun recordIssueViewed(issue: SafetyCenterIssue, isDismissed: Boolean) {
+ if (viewedIssueIds.contains(issue.id)) {
+ return
+ }
+
+ recordForIssue(Action.SAFETY_ISSUE_VIEWED, issue, isDismissed)
+ viewedIssueIds.add(issue.id)
+ }
+
+ fun clearViewedIssues() {
+ viewedIssueIds.clear()
+ }
+
+ fun recordForIssue(action: Action, issue: SafetyCenterIssue, isDismissed: Boolean) {
+ val decodedId = SafetyCenterIds.issueIdFromString(issue.id)
+ writeAtom(
+ action,
+ LogSeverityLevel.fromIssueSeverityLevel(issue.severityLevel),
+ sourceId = decodedId.safetyCenterIssueKey.safetySourceId,
+ sourceProfileType =
+ SafetySourceProfileType.fromUserId(decodedId.safetyCenterIssueKey.userId),
+ issueTypeId = decodedId.issueTypeId,
+ issueState =
+ if (isDismissed) {
+ SAFETY_CENTER_INTERACTION_REPORTED__ISSUE_STATE__DISMISSED
+ } else {
+ SAFETY_CENTER_INTERACTION_REPORTED__ISSUE_STATE__ACTIVE
+ }
+ )
+ }
+
+ fun recordForEntry(action: Action, entry: SafetyCenterEntry) {
+ val decodedId = SafetyCenterIds.entryIdFromString(entry.id)
+ writeAtom(
+ action,
+ LogSeverityLevel.fromEntrySeverityLevel(entry.severityLevel),
+ sourceId = decodedId.safetySourceId,
+ sourceProfileType = SafetySourceProfileType.fromUserId(decodedId.userId)
+ )
+ }
+
+ fun recordForSensor(action: Action, sensor: Sensor) {
+ writeAtom(action = action, sensor = sensor)
+ }
+
+ private fun writeAtom(
+ action: Action,
+ severityLevel: LogSeverityLevel = LogSeverityLevel.UNKNOWN,
+ sourceId: String? = null,
+ sourceProfileType: SafetySourceProfileType = SafetySourceProfileType.UNKNOWN,
+ issueTypeId: String? = null,
+ issueState: Int = SAFETY_CENTER_INTERACTION_REPORTED__ISSUE_STATE__ISSUE_STATE_UNKNOWN,
+ sensor: Sensor = Sensor.UNKNOWN,
+ ) {
+ if (noLogSourceIds.contains(sourceId)) {
+ return
+ }
+
+ // WARNING: Be careful when logging severity levels. If the severity level being recorded
+ // is at all influenced by a logging-disallowed source, we should not record it. At the
+ // moment, we do not record overall severity levels in this atom, but leaving this note for
+ // future implementors.
+
+ PermissionControllerStatsLog.write(
+ PermissionControllerStatsLog.SAFETY_CENTER_INTERACTION_REPORTED,
+ sessionId,
+ action.statsLogValue,
+ viewType.statsLogValue,
+ navigationSource.statsLogValue,
+ severityLevel.statsLogValue,
+ encodeStringId(sourceId),
+ sourceProfileType.statsLogValue,
+ encodeStringId(issueTypeId),
+ (if (sensor != Sensor.UNKNOWN) sensor else navigationSensor).statsLogValue,
+ encodeStringId(groupId),
+ issueState
+ )
+ }
+
+ private companion object {
+ /**
+ * Encodes a string into an long ID. The ID is a SHA-256 of the string, truncated to 64
+ * bits.
+ */
+ private fun encodeStringId(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()
+ }
+
+ private fun extractNoLogSourceIds(safetyCenterConfig: SafetyCenterConfig?): Set<String?> {
+ if (safetyCenterConfig == null) return setOf()
+
+ return safetyCenterConfig.safetySourcesGroups
+ .asSequence()
+ .flatMap { it.safetySources }
+ .filterNot { it.isLoggable() }
+ .map { it.id }
+ .toSet()
+ }
+
+ private fun SafetySource.isLoggable(): Boolean =
+ try {
+ isLoggingAllowed
+ } catch (ex: UnsupportedOperationException) {
+ // isLoggingAllowed will throw if you call it on a static source :(
+ // Default to logging all sources that don't support this config value.
+ true
+ }
+ }
+}
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+enum class Action(val statsLogValue: Int) {
+ UNKNOWN(
+ PermissionControllerStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ACTION__ACTION_UNKNOWN
+ ),
+ SAFETY_CENTER_VIEWED(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__ACTION__SAFETY_CENTER_VIEWED
+ ),
+ SAFETY_ISSUE_VIEWED(
+ PermissionControllerStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ACTION__SAFETY_ISSUE_VIEWED
+ ),
+ SCAN_INITIATED(
+ PermissionControllerStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ACTION__SCAN_INITIATED
+ ),
+ ISSUE_PRIMARY_ACTION_CLICKED(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__ACTION__ISSUE_PRIMARY_ACTION_CLICKED
+ ),
+ ISSUE_SECONDARY_ACTION_CLICKED(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__ACTION__ISSUE_SECONDARY_ACTION_CLICKED
+ ),
+ ISSUE_DISMISS_CLICKED(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__ACTION__ISSUE_DISMISS_CLICKED
+ ),
+ MORE_ISSUES_CLICKED(
+ PermissionControllerStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ACTION__MORE_ISSUES_CLICKED
+ ),
+ ENTRY_CLICKED(
+ PermissionControllerStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ACTION__ENTRY_CLICKED
+ ),
+ ENTRY_ICON_ACTION_CLICKED(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__ACTION__ENTRY_ICON_ACTION_CLICKED
+ ),
+ STATIC_ENTRY_CLICKED(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__ACTION__STATIC_ENTRY_CLICKED
+ ),
+ PRIVACY_CONTROL_TOGGLE_CLICKED(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__ACTION__PRIVACY_CONTROL_TOGGLE_CLICKED
+ ),
+ SENSOR_PERMISSION_REVOKE_CLICKED(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__ACTION__SENSOR_PERMISSION_REVOKE_CLICKED
+ ),
+ SENSOR_PERMISSION_SEE_USAGES_CLICKED(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__ACTION__SENSOR_PERMISSION_SEE_USAGES_CLICKED
+ ),
+ REVIEW_SETTINGS_CLICKED(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__ACTION__REVIEW_SETTINGS_CLICKED
+ )
+}
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+enum class ViewType(val statsLogValue: Int) {
+ UNKNOWN(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__VIEW_TYPE__VIEW_TYPE_UNKNOWN
+ ),
+ FULL(PermissionControllerStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__VIEW_TYPE__FULL),
+ QUICK_SETTINGS(
+ PermissionControllerStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__VIEW_TYPE__QUICK_SETTINGS
+ ),
+ SUBPAGE(PermissionControllerStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__VIEW_TYPE__SUBPAGE)
+}
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+enum class NavigationSource(val statsLogValue: Int) {
+ UNKNOWN(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__NAVIGATION_SOURCE__SOURCE_UNKNOWN
+ ),
+ NOTIFICATION(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__NAVIGATION_SOURCE__NOTIFICATION
+ ),
+ QUICK_SETTINGS_TILE(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__NAVIGATION_SOURCE__QUICK_SETTINGS_TILE
+ ),
+ SETTINGS(
+ PermissionControllerStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__NAVIGATION_SOURCE__SETTINGS
+ ),
+ SENSOR_INDICATOR(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__NAVIGATION_SOURCE__SENSOR_INDICATOR
+ ),
+ SAFETY_CENTER(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__NAVIGATION_SOURCE__SAFETY_CENTER
+ );
+
+ fun addToIntent(intent: Intent) {
+ intent.putExtra(SafetyCenterConstants.EXTRA_NAVIGATION_SOURCE, this.toString())
+ }
+
+ companion object {
+ @JvmStatic
+ fun fromIntent(intent: Intent): NavigationSource =
+ when (intent.action) {
+ Intent.ACTION_SAFETY_CENTER -> fromSafetyCenterIntent(intent)
+ Intent.ACTION_VIEW_SAFETY_CENTER_QS -> fromQuickSettingsIntent(intent)
+ else -> UNKNOWN
+ }
+
+ private fun fromSafetyCenterIntent(intent: Intent): NavigationSource {
+ val intentNavigationSource =
+ intent.getStringExtra(SafetyCenterConstants.EXTRA_NAVIGATION_SOURCE)
+ val sourceIssueId = intent.getStringExtra(EXTRA_SAFETY_SOURCE_ISSUE_ID)
+ val searchKey = intent.getStringExtra(EXTRA_SETTINGS_FRAGMENT_ARGS_KEY)
+
+ return if (sourceIssueId != null) {
+ NOTIFICATION
+ } else if (searchKey != null) {
+ SETTINGS
+ } else if (intentNavigationSource != null) {
+ valueOf(intentNavigationSource)
+ } else {
+ UNKNOWN
+ }
+ }
+
+ private fun fromQuickSettingsIntent(intent: Intent): NavigationSource {
+ val usages =
+ intent.getParcelableArrayListExtra(
+ PermissionManager.EXTRA_PERMISSION_USAGES,
+ PermissionGroupUsage::class.java
+ )
+
+ return if (usages != null && usages.isNotEmpty()) {
+ SENSOR_INDICATOR
+ } else {
+ QUICK_SETTINGS_TILE
+ }
+ }
+ }
+}
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+enum class LogSeverityLevel(val statsLogValue: Int) {
+ UNKNOWN(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN
+ ),
+ UNSPECIFIED(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_UNSPECIFIED
+ ),
+ OK(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_OK
+ ),
+ RECOMMENDATION(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION
+ ),
+ CRITICAL_WARNING(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING
+ );
+
+ companion object {
+ @JvmStatic
+ fun fromOverallSeverityLevel(overallLevel: Int): LogSeverityLevel =
+ when (overallLevel) {
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN -> UNKNOWN
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK -> OK
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION -> RECOMMENDATION
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING -> CRITICAL_WARNING
+ else -> UNKNOWN
+ }
+
+ @JvmStatic
+ fun fromIssueSeverityLevel(issueLevel: Int): LogSeverityLevel =
+ when (issueLevel) {
+ SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK -> OK
+ SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION -> RECOMMENDATION
+ SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING -> CRITICAL_WARNING
+ else -> UNKNOWN
+ }
+
+ @JvmStatic
+ fun fromEntrySeverityLevel(entryLevel: Int): LogSeverityLevel =
+ when (entryLevel) {
+ SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK -> OK
+ SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION -> RECOMMENDATION
+ SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING -> CRITICAL_WARNING
+ SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED -> UNSPECIFIED
+ else -> UNKNOWN
+ }
+ }
+}
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+enum class SafetySourceProfileType(val statsLogValue: Int) {
+ UNKNOWN(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_UNKNOWN
+ ),
+ PERSONAL(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL
+ ),
+ MANAGED(
+ PermissionControllerStatsLog
+ .SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED
+ );
+
+ companion object {
+ @JvmStatic
+ fun fromUserId(userId: Int): SafetySourceProfileType =
+ if (Utils.isUserManagedProfile(userId)) MANAGED else PERSONAL
+ }
+}
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+enum class Sensor(val statsLogValue: Int) {
+ UNKNOWN(
+ PermissionControllerStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SENSOR__SENSOR_UNKNOWN
+ ),
+ MICROPHONE(PermissionControllerStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SENSOR__MICROPHONE),
+ CAMERA(PermissionControllerStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SENSOR__CAMERA),
+ LOCATION(PermissionControllerStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SENSOR__LOCATION);
+
+ companion object {
+ @JvmStatic
+ fun fromIntent(intent: Intent): Sensor {
+ if (intent.action != Intent.ACTION_VIEW_SAFETY_CENTER_QS) return UNKNOWN
+
+ val usages =
+ intent.getParcelableArrayListExtra(
+ PermissionManager.EXTRA_PERMISSION_USAGES,
+ PermissionGroupUsage::class.java
+ )
+
+ // Multiple usages may be in effect, but we can only log one. Log unknown in this
+ // scenario until we have a better solution (an explicit value approved for
+ // logging).
+ if (usages != null && usages.size > 1) return UNKNOWN
+
+ return fromPermissionGroupUsage(usages?.firstOrNull())
+ }
+
+ @JvmStatic
+ fun fromPermissionGroupUsage(usage: PermissionGroupUsage?) =
+ fromPermissionGroupName(usage?.permissionGroupName)
+
+ @JvmStatic
+ fun fromPermissionGroupName(permissionGroupName: String?) =
+ when (permissionGroupName) {
+ PERMISSION_GROUP_CAMERA -> CAMERA
+ PERMISSION_GROUP_MICROPHONE -> MICROPHONE
+ PERMISSION_GROUP_LOCATION -> LOCATION
+ else -> UNKNOWN
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardAnimator.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardAnimator.kt
new file mode 100644
index 000000000..a0c7c01b9
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardAnimator.kt
@@ -0,0 +1,220 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui
+
+import android.content.Context
+import android.graphics.drawable.Animatable2
+import android.graphics.drawable.AnimatedVectorDrawable
+import android.graphics.drawable.Drawable
+import android.provider.DeviceConfig
+import android.safetycenter.SafetyCenterIssue
+import android.text.TextUtils
+import android.transition.Fade
+import android.transition.Transition
+import android.transition.TransitionListenerAdapter
+import android.transition.TransitionManager
+import android.transition.TransitionSet
+import android.view.View
+import android.view.ViewGroup
+import android.view.animation.LinearInterpolator
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.preference.PreferenceViewHolder
+import com.android.permissioncontroller.R
+import java.time.Duration
+
+class IssueCardAnimator(val callback: AnimationCallback) {
+
+ fun transitionToIssueResolvedThenMarkComplete(
+ context: Context,
+ holder: PreferenceViewHolder,
+ action: SafetyCenterIssue.Action
+ ) {
+ var successMessage = action.successMessage
+ if (TextUtils.isEmpty(successMessage)) {
+ successMessage = context.getString(R.string.safety_center_resolved_issue_fallback)
+ }
+ (holder.findViewById(R.id.resolved_issue_text) as TextView).text = successMessage
+ val resolvedImageView = holder.findViewById(R.id.resolved_issue_image) as ImageView
+ resolvedImageView.contentDescription = successMessage
+
+ // Ensure AVD is reset before transition starts
+ (resolvedImageView.drawable as AnimatedVectorDrawable).reset()
+
+ val defaultIssueContentGroup = holder.findViewById(R.id.default_issue_content)
+ val resolvedIssueContentGroup = holder.findViewById(R.id.resolved_issue_content)
+
+ val transitionSet = TransitionSet()
+ .setOrdering(TransitionSet.ORDERING_SEQUENTIAL)
+ .setInterpolator(linearInterpolator)
+ .addTransition(hideIssueContentTransition)
+ .addTransition(
+ showResolvedImageTransition
+ .clone()
+ .addListener(
+ object : TransitionListenerAdapter() {
+ override fun onTransitionEnd(
+ transition: Transition
+ ) {
+ super.onTransitionEnd(transition)
+ startIssueResolvedAnimation(
+ resolvedIssueContentGroup,
+ resolvedImageView
+ )
+ }
+ })
+ )
+ .addTransition(showResolvedTextTransition)
+
+ // Defer transition so that it's called after the root ViewGroup has been laid out.
+ holder.itemView.post {
+ TransitionManager.beginDelayedTransition(
+ defaultIssueContentGroup.parent as ViewGroup?, transitionSet
+ )
+
+ // Setting INVISIBLE rather than GONE to ensure consistent card height between
+ // view groups.
+ defaultIssueContentGroup.visibility = View.INVISIBLE
+
+ // These two 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_subtitle))
+ makeInvisibleIfVisible(holder.findViewById(R.id.issue_card_protected_by_android))
+
+ resolvedIssueContentGroup.visibility = View.VISIBLE
+ }
+
+ // Cancel animations if they are scrolled out of view (detached from recycler view)
+ holder.itemView.addOnAttachStateChangeListener(
+ object : View.OnAttachStateChangeListener {
+ override fun onViewAttachedToWindow(v: View) {}
+ override fun onViewDetachedFromWindow(v: View) {
+ holder.itemView.removeOnAttachStateChangeListener(this)
+ cancelIssueResolvedUiTransitionsAndMarkCompleted(
+ defaultIssueContentGroup,
+ resolvedIssueContentGroup,
+ resolvedImageView
+ )
+ }
+ })
+ }
+
+ private fun makeInvisibleIfVisible(view: View?) {
+ if (view != null && view.visibility == View.VISIBLE) {
+ view.visibility = View.INVISIBLE
+ }
+ }
+
+ private fun startIssueResolvedAnimation(
+ resolvedIssueContentGroup: View,
+ resolvedImageView: ImageView
+ ) {
+ val animatedDrawable = resolvedImageView.drawable as AnimatedVectorDrawable
+ animatedDrawable.reset()
+ animatedDrawable.clearAnimationCallbacks()
+ animatedDrawable.registerAnimationCallback(
+ object : Animatable2.AnimationCallback() {
+ override fun onAnimationEnd(drawable: Drawable) {
+ super.onAnimationEnd(drawable)
+ transitionResolvedIssueUiToHiddenAndMarkComplete(resolvedIssueContentGroup)
+ }
+ })
+ animatedDrawable.start()
+ }
+
+ private fun transitionResolvedIssueUiToHiddenAndMarkComplete(resolvedIssueContentGroup: View) {
+ val hideTransition = hideResolvedUiTransition
+ .clone()
+ .setInterpolator(linearInterpolator)
+ .addListener(
+ object : TransitionListenerAdapter() {
+ override fun onTransitionEnd(transition: Transition) {
+ super.onTransitionEnd(transition)
+ callback.markIssueResolvedUiCompleted()
+ }
+ })
+ TransitionManager.beginDelayedTransition(
+ resolvedIssueContentGroup.parent as ViewGroup, hideTransition
+ )
+ resolvedIssueContentGroup.visibility = View.GONE
+ }
+
+ private fun cancelIssueResolvedUiTransitionsAndMarkCompleted(
+ defaultIssueContentGroup: View,
+ resolvedIssueContentGroup: View,
+ resolvedImageView: ImageView
+ ) {
+ // Cancel any in flight initial fade (in and out) transitions
+ TransitionManager.endTransitions(defaultIssueContentGroup.parent as ViewGroup)
+
+ // Cancel any in flight resolved image animations
+ val animatedDrawable = resolvedImageView.drawable as AnimatedVectorDrawable
+ animatedDrawable.clearAnimationCallbacks()
+ animatedDrawable.stop()
+
+ // Cancel any in flight fade out transitions
+ TransitionManager.endTransitions(resolvedIssueContentGroup.parent as ViewGroup)
+ callback.markIssueResolvedUiCompleted()
+ }
+
+ interface AnimationCallback {
+ fun markIssueResolvedUiCompleted()
+ }
+
+ companion object {
+ /**
+ * Device config property for time in milliseconds to increase
+ * HIDE_RESOLVED_UI_TRANSITION_DELAY for use in testing.
+ */
+ private const val PROPERTY_HIDE_RESOLVED_UI_TRANSITION_DELAY_MILLIS =
+ "safety_center_hide_resolved_ui_transition_delay_millis"
+
+ private val HIDE_ISSUE_CONTENT_TRANSITION_DURATION = Duration.ofMillis(333)
+ private val SHOW_RESOLVED_TEXT_TRANSITION_DELAY = Duration.ofMillis(133)
+ private val SHOW_RESOLVED_TEXT_TRANSITION_DURATION = Duration.ofMillis(250)
+ private val HIDE_RESOLVED_UI_TRANSITION_DURATION = Duration.ofMillis(167)
+
+ // Using getter due to reliance on DeviceConfig property modification in tests
+ private val hideResolvedUiTransitionDelay
+ get() = Duration.ofMillis(
+ DeviceConfig.getLong(DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_HIDE_RESOLVED_UI_TRANSITION_DELAY_MILLIS,
+ 400))
+
+ private val linearInterpolator = LinearInterpolator()
+
+ private val hideIssueContentTransition =
+ Fade(Fade.OUT).setDuration(HIDE_ISSUE_CONTENT_TRANSITION_DURATION.toMillis())
+
+ private val showResolvedImageTransition =
+ Fade(Fade.IN)
+ // Fade is used for visibility transformation. Image to be shown immediately
+ .setDuration(0)
+ .addTarget(R.id.resolved_issue_image)
+
+ private val showResolvedTextTransition = Fade(Fade.IN)
+ .setStartDelay(SHOW_RESOLVED_TEXT_TRANSITION_DELAY.toMillis())
+ .setDuration(SHOW_RESOLVED_TEXT_TRANSITION_DURATION.toMillis())
+ .addTarget(R.id.resolved_issue_text)
+
+ private val hideResolvedUiTransition
+ get() = Fade(Fade.OUT)
+ .setStartDelay(hideResolvedUiTransitionDelay.toMillis())
+ .setDuration(HIDE_RESOLVED_UI_TRANSITION_DURATION.toMillis())
+ }
+} \ No newline at end of file
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardPreference.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardPreference.java
index 621925fbc..c56cce0a5 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardPreference.java
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardPreference.java
@@ -16,97 +16,607 @@
package com.android.permissioncontroller.safetycenter.ui;
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static java.util.Objects.requireNonNull;
-import android.app.PendingIntent;
+import android.app.AlertDialog;
+import android.app.Dialog;
import android.content.Context;
+import android.os.Bundle;
import android.safetycenter.SafetyCenterIssue;
+import android.text.TextUtils;
import android.util.Log;
+import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewGroup.MarginLayoutParams;
import android.widget.Button;
-import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.Space;
import android.widget.TextView;
-import android.widget.Toast;
+import androidx.annotation.ColorRes;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.appcompat.view.ContextThemeWrapper;
+import androidx.core.content.ContextCompat;
+import androidx.fragment.app.DialogFragment;
+import androidx.fragment.app.FragmentManager;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
+import com.android.modules.utils.build.SdkLevel;
import com.android.permissioncontroller.R;
+import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterViewModel;
+
+import com.google.android.material.button.MaterialButton;
+import com.google.android.material.shape.AbsoluteCornerSize;
+import com.google.android.material.shape.CornerSize;
+import com.google.android.material.shape.ShapeAppearanceModel;
+
+import java.util.Objects;
/** A preference that displays a card representing a {@link SafetyCenterIssue}. */
-public class IssueCardPreference extends Preference {
+@RequiresApi(TIRAMISU)
+public class IssueCardPreference extends Preference implements ComparablePreference {
public static final String TAG = IssueCardPreference.class.getSimpleName();
+ private final IssueCardAnimator mIssueCardAnimator =
+ new IssueCardAnimator(this::markIssueResolvedUiCompleted);
+ private final SafetyCenterViewModel mSafetyCenterViewModel;
private final SafetyCenterIssue mIssue;
+ private final FragmentManager mDialogFragmentManager;
+ @Nullable private String mResolvedIssueActionId;
+ @Nullable private final Integer mTaskId;
+ private final boolean mIsDismissed;
+ private final PositionInCardList mPositionInCardList;
- public IssueCardPreference(Context context, SafetyCenterIssue issue) {
+ public IssueCardPreference(
+ Context context,
+ SafetyCenterViewModel safetyCenterViewModel,
+ SafetyCenterIssue issue,
+ @Nullable String resolvedIssueActionId,
+ FragmentManager dialogFragmentManager,
+ @Nullable Integer launchTaskId,
+ boolean isDismissed,
+ PositionInCardList positionInCardList) {
super(context);
setLayoutResource(R.layout.preference_issue_card);
+ mSafetyCenterViewModel = requireNonNull(safetyCenterViewModel);
mIssue = requireNonNull(issue);
+ mDialogFragmentManager = dialogFragmentManager;
+ mResolvedIssueActionId = resolvedIssueActionId;
+ mTaskId = launchTaskId;
+ mIsDismissed = isDismissed;
+ mPositionInCardList = positionInCardList;
}
- // TODO: Add real todos with bug numbers once UI bug breakdown is finished.
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
- ((ImageView) holder.findViewById(R.id.issue_card_banner_icon)).setImageResource(
- toSeverityLevel(mIssue.getSeverityLevel()).getWarningCardIconResId());
+ holder.itemView.setBackgroundResource(mPositionInCardList.getBackgroundDrawableResId());
+ int topMargin = getTopMargin(mPositionInCardList, getContext());
+ MarginLayoutParams layoutParams = (MarginLayoutParams) holder.itemView.getLayoutParams();
+ if (layoutParams.topMargin != topMargin) {
+ layoutParams.topMargin = topMargin;
+ holder.itemView.setLayoutParams(layoutParams);
+ }
+
+ // Set default group visibility in case view is being reused
+ holder.findViewById(R.id.default_issue_content).setVisibility(View.VISIBLE);
+ holder.findViewById(R.id.resolved_issue_content).setVisibility(View.GONE);
- // TODO: Fire off real dismissal (to the API)
- holder.findViewById(R.id.issue_card_dismiss_btn).setOnClickListener(
- (view) -> this.getParent().removePreference(this));
+ configureDismissButton(holder.findViewById(R.id.issue_card_dismiss_btn));
- ((TextView) holder.findViewById(R.id.issue_card_title)).setText(mIssue.getTitle());
- ((TextView) holder.findViewById(R.id.issue_card_subtitle)).setText(mIssue.getSubtitle());
+ TextView titleTextView = (TextView) holder.findViewById(R.id.issue_card_title);
+ titleTextView.setText(mIssue.getTitle());
((TextView) holder.findViewById(R.id.issue_card_summary)).setText(mIssue.getSummary());
+ TextView attributionTitleTextView =
+ (TextView) holder.findViewById(R.id.issue_card_attribution_title);
+ maybeDisplayText(
+ SdkLevel.isAtLeastU() ? mIssue.getAttributionTitle() : null,
+ attributionTitleTextView);
+
+ TextView subtitleTextView = (TextView) holder.findViewById(R.id.issue_card_subtitle);
+ maybeDisplayText(mIssue.getSubtitle(), subtitleTextView);
+
+ holder.itemView.setClickable(false);
+
+ configureContentDescription(attributionTitleTextView, titleTextView);
+ configureButtonList(holder);
+ configureSafetyProtectionView(holder);
+ maybeStartResolutionAnimation(holder);
+
+ mSafetyCenterViewModel
+ .getInteractionLogger()
+ .recordIssueViewed(mIssue, mIsDismissed);
+ }
+
+ private void maybeDisplayText(@Nullable CharSequence maybeText, TextView textView) {
+ if (TextUtils.isEmpty(maybeText)) {
+ textView.setVisibility(View.GONE);
+ } else {
+ textView.setText(maybeText);
+ textView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private void configureContentDescription(
+ TextView attributionTitleTextView, TextView titleTextView) {
+ TextView firstVisibleTextView;
+ if (attributionTitleTextView.getVisibility() == View.VISIBLE) {
+ // Attribution title might not be present for an issue, title always is.
+ firstVisibleTextView = attributionTitleTextView;
+
+ // Clear the modified title description in case this view is reused.
+ titleTextView.setContentDescription(null);
+ } else {
+ firstVisibleTextView = titleTextView;
+ }
+
+ // We would like to say "alert" before reading the content of the issue card. Best way to
+ // do that is by modifying the content description of the first view that would be read
+ // in the issue card.
+ firstVisibleTextView.setContentDescription(
+ getContext()
+ .getString(
+ R.string.safety_center_issue_card_prefix_content_description,
+ firstVisibleTextView.getText()));
+ }
+
+ private void configureButtonList(PreferenceViewHolder holder) {
LinearLayout buttonList =
((LinearLayout) holder.findViewById(R.id.issue_card_action_button_list));
buttonList.removeAllViews(); // This view may be recycled from another issue
+
+ for (int i = 0; i < mIssue.getActions().size(); i++) {
+ SafetyCenterIssue.Action action = mIssue.getActions().get(i);
+ ActionButtonBuilder builder =
+ new ActionButtonBuilder(action, holder.itemView.getContext())
+ .setIndex(i)
+ .setActionButtonListSize(mIssue.getActions().size())
+ .setIsDismissed(mIsDismissed)
+ .setIsLargeScreen(buttonList instanceof EqualWidthContainer);
+ builder.buildAndAddToView(buttonList);
+ }
+ }
+
+ private int getTopMargin(PositionInCardList position, Context context) {
+ switch (position) {
+ case LIST_START_END:
+ case LIST_START_CARD_END:
+ return context.getResources()
+ .getDimensionPixelSize(
+ mIsDismissed ? R.dimen.sc_card_margin : R.dimen.sc_spacing_large);
+ default:
+ return position.getTopMargin(context);
+ }
+ }
+
+ private void configureSafetyProtectionView(PreferenceViewHolder holder) {
+ View safetyProtectionSectionView =
+ holder.findViewById(R.id.issue_card_protected_by_android);
+ if (safetyProtectionSectionView.getVisibility() == View.GONE) {
+ holder.itemView.setPaddingRelative(
+ holder.itemView.getPaddingStart(),
+ holder.itemView.getPaddingTop(),
+ holder.itemView.getPaddingEnd(),
+ /* bottom= */ getContext()
+ .getResources()
+ .getDimensionPixelSize(R.dimen.sc_card_margin_bottom));
+ } else {
+ holder.itemView.setPaddingRelative(
+ holder.itemView.getPaddingStart(),
+ holder.itemView.getPaddingTop(),
+ holder.itemView.getPaddingEnd(),
+ /* bottom= */ 0);
+ }
+ }
+
+ private void maybeStartResolutionAnimation(PreferenceViewHolder holder) {
+ if (mResolvedIssueActionId == null) {
+ return;
+ }
+
for (SafetyCenterIssue.Action action : mIssue.getActions()) {
- buttonList.addView(buildActionButton(action, holder.itemView.getContext()));
+ if (action.getId().equals(mResolvedIssueActionId)) {
+ mIssueCardAnimator.transitionToIssueResolvedThenMarkComplete(
+ getContext(), holder, action);
+ }
+ }
+ }
+
+ public int getSeverityLevel() {
+ return mIssue.getSeverityLevel();
+ }
+
+ private void configureDismissButton(View dismissButton) {
+ if (mIssue.isDismissible() && !mIsDismissed) {
+ dismissButton.setOnClickListener(
+ mIssue.shouldConfirmDismissal()
+ ? new ConfirmDismissalOnClickListener()
+ : new DismissOnClickListener());
+ dismissButton.setVisibility(View.VISIBLE);
+
+ SafetyCenterTouchTarget.configureSize(
+ dismissButton, R.dimen.sc_icon_button_touch_target_size);
+ } else {
+ dismissButton.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public boolean isSameItem(Preference preference) {
+ return (preference instanceof IssueCardPreference)
+ && TextUtils.equals(
+ mIssue.getId(), ((IssueCardPreference) preference).mIssue.getId());
+ }
+
+ @Override
+ public boolean hasSameContents(Preference preference) {
+ return (preference instanceof IssueCardPreference)
+ && mIssue.equals(((IssueCardPreference) preference).mIssue)
+ && Objects.equals(
+ mResolvedIssueActionId,
+ ((IssueCardPreference) preference).mResolvedIssueActionId)
+ && mIsDismissed == ((IssueCardPreference) preference).mIsDismissed
+ && mPositionInCardList == ((IssueCardPreference) preference).mPositionInCardList;
+ }
+
+ private class DismissOnClickListener implements View.OnClickListener {
+ @Override
+ public void onClick(View v) {
+ mSafetyCenterViewModel.dismissIssue(mIssue);
+ mSafetyCenterViewModel
+ .getInteractionLogger()
+ .recordForIssue(Action.ISSUE_DISMISS_CLICKED, mIssue, mIsDismissed);
+ }
+ }
+
+ private class ConfirmDismissalOnClickListener implements View.OnClickListener {
+ @Override
+ public void onClick(View v) {
+ ConfirmDismissalDialogFragment.newInstance(mIssue)
+ .showNow(mDialogFragmentManager, /* tag= */ null);
+ }
+ }
+
+ /** Fragment to display a dismissal confirmation dialog for an {@link IssueCardPreference}. */
+ public static class ConfirmDismissalDialogFragment extends DialogFragment {
+ private static final String ISSUE_KEY = "confirm_dialog_sc_issue";
+
+ private static ConfirmDismissalDialogFragment newInstance(SafetyCenterIssue issue) {
+ ConfirmDismissalDialogFragment fragment = new ConfirmDismissalDialogFragment();
+
+ Bundle args = new Bundle();
+ args.putParcelable(ISSUE_KEY, issue);
+ fragment.setArguments(args);
+
+ return fragment;
+ }
+
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ SafetyCenterViewModel safetyCenterViewModel =
+ ((SafetyCenterFragment) requireParentFragment()).getSafetyCenterViewModel();
+ SafetyCenterIssue issue =
+ requireNonNull(
+ requireArguments().getParcelable(ISSUE_KEY, SafetyCenterIssue.class));
+ return new AlertDialog.Builder(getContext())
+ .setTitle(R.string.safety_center_issue_card_dismiss_confirmation_title)
+ .setMessage(R.string.safety_center_issue_card_dismiss_confirmation_message)
+ .setPositiveButton(
+ R.string.safety_center_issue_card_confirm_dismiss_button,
+ (dialog, which) -> {
+ safetyCenterViewModel.dismissIssue(issue);
+ safetyCenterViewModel
+ .getInteractionLogger()
+ .recordForIssue(
+ Action.ISSUE_DISMISS_CLICKED,
+ issue,
+ // You can only dismiss non-dismissed issues
+ /* isDismissed= */ false);
+ })
+ .setNegativeButton(
+ R.string.safety_center_issue_card_cancel_dismiss_button, null)
+ .create();
}
}
- private Button buildActionButton(
- SafetyCenterIssue.Action action,
- Context context) {
- Button button = new Button(
- context, null, 0, R.style.SafetyCenter_IssueCard_ActionButton);
+ /** A dialog to prompt for a confirmation to performn an Action. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static class ConfirmActionDialogFragment extends DialogFragment {
+ private static final String ISSUE_KEY = "issue";
+ private static final String ACTION_KEY = "action";
+ private static final String TASK_ID_KEY = "taskId";
+ private static final String IS_PRIMARY_BUTTON_KEY = "isPrimaryButton";
+ private static final String IS_DISMISSED_KEY = "isDismissed";
- button.setText(action.getLabel());
- button.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
- button.setOnClickListener((view) -> {
- try {
- action.getPendingIntent().send();
- } catch (PendingIntent.CanceledException e) {
- Log.e(TAG, String.format("Executing action \"%s\" failed", action.getLabel()), e);
- Toast.makeText(getContext(), "Action failed", Toast.LENGTH_SHORT).show();
+ /** Create new fragment with the data it will need. */
+ public static ConfirmActionDialogFragment newInstance(
+ SafetyCenterIssue issue,
+ SafetyCenterIssue.Action action,
+ @Nullable Integer taskId,
+ boolean isFirstButton,
+ boolean isDismissed) {
+ ConfirmActionDialogFragment fragment = new ConfirmActionDialogFragment();
+
+ Bundle args = new Bundle();
+ args.putParcelable(ISSUE_KEY, issue);
+ args.putParcelable(ACTION_KEY, action);
+ args.putBoolean(IS_PRIMARY_BUTTON_KEY, isFirstButton);
+ args.putBoolean(IS_DISMISSED_KEY, isDismissed);
+
+ if (taskId != null) {
+ args.putInt(TASK_ID_KEY, taskId);
}
- });
- return button;
+ fragment.setArguments(args);
+
+ return fragment;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ SafetyCenterViewModel safetyCenterViewModel =
+ ((SafetyCenterFragment) requireParentFragment()).getSafetyCenterViewModel();
+ SafetyCenterIssue issue =
+ requireNonNull(
+ requireArguments().getParcelable(ISSUE_KEY, SafetyCenterIssue.class));
+ SafetyCenterIssue.Action action =
+ requireNonNull(
+ requireArguments()
+ .getParcelable(ACTION_KEY, SafetyCenterIssue.Action.class));
+ boolean isPrimaryButton = requireArguments().getBoolean(IS_PRIMARY_BUTTON_KEY);
+ boolean isDismissed = requireArguments().getBoolean(IS_DISMISSED_KEY);
+
+ Integer taskId =
+ requireArguments().containsKey(TASK_ID_KEY)
+ ? requireArguments().getInt(TASK_ID_KEY)
+ : null;
+
+ return new AlertDialog.Builder(getContext())
+ .setTitle(action.getConfirmationDialogDetails().getTitle())
+ .setMessage(action.getConfirmationDialogDetails().getText())
+ .setPositiveButton(
+ action.getConfirmationDialogDetails().getAcceptButtonText(),
+ (dialog, which) -> {
+ safetyCenterViewModel.executeIssueAction(issue, action, taskId);
+ // TODO(b/269097766): Is this the best logging model?
+ safetyCenterViewModel
+ .getInteractionLogger()
+ .recordForIssue(
+ isPrimaryButton
+ ? Action.ISSUE_PRIMARY_ACTION_CLICKED
+ : Action.ISSUE_SECONDARY_ACTION_CLICKED,
+ issue,
+ isDismissed);
+ })
+ .setNegativeButton(
+ action.getConfirmationDialogDetails().getDenyButtonText(), null)
+ .create();
+ }
}
- private static SeverityLevel toSeverityLevel(int issueSeverityLevel) {
- switch (issueSeverityLevel) {
- case SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK:
- return SeverityLevel.INFORMATION;
- case SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION:
- return SeverityLevel.RECOMMENDATION;
- case SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING:
- return SeverityLevel.CRITICAL_WARNING;
+ private void markIssueResolvedUiCompleted() {
+ if (mResolvedIssueActionId != null) {
+ mResolvedIssueActionId = null;
+ mSafetyCenterViewModel.markIssueResolvedUiCompleted(mIssue.getId());
}
- throw new IllegalArgumentException(
- String.format("Unexpected SafetyCenterIssue.IssueSeverityLevel: %s",
- issueSeverityLevel));
}
+ private class ActionButtonBuilder {
+ private final SafetyCenterIssue.Action mAction;
+ private final Context mContext;
+ private final ContextThemeWrapper mContextThemeWrapper;
+ private int mIndex;
+ private int mActionButtonListSize;
+ private boolean mIsDismissed = false;
+ private boolean mIsLargeScreen = false;
+
+ ActionButtonBuilder(SafetyCenterIssue.Action action, Context context) {
+ mAction = action;
+ mContext = context;
+ mContextThemeWrapper =
+ new ContextThemeWrapper(context, R.style.Theme_MaterialComponents_DayNight);
+ }
+
+ public ActionButtonBuilder setIndex(int index) {
+ mIndex = index;
+ return this;
+ }
+
+ public ActionButtonBuilder setActionButtonListSize(int actionButtonListSize) {
+ mActionButtonListSize = actionButtonListSize;
+ return this;
+ }
+
+ public ActionButtonBuilder setIsDismissed(boolean isDismissed) {
+ mIsDismissed = isDismissed;
+ return this;
+ }
+
+ public ActionButtonBuilder setIsLargeScreen(boolean isLargeScreen) {
+ mIsLargeScreen = isLargeScreen;
+ return this;
+ }
+
+ private boolean isPrimaryButton() {
+ return mIndex == 0;
+ }
+
+ private boolean isLastButton() {
+ return mIndex == (mActionButtonListSize - 1);
+ }
+
+ private boolean isFilled() {
+ return isPrimaryButton() && !mIsDismissed;
+ }
+
+ public void buildAndAddToView(LinearLayout buttonList) {
+ MaterialButton button = new MaterialButton(mContextThemeWrapper, null, getStyle());
+ if (SdkLevel.isAtLeastU() && !mIsLargeScreen) {
+ configureGroupStyleCorners(button);
+ }
+ setButtonColors(button);
+ setButtonLayout(button);
+ button.setText(mAction.getLabel());
+ button.setEnabled(!mAction.isInFlight());
+ button.setOnClickListener(
+ view -> {
+ if (SdkLevel.isAtLeastU()
+ && mAction.getConfirmationDialogDetails() != null) {
+ ConfirmActionDialogFragment.newInstance(
+ mIssue,
+ mAction,
+ mTaskId,
+ isPrimaryButton(),
+ mIsDismissed)
+ .showNow(mDialogFragmentManager, /* tag= */ null);
+ } else {
+ if (mAction.willResolve()) {
+ // Without a confirmation, the button remains tappable. Disable the
+ // button to prevent double-taps.
+ // We ideally want to do this on any button press, however out of an
+ // abundance of caution we only do it with actions that indicate
+ // they will resolve (and therefore we can rely on a model update to
+ // redraw state - either to isInFlight() or simply resolving the
+ // issue.
+ button.setEnabled(false);
+ }
+ mSafetyCenterViewModel.executeIssueAction(mIssue, mAction, mTaskId);
+ mSafetyCenterViewModel
+ .getInteractionLogger()
+ .recordForIssue(
+ isPrimaryButton()
+ ? Action.ISSUE_PRIMARY_ACTION_CLICKED
+ : Action.ISSUE_SECONDARY_ACTION_CLICKED,
+ mIssue,
+ mIsDismissed);
+ }
+ });
+
+ maybeAddSpaceToView(buttonList);
+ buttonList.addView(button);
+ }
+
+ /**
+ * Configures "group-style" corners for this button, where the first button in the list has
+ * large corners on top and the last button in the list has large corners on bottom.
+ */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ private void configureGroupStyleCorners(MaterialButton button) {
+ button.setCornerRadiusResource(R.dimen.sc_button_corner_radius_small);
+ ShapeAppearanceModel.Builder shapeAppearanceModelBuilder =
+ button.getShapeAppearanceModel().toBuilder();
+
+ CornerSize largeCornerSize =
+ new AbsoluteCornerSize(
+ mContext.getResources()
+ .getDimensionPixelSize(R.dimen.sc_button_corner_radius));
+ if (isPrimaryButton()) {
+ shapeAppearanceModelBuilder
+ .setTopLeftCornerSize(largeCornerSize)
+ .setTopRightCornerSize(largeCornerSize);
+ }
+ if (isLastButton()) {
+ shapeAppearanceModelBuilder
+ .setBottomLeftCornerSize(largeCornerSize)
+ .setBottomRightCornerSize(largeCornerSize);
+ }
+
+ button.setShapeAppearanceModel(shapeAppearanceModelBuilder.build());
+ }
+
+ private void maybeAddSpaceToView(LinearLayout buttonList) {
+ if (isPrimaryButton()) {
+ return;
+ }
+
+ int margin =
+ mContext.getResources()
+ .getDimensionPixelSize(R.dimen.sc_action_button_list_margin);
+ Space space = new Space(mContext);
+ space.setLayoutParams(new ViewGroup.LayoutParams(margin, margin));
+ buttonList.addView(space);
+ }
+
+ private int getStyle() {
+ return isFilled() ? R.attr.scActionButtonStyle : R.attr.scSecondaryActionButtonStyle;
+ }
+
+ private void setButtonColors(MaterialButton button) {
+ if (isFilled()) {
+ button.setBackgroundTintList(
+ ContextCompat.getColorStateList(
+ mContext,
+ getPrimaryButtonColorFromSeverity(mIssue.getSeverityLevel())));
+ } else {
+ button.setStrokeColor(
+ ContextCompat.getColorStateList(
+ mContext,
+ getSecondaryButtonStrokeColorFromSeverity(
+ mIssue.getSeverityLevel())));
+ }
+ }
+
+ private void setButtonLayout(Button button) {
+ MarginLayoutParams layoutParams = new MarginLayoutParams(layoutWidth(), WRAP_CONTENT);
+ button.setLayoutParams(layoutParams);
+ }
+
+ private int layoutWidth() {
+ if (mIsLargeScreen) {
+ return WRAP_CONTENT;
+ } else {
+ return MATCH_PARENT;
+ }
+ }
+
+ @ColorRes
+ private int getPrimaryButtonColorFromSeverity(int issueSeverityLevel) {
+ return pickColorForSeverityLevel(
+ issueSeverityLevel,
+ R.color.safety_center_button_info,
+ R.color.safety_center_button_recommend,
+ R.color.safety_center_button_warn);
+ }
+
+ @ColorRes
+ private int getSecondaryButtonStrokeColorFromSeverity(int issueSeverityLevel) {
+ return pickColorForSeverityLevel(
+ issueSeverityLevel,
+ R.color.safety_center_outline_button_info,
+ R.color.safety_center_outline_button_recommend,
+ R.color.safety_center_outline_button_warn);
+ }
+
+ @ColorRes
+ private int pickColorForSeverityLevel(
+ int issueSeverityLevel,
+ @ColorRes int infoColor,
+ @ColorRes int recommendColor,
+ @ColorRes int warnColor) {
+ switch (issueSeverityLevel) {
+ case SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK:
+ return infoColor;
+ case SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION:
+ return recommendColor;
+ case SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING:
+ return warnColor;
+ default:
+ Log.w(
+ TAG,
+ String.format("Unexpected issueSeverityLevel: %s", issueSeverityLevel));
+ return infoColor;
+ }
+ }
+ }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardAnimator.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardAnimator.kt
new file mode 100644
index 000000000..55293f775
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardAnimator.kt
@@ -0,0 +1,114 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui
+
+import android.graphics.drawable.Animatable2
+import android.graphics.drawable.AnimatedVectorDrawable
+import android.graphics.drawable.Drawable
+import android.safetycenter.SafetyCenterIssue
+import android.util.Log
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.annotation.DrawableRes
+import com.android.permissioncontroller.R
+
+class MoreIssuesCardAnimator {
+ private val textFadeAnimator = TextFadeAnimator(R.id.widget_title)
+
+ fun animateStatusIconsChange(
+ statusIcon: ImageView,
+ startSeverityLevel: Int,
+ endSeverityLevel: Int,
+ @DrawableRes endSeverityLevelResId: Int
+ ) {
+ val severityLevelAnimationResId =
+ selectIconAnimationResId(startSeverityLevel, endSeverityLevel)
+ statusIcon.setImageResource(severityLevelAnimationResId)
+ val setStatusIconDrawable = statusIcon.drawable
+ if (setStatusIconDrawable is AnimatedVectorDrawable) {
+ setStatusIconDrawable.registerAnimationCallback(
+ object : Animatable2.AnimationCallback() {
+ override fun onAnimationEnd(drawable: Drawable) {
+ 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) {
+ statusDrawable.clearAnimationCallbacks()
+ statusDrawable.stop()
+ }
+ }
+
+ fun animateChangeText(textView: TextView, text: String) {
+ textFadeAnimator.animateChangeText(textView, text)
+ }
+
+ fun cancelTextChangeAnimation(textView: TextView) {
+ textFadeAnimator.cancelTextChangeAnimation(textView)
+ }
+
+ @DrawableRes
+ private fun selectIconAnimationResId(startSeverityLevel: Int, endSeverityLevel: Int): Int {
+ return when (endSeverityLevel) {
+ SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK ->
+ when (startSeverityLevel) {
+ SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK ->
+ R.drawable.safety_status_small_info_to_info_anim
+ SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION ->
+ R.drawable.safety_status_small_recommendation_to_info_anim
+ SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING ->
+ R.drawable.safety_status_small_warn_to_info_anim
+ else -> R.drawable.ic_safety_info
+ }
+ SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION ->
+ when (startSeverityLevel) {
+ SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK ->
+ R.drawable.safety_status_small_info_to_recommendation_anim
+ SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION ->
+ R.drawable.safety_status_small_recommendation_to_recommendation_anim
+ SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING ->
+ R.drawable.safety_status_small_warn_to_recommendation_anim
+ else -> R.drawable.ic_safety_recommendation
+ }
+ SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING ->
+ when (startSeverityLevel) {
+ SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK ->
+ R.drawable.safety_status_small_info_to_warn_anim
+ SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION ->
+ R.drawable.safety_status_small_recommendation_to_warn_anim
+ SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING ->
+ R.drawable.safety_status_small_warn_to_warn_anim
+ else -> R.drawable.ic_safety_warn
+ }
+ else -> {
+ Log.e(
+ MoreIssuesCardPreference.TAG,
+ String.format(
+ "Unexpected SafetyCenterIssue.IssueSeverityLevel: %d", endSeverityLevel))
+ R.drawable.ic_safety_null_state
+ }
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardPreference.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardPreference.kt
new file mode 100644
index 000000000..a63e19984
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardPreference.kt
@@ -0,0 +1,98 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui
+
+import android.content.Context
+import android.os.Build
+import androidx.annotation.DrawableRes
+import androidx.annotation.RequiresApi
+import androidx.preference.Preference
+import androidx.preference.PreferenceViewHolder
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.safetycenter.ui.view.MoreIssuesHeaderView
+
+/** A preference that displays a card linking to a list of more {@link SafetyCenterIssue}. */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+internal class MoreIssuesCardPreference(
+ context: Context,
+ @DrawableRes val overrideChevronIconResId: Int?,
+ private var previousMoreIssuesCardData: MoreIssuesCardData?,
+ private var newMoreIssuesCardData: MoreIssuesCardData,
+ private val dismissedOnly: Boolean,
+ val isStaticHeader: Boolean,
+ private val onClickListener: () -> Unit
+) : Preference(context), ComparablePreference {
+
+ init {
+ layoutResource = R.layout.preference_more_issues_card
+ }
+
+ override fun onBindViewHolder(holder: PreferenceViewHolder) {
+ super.onBindViewHolder(holder)
+
+ val issueHeaderView = holder.itemView as MoreIssuesHeaderView
+ if (isStaticHeader) {
+ issueHeaderView.showStaticHeader(
+ context.getString(R.string.safety_center_dismissed_issues_card_title),
+ newMoreIssuesCardData.severityLevel
+ )
+ } else {
+ issueHeaderView.showExpandableHeader(
+ previousMoreIssuesCardData,
+ newMoreIssuesCardData,
+ context.getString(
+ if (dismissedOnly) {
+ R.string.safety_center_dismissed_issues_card_title
+ } else {
+ R.string.safety_center_more_issues_card_title
+ }
+ ),
+ overrideChevronIconResId,
+ onClickListener
+ )
+ }
+ }
+
+ fun setNewMoreIssuesCardData(moreIssuesCardData: MoreIssuesCardData) {
+ previousMoreIssuesCardData = newMoreIssuesCardData
+ newMoreIssuesCardData = moreIssuesCardData
+ notifyChanged()
+ }
+
+ override fun isSameItem(preference: Preference): Boolean {
+ return preference is MoreIssuesCardPreference && isStaticHeader == preference.isStaticHeader
+ }
+
+ override fun hasSameContents(preference: Preference): Boolean {
+ return preference is MoreIssuesCardPreference &&
+ isStaticHeader == preference.isStaticHeader &&
+ previousMoreIssuesCardData == preference.previousMoreIssuesCardData &&
+ newMoreIssuesCardData == preference.newMoreIssuesCardData &&
+ overrideChevronIconResId == preference.overrideChevronIconResId &&
+ dismissedOnly == preference.dismissedOnly
+ }
+
+ companion object {
+ val TAG: String = MoreIssuesCardPreference::class.java.simpleName
+ }
+}
+
+internal data class MoreIssuesCardData(
+ val severityLevel: Int,
+ val hiddenIssueCount: Int,
+ val isExpanded: Boolean
+)
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ParsedSafetyCenterIntent.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ParsedSafetyCenterIntent.kt
new file mode 100644
index 000000000..6bf4b52e8
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/ParsedSafetyCenterIntent.kt
@@ -0,0 +1,78 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui
+
+import android.content.Intent
+import android.os.Build
+import android.os.UserHandle
+import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_ID
+import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_ISSUE_ID
+import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_USER_HANDLE
+import androidx.annotation.RequiresApi
+import com.android.permissioncontroller.safetycenter.SafetyCenterConstants.EXPAND_ISSUE_GROUP_QS_FRAGMENT_KEY
+import com.android.safetycenter.internaldata.SafetyCenterIssueKey
+
+/** Class representing parsed intent extra values for use in [SafetyCenterDashboardFragment] */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+data class ParsedSafetyCenterIntent(
+ val safetyCenterIssueKey: SafetyCenterIssueKey? = null,
+ val shouldExpandIssuesGroup: Boolean
+) {
+ companion object {
+ @JvmStatic
+ fun Intent.toSafetyCenterIntent(): ParsedSafetyCenterIntent {
+ val safetySourceId: String? = getStringExtra(EXTRA_SAFETY_SOURCE_ID)
+ val safetySourceIssueId: String? = getStringExtra(EXTRA_SAFETY_SOURCE_ISSUE_ID)
+ val safetySourceUserHandle: UserHandle? =
+ getParcelableExtra(EXTRA_SAFETY_SOURCE_USER_HANDLE, UserHandle::class.java)
+ val safetyCenterIssueKey: SafetyCenterIssueKey? =
+ createSafetyCenterIssueKey(
+ safetySourceId, safetySourceIssueId, safetySourceUserHandle)
+
+ // Check if we've navigated from QS or if focusing on single issue and issues should be
+ // expanded
+ val shouldExpandIssuesGroup: Boolean =
+ getBooleanExtra(EXPAND_ISSUE_GROUP_QS_FRAGMENT_KEY, false)
+
+ return ParsedSafetyCenterIntent(safetyCenterIssueKey, shouldExpandIssuesGroup)
+ }
+
+ /**
+ * Creates [SafetyCenterIssueKey] using the provided values
+ *
+ * @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
+ */
+ private fun createSafetyCenterIssueKey(
+ safetySourceId: String?,
+ safetySourceIssueId: String?,
+ safetySourceUserHandle: UserHandle?
+ ): SafetyCenterIssueKey? {
+ if (safetySourceId == null || safetySourceIssueId == null) {
+ return null
+ }
+ return SafetyCenterIssueKey.newBuilder()
+ .setSafetySourceId(safetySourceId)
+ .setSafetySourceIssueId(safetySourceIssueId)
+ // Default to current user
+ .setUserId(safetySourceUserHandle?.identifier ?: UserHandle.myUserId())
+ .build()
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PendingIntentSender.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PendingIntentSender.kt
new file mode 100644
index 000000000..bb953399b
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PendingIntentSender.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui
+
+import android.app.PendingIntent
+import android.os.Build.VERSION_CODES.TIRAMISU
+import androidx.annotation.RequiresApi
+import androidx.fragment.app.FragmentActivity
+import com.android.safetycenter.internaldata.SafetyCenterIds
+
+/** An object which sends pendingIntents, in a proper task, if needed. */
+@RequiresApi(TIRAMISU)
+object PendingIntentSender {
+
+ @JvmStatic
+ @Throws(PendingIntent.CanceledException::class)
+ fun send(pi: PendingIntent?, launchTaskId: Int? = null) {
+ if (pi == null) {
+ return
+ }
+ com.android.safetycenter.pendingintents.PendingIntentSender.send(pi, launchTaskId)
+ }
+
+ /**
+ * Gets the current task ID for sending pending intents in a fragment
+ *
+ * @param entryId identifies an entry on the Safety Center page
+ * @param sameTaskSourceIds list of safety source IDs to show in the same task as Safety Center
+ * @param activity represents the parent activity of the fragment
+ */
+ @JvmStatic
+ fun getTaskIdForEntry(
+ entryId: String,
+ sameTaskSourceIds: List<String>,
+ activity: FragmentActivity
+ ): Int? {
+ val sourceId: String = SafetyCenterIds.entryIdFromString(entryId).getSafetySourceId()
+ return if (sameTaskSourceIds.contains(sourceId)) activity.getTaskId() else null
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PositionInCardList.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PositionInCardList.kt
new file mode 100644
index 000000000..01e8f8d15
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PositionInCardList.kt
@@ -0,0 +1,90 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui
+
+import android.content.Context
+import com.android.permissioncontroller.R
+
+/**
+ * Determines the correct background drawable for a given element in the Safety Center card list.
+ *
+ * This class helps transform a flat list of elements (which are typically Preferences in the
+ * PreferenceScreen's recycler view) into a visually grouped list of cards by providing the correct
+ * background drawable for each element based on both its position in the flat list of elements and
+ * its conceptual position in the card list. While Preferences have a nested XML structure, with
+ * Preferences nested inside of PreferenceGroups, they are displayed as a flat list of views, with
+ * the PreferenceGroup's view inserted as a header above its constituent preference's views.
+ *
+ * A list is a group conceptually-related of cards. The top card in the list has large top corners
+ * and the bottom card in the list has large bottom corners. Corners between cards in the list are
+ * small. In the Safety Center, the entry list is a single list.
+ *
+ * A card is a group of one or more elements that appear as a single visual card, without corners
+ * between its constituent elements. In the Safety Center, a single expanded entry list group is a
+ * single card composed of a list of separate preferences (one for the header and one for each entry
+ * in the group).
+ */
+internal enum class PositionInCardList(val backgroundDrawableResId: Int) {
+ INSIDE_GROUP(R.drawable.safety_group_entry_background),
+ LIST_START_END(R.drawable.safety_entity_top_large_bottom_large_background),
+ LIST_START(R.drawable.safety_entity_top_large_bottom_flat_background),
+ LIST_START_CARD_END(R.drawable.safety_entity_top_large_bottom_small_background),
+ CARD_START(R.drawable.safety_entity_top_small_bottom_flat_background),
+ CARD_START_END(R.drawable.safety_entity_top_small_bottom_small_background),
+ CARD_START_LIST_END(R.drawable.safety_entity_top_small_bottom_large_background),
+ CARD_ELEMENT(R.drawable.safety_entity_top_flat_bottom_flat_background),
+ CARD_END(R.drawable.safety_entity_top_flat_bottom_small_background),
+ LIST_END(R.drawable.safety_entity_top_flat_bottom_large_background);
+
+ 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)
+ else -> 0
+ }
+
+ companion object {
+ @JvmStatic
+ @JvmOverloads
+ fun calculate(
+ isListStart: Boolean,
+ isListEnd: Boolean,
+ isCardStart: Boolean = !isListStart,
+ isCardEnd: Boolean = !isListEnd
+ ): PositionInCardList =
+ if (isListStart && isListEnd) {
+ LIST_START_END
+ } else if (isListStart && isCardEnd) {
+ LIST_START_CARD_END
+ } else if (isListEnd && isCardStart) {
+ CARD_START_LIST_END
+ } else if (isCardStart && isCardEnd) {
+ CARD_START_END
+ } else if (isListStart) {
+ LIST_START
+ } else if (isListEnd) {
+ LIST_END
+ } else if (isCardStart) {
+ CARD_START
+ } else if (isCardEnd) {
+ CARD_END
+ } else {
+ CARD_ELEMENT
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PreferenceHighlightManager.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PreferenceHighlightManager.kt
new file mode 100644
index 000000000..2acd6b5a3
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PreferenceHighlightManager.kt
@@ -0,0 +1,131 @@
+/*
+ * 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.safetycenter.ui
+
+import android.os.Bundle
+import androidx.preference.PreferenceFragmentCompat
+import androidx.preference.PreferenceScreen
+import androidx.recyclerview.widget.RecyclerView
+import com.android.permissioncontroller.safetycenter.SafetyCenterConstants.EXTRA_SETTINGS_FRAGMENT_ARGS_KEY
+import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity
+
+/** Class used to scroll and highlight preferences for settings search. */
+internal class PreferenceHighlightManager(private val fragment: PreferenceFragmentCompat) {
+ private var preferenceHighlighted = false
+ private var isDataSetObserverRegistered = false
+
+ private var currentRootAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>? = null
+ private var preferenceGroupAdapter: HighlightablePreferenceGroupAdapter? = null
+ private val dataSetObserver: RecyclerView.AdapterDataObserver =
+ object : RecyclerView.AdapterDataObserver() {
+ override fun onChanged() {
+ highlightPreferenceIfNeeded()
+ }
+
+ override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
+ highlightPreferenceIfNeeded()
+ }
+
+ override fun onItemRangeChanged(positionStart: Int, itemCount: Int, payload: Any?) {
+ highlightPreferenceIfNeeded()
+ }
+
+ override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
+ highlightPreferenceIfNeeded()
+ }
+
+ override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
+ highlightPreferenceIfNeeded()
+ }
+
+ override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {
+ highlightPreferenceIfNeeded()
+ }
+ }
+
+ /** Creates a new [HighlightablePreferenceGroupAdapter] instance */
+ fun createAdapter(
+ preferenceScreen: PreferenceScreen?,
+ ): RecyclerView.Adapter<RecyclerView.ViewHolder> {
+ val intent = fragment.getActivity()?.getIntent()
+ preferenceGroupAdapter =
+ HighlightablePreferenceGroupAdapter(
+ preferenceScreen,
+ intent?.getStringExtra(EXTRA_SETTINGS_FRAGMENT_ARGS_KEY),
+ preferenceHighlighted
+ )
+ @Suppress("UNCHECKED_CAST")
+ return preferenceGroupAdapter!! as RecyclerView.Adapter<RecyclerView.ViewHolder>
+ }
+
+ /** Restore previously saved instance state from [Bundle] */
+ fun restoreState(savedInstanceState: Bundle?) {
+ if (!SafetyCenterUiFlags.getShowSubpages() || savedInstanceState == null) {
+ return
+ }
+
+ preferenceHighlighted = savedInstanceState.getBoolean(SAVE_HIGHLIGHTED_KEY, false)
+ }
+
+ /** Save current instance state to provided [Bundle] */
+ fun saveState(outState: Bundle) {
+ if (!SafetyCenterUiFlags.getShowSubpages()) {
+ return
+ }
+
+ val highlightRequested = preferenceGroupAdapter?.isHighlightRequested
+ highlightRequested?.let { outState.putBoolean(SAVE_HIGHLIGHTED_KEY, it) }
+ }
+
+ /** Scrolls to a particular preference in the recycler view and highlights it */
+ fun highlightPreferenceIfNeeded() {
+ if (!SafetyCenterUiFlags.getShowSubpages() || !fragment.isAdded()) {
+ return
+ }
+
+ val collapsingActivity = fragment.getActivity() as? CollapsingToolbarBaseActivity
+ preferenceGroupAdapter?.requestHighlight(
+ fragment.getView(),
+ fragment.getListView(),
+ collapsingActivity?.appBarLayout
+ )
+ }
+
+ /** Registers the observer while binding preferences */
+ fun registerObserverIfNeeded() {
+ if (!isDataSetObserverRegistered) {
+ currentRootAdapter?.unregisterAdapterDataObserver(dataSetObserver)
+ currentRootAdapter = fragment.getListView()?.getAdapter()
+ currentRootAdapter?.registerAdapterDataObserver(dataSetObserver)
+ isDataSetObserverRegistered = true
+ highlightPreferenceIfNeeded()
+ }
+ }
+
+ /** Unregisters the observer while unbinding preferences */
+ fun unregisterObserverIfNeeded() {
+ if (isDataSetObserverRegistered) {
+ currentRootAdapter?.unregisterAdapterDataObserver(dataSetObserver)
+ currentRootAdapter = null
+ isDataSetObserverRegistered = false
+ }
+ }
+
+ companion object {
+ private const val SAVE_HIGHLIGHTED_KEY: String = "android:preference_highlighted"
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PrivacyControlsFragment.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PrivacyControlsFragment.java
new file mode 100644
index 000000000..43a8877d4
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PrivacyControlsFragment.java
@@ -0,0 +1,82 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui;
+
+import android.os.Build;
+import android.os.Bundle;
+
+import androidx.annotation.RequiresApi;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.preference.PreferenceFragmentCompat;
+
+import com.android.permissioncontroller.R;
+import com.android.permissioncontroller.safetycenter.ui.model.PrivacyControlsViewModel;
+import com.android.permissioncontroller.safetycenter.ui.model.PrivacyControlsViewModel.Pref;
+import com.android.permissioncontroller.safetycenter.ui.model.PrivacyControlsViewModel.PrefState;
+import com.android.permissioncontroller.safetycenter.ui.model.PrivacyControlsViewModelFactory;
+
+import java.util.Map;
+
+/** Fragment that shows several privacy toggle controls, alongside a link to location settings */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+public final class PrivacyControlsFragment extends PreferenceFragmentCompat {
+
+ /** Create a new instance of this fragment */
+ public static PrivacyControlsFragment newInstance() {
+ return new PrivacyControlsFragment();
+ }
+
+ private PrivacyControlsViewModel mViewModel;
+ private String mRootKey;
+ private boolean mPrefsSet;
+
+ @Override
+ public void onCreatePreferences(Bundle bundle, String rootKey) {
+ mRootKey = rootKey;
+ mPrefsSet = false;
+
+ PrivacyControlsViewModelFactory factory =
+ new PrivacyControlsViewModelFactory(getActivity().getApplication());
+ mViewModel = new ViewModelProvider(this, factory).get(PrivacyControlsViewModel.class);
+ mViewModel.getControlStateLiveData().observe(this, this::setPreferences);
+ }
+
+ private void setPreferences(Map<Pref, PrefState> prefStates) {
+ // Delaying setting of preferences, in order to avoid disabled prefs being briefly visible
+ if (!mPrefsSet) {
+ setPreferencesFromResource(R.xml.privacy_controls, mRootKey);
+ mPrefsSet = true;
+ }
+
+ setSwitchPreference(prefStates, Pref.MIC);
+ setSwitchPreference(prefStates, Pref.CAMERA);
+ setSwitchPreference(prefStates, Pref.CLIPBOARD);
+ setSwitchPreference(prefStates, Pref.SHOW_PASSWORD);
+
+ findPreference(Pref.LOCATION.getKey())
+ .setOnPreferenceClickListener(
+ (v) -> {
+ mViewModel.handlePrefClick(this, Pref.LOCATION, null);
+ return true;
+ });
+ }
+
+ private void setSwitchPreference(Map<Pref, PrefState> prefStates, Pref prefType) {
+ ClickableDisabledSwitchPreference preference = findPreference(prefType.getKey());
+ preference.setupState(prefStates.get(prefType), prefType, mViewModel, this);
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PrivacySubpageFragment.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PrivacySubpageFragment.kt
new file mode 100644
index 000000000..54ba9560f
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/PrivacySubpageFragment.kt
@@ -0,0 +1,185 @@
+/*
+ * 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.safetycenter.ui
+
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import android.os.Bundle
+import android.safetycenter.SafetyCenterEntryGroup
+import android.util.Log
+import androidx.annotation.RequiresApi
+import androidx.lifecycle.ViewModelProvider
+import androidx.preference.Preference
+import androidx.preference.PreferenceGroup
+import com.android.permissioncontroller.Constants.EXTRA_SESSION_ID
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.safetycenter.SafetyCenterConstants.PRIVACY_SOURCES_GROUP_ID
+import com.android.permissioncontroller.safetycenter.ui.SafetyBrandChipPreference.Companion.closeSubpage
+import com.android.permissioncontroller.safetycenter.ui.model.PrivacyControlsViewModel
+import com.android.permissioncontroller.safetycenter.ui.model.PrivacyControlsViewModel.Pref
+import com.android.permissioncontroller.safetycenter.ui.model.PrivacyControlsViewModel.PrefState
+import com.android.permissioncontroller.safetycenter.ui.model.PrivacyControlsViewModelFactory
+import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterUiData
+import com.android.safetycenter.internaldata.SafetyCenterIds
+
+/** A fragment that represents the privacy subpage in Safety Center. */
+@RequiresApi(UPSIDE_DOWN_CAKE)
+class PrivacySubpageFragment : SafetyCenterFragment() {
+
+ private lateinit var subpageBrandChip: SafetyBrandChipPreference
+ private lateinit var subpageIssueGroup: PreferenceGroup
+ private lateinit var subpageGenericEntryGroup: PreferenceGroup
+ private lateinit var subpageControlsExtraEntryGroup: PreferenceGroup
+ private lateinit var privacyControlsViewModel: PrivacyControlsViewModel
+
+ override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
+ super.onCreatePreferences(savedInstanceState, rootKey)
+ setPreferencesFromResource(R.xml.privacy_subpage, rootKey)
+
+ subpageBrandChip = getPreferenceScreen().findPreference(BRAND_CHIP_KEY)!!
+ subpageIssueGroup = getPreferenceScreen().findPreference(ISSUE_GROUP_KEY)!!
+ subpageGenericEntryGroup = getPreferenceScreen().findPreference(GENERIC_ENTRY_GROUP_KEY)!!
+ subpageControlsExtraEntryGroup =
+ getPreferenceScreen().findPreference(CONTROLS_EXTRA_ENTRY_GROUP_KEY)!!
+ subpageBrandChip.setupListener(requireActivity(), safetyCenterSessionId)
+
+ val factory = PrivacyControlsViewModelFactory(requireActivity().getApplication())
+ privacyControlsViewModel =
+ ViewModelProvider(this, factory).get(PrivacyControlsViewModel::class.java)
+ privacyControlsViewModel.controlStateLiveData.observe(this) {
+ prefStates: Map<Pref, PrefState> ->
+ renderPrivacyControls(prefStates)
+ }
+
+ prerenderCurrentSafetyCenterData()
+ }
+
+ override fun configureInteractionLogger() {
+ val logger = safetyCenterViewModel.interactionLogger
+ logger.sessionId = safetyCenterSessionId
+ logger.navigationSource = NavigationSource.fromIntent(requireActivity().getIntent())
+ logger.viewType = ViewType.SUBPAGE
+ logger.groupId = PRIVACY_SOURCES_GROUP_ID
+ }
+
+ override fun onResume() {
+ super.onResume()
+ safetyCenterViewModel.pageOpen(PRIVACY_SOURCES_GROUP_ID)
+ }
+
+ override fun renderSafetyCenterData(uiData: SafetyCenterUiData?) {
+ Log.d(TAG, "renderSafetyCenterEntryGroup called with $uiData")
+ val entryGroup = uiData?.getMatchingGroup(PRIVACY_SOURCES_GROUP_ID)
+ if (entryGroup == null) {
+ Log.w(
+ TAG,
+ "$PRIVACY_SOURCES_GROUP_ID doesn't match any of the existing SafetySourcesGroup IDs"
+ )
+ closeSubpage(requireActivity(), requireContext(), safetyCenterSessionId)
+ return
+ }
+
+ requireActivity().setTitle(entryGroup.title)
+ updateSafetyCenterIssues(uiData)
+ updateSafetyCenterEntries(entryGroup)
+ }
+
+ private fun updateSafetyCenterIssues(uiData: SafetyCenterUiData?) {
+ subpageIssueGroup.removeAll()
+ val subpageIssues = uiData?.getMatchingIssues(PRIVACY_SOURCES_GROUP_ID)
+ val subpageDismissedIssues = uiData?.getMatchingDismissedIssues(PRIVACY_SOURCES_GROUP_ID)
+ if (subpageIssues.isNullOrEmpty() && subpageDismissedIssues.isNullOrEmpty()) {
+ Log.w(TAG, "$PRIVACY_SOURCES_GROUP_ID doesn't have any matching SafetyCenterIssues")
+ return
+ }
+
+ collapsableIssuesCardHelper.addIssues(
+ requireContext(),
+ safetyCenterViewModel,
+ getChildFragmentManager(),
+ subpageIssueGroup,
+ subpageIssues,
+ subpageDismissedIssues,
+ uiData.resolvedIssues,
+ requireActivity().getTaskId())
+ }
+
+ private fun updateSafetyCenterEntries(entryGroup: SafetyCenterEntryGroup) {
+ Log.d(TAG, "updateSafetyCenterEntries called with $entryGroup")
+ subpageGenericEntryGroup.removeAll()
+ subpageControlsExtraEntryGroup.removeAll()
+
+ for (entry in entryGroup.entries) {
+ val entryId = entry.id
+ val sourceId = SafetyCenterIds.entryIdFromString(entryId).getSafetySourceId()
+
+ val subpageEntry =
+ SafetySubpageEntryPreference(
+ requireContext(),
+ PendingIntentSender.getTaskIdForEntry(
+ entryId, sameTaskSourceIds, requireActivity()),
+ entry,
+ safetyCenterViewModel)
+
+ if (sourceId == "AndroidPrivacyControls") {
+ // No action required here because the privacy controls are rendered separately
+ // by this fragment as generic preferences.
+ } else if (sourceId.endsWith("ActivityControls")) {
+ subpageControlsExtraEntryGroup.addPreference(subpageEntry)
+ } else {
+ subpageGenericEntryGroup.addPreference(subpageEntry)
+ }
+ }
+ }
+
+ private fun renderPrivacyControls(prefStates: Map<Pref, PrefState>) {
+ fun setSwitchPreference(prefType: Pref) {
+ val switchPreference: ClickableDisabledSwitchPreference? = findPreference(prefType.key)
+ switchPreference?.setupState(
+ prefStates[prefType], prefType, privacyControlsViewModel, this)
+ }
+
+ setSwitchPreference(Pref.MIC)
+ setSwitchPreference(Pref.CAMERA)
+ setSwitchPreference(Pref.CLIPBOARD)
+ setSwitchPreference(Pref.SHOW_PASSWORD)
+
+ val locationEntry: Preference? = findPreference(Pref.LOCATION.key)
+ locationEntry?.setOnPreferenceClickListener {
+ privacyControlsViewModel.handlePrefClick(this, Pref.LOCATION, null)
+ true
+ }
+ }
+
+ companion object {
+ private val TAG: String = PrivacySubpageFragment::class.java.simpleName
+ private const val BRAND_CHIP_KEY: String = "subpage_brand_chip"
+ private const val ISSUE_GROUP_KEY: String = "subpage_issue_group"
+ private const val GENERIC_ENTRY_GROUP_KEY: String = "subpage_generic_entry_group"
+ private const val CONTROLS_EXTRA_ENTRY_GROUP_KEY: String =
+ "subpage_controls_extra_entry_group"
+ /** Creates an instance of PrivacySubpageFragment with the arguments set */
+ @JvmStatic
+ fun newInstance(sessionId: Long): PrivacySubpageFragment {
+ val args = Bundle()
+ args.putLong(EXTRA_SESSION_ID, sessionId)
+
+ val subpageFragment = PrivacySubpageFragment()
+ subpageFragment.setArguments(args)
+ return subpageFragment
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyBrandChipPreference.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyBrandChipPreference.kt
new file mode 100644
index 000000000..bf2d0565c
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyBrandChipPreference.kt
@@ -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.safetycenter.ui
+
+import android.content.Context
+import android.content.Intent
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import android.util.AttributeSet
+import android.view.View
+import androidx.annotation.RequiresApi
+import androidx.fragment.app.FragmentActivity
+import androidx.preference.Preference
+import androidx.preference.PreferenceViewHolder
+import com.android.permissioncontroller.Constants.EXTRA_SESSION_ID
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.safetycenter.SafetyCenterConstants
+
+/** A preference that displays the Security and Privacy brand name on a Safety Center subpage. */
+@RequiresApi(UPSIDE_DOWN_CAKE)
+internal class SafetyBrandChipPreference(context: Context, attrs: AttributeSet) :
+ Preference(context, attrs) {
+
+ init {
+ setLayoutResource(R.layout.preference_brand_chip)
+ }
+
+ private var brandChipClickListener: View.OnClickListener? = null
+
+ override fun onBindViewHolder(holder: PreferenceViewHolder) {
+ super.onBindViewHolder(holder)
+ val brandChipButton = holder.findViewById(R.id.brand_chip)
+ brandChipButton.setOnClickListener(brandChipClickListener)
+ }
+
+ /**
+ * Sets the listener that handles clicks for the brand chip
+ *
+ * @param activity represents the parent activity of the fragment
+ * @param sessionId identifier for the current session
+ */
+ fun setupListener(activity: FragmentActivity, sessionId: Long) {
+ brandChipClickListener = View.OnClickListener { closeSubpage(activity, context, sessionId) }
+ }
+
+ companion object {
+ /**
+ * Closes the subpage and optionally opens up the homepage
+ *
+ * @param fragmentActivity represents the parent activity of the fragment
+ * @param fragmentContext represents the context associated with the fragment
+ * @param sessionId identifier for the current session
+ */
+ fun closeSubpage(
+ fragmentActivity: FragmentActivity,
+ fragmentContext: Context,
+ sessionId: Long
+ ) {
+ val openedFromHomepage =
+ fragmentActivity
+ .getIntent()
+ .getBooleanExtra(SafetyCenterConstants.EXTRA_OPENED_FROM_HOMEPAGE, false)
+ if (!openedFromHomepage) {
+ val intent = Intent(Intent.ACTION_SAFETY_CENTER)
+ intent.putExtra(EXTRA_SESSION_ID, sessionId)
+ NavigationSource.SAFETY_CENTER.addToIntent(intent)
+ fragmentContext.startActivity(intent)
+ }
+ fragmentActivity.finish()
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java
index 9ae4eb673..8f31da828 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,44 +15,253 @@
*/
package com.android.permissioncontroller.safetycenter.ui;
+import static android.content.Intent.ACTION_SAFETY_CENTER;
import static android.content.Intent.FLAG_ACTIVITY_FORWARD_RESULT;
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+import static android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCES_GROUP_ID;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_NOTIFICATION_INTERACTION;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__ACTION__NOTIFICATION_CLICKED;
+import static com.android.permissioncontroller.safetycenter.SafetyCenterConstants.EXTRA_SETTINGS_FRAGMENT_ARGS_KEY;
+import static com.android.permissioncontroller.safetycenter.SafetyCenterConstants.PERSONAL_PROFILE_SUFFIX;
+import static com.android.permissioncontroller.safetycenter.SafetyCenterConstants.PRIVACY_SOURCES_GROUP_ID;
+import static com.android.permissioncontroller.safetycenter.SafetyCenterConstants.WORK_PROFILE_SUFFIX;
+
+import android.app.ActionBar;
import android.content.Intent;
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.util.Log;
-import androidx.annotation.Keep;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.fragment.app.Fragment;
+import com.android.permissioncontroller.Constants;
+import com.android.permissioncontroller.PermissionControllerStatsLog;
import com.android.permissioncontroller.R;
+import com.android.permissioncontroller.permission.utils.Utils;
+import com.android.permissioncontroller.safetycenter.ui.model.PrivacyControlsViewModel.Pref;
+import com.android.settingslib.activityembedding.ActivityEmbeddingUtils;
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
-/**
- * Entry-point activity for SafetyCenter.
- */
-@Keep
+import java.util.List;
+import java.util.Objects;
+
+/** Entry-point activity for SafetyCenter. */
+@RequiresApi(TIRAMISU)
public final class SafetyCenterActivity extends CollapsingToolbarBaseActivity {
private static final String TAG = SafetyCenterActivity.class.getSimpleName();
+ private static final String PRIVACY_CONTROLS_ACTION = "android.settings.PRIVACY_CONTROLS";
+ private static final String MENU_KEY_SAFETY_CENTER = "top_level_safety_center";
+ private static final String EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI =
+ "android.provider.extra.SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI";
+ private static final String EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY =
+ "android.provider.extra.SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY";
+ private static final String EXTRA_PREVENT_TRAMPOLINE_TO_SETTINGS =
+ "com.android.permissioncontroller.safetycenter.extra.PREVENT_TRAMPOLINE_TO_SETTINGS";
+
+ private SafetyCenterManager mSafetyCenterManager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- SafetyCenterManager safetyCenterManager = getSystemService(SafetyCenterManager.class);
+ mSafetyCenterManager = getSystemService(SafetyCenterManager.class);
+
+ if (maybeRedirectIfDisabled()) {
+ return;
+ }
+
+ if (maybeRedirectIntoTwoPaneSettings()) {
+ return;
+ }
+
+ Fragment frag;
+ final boolean maybeOpenSubpage =
+ SafetyCenterUiFlags.getShowSubpages()
+ && getIntent().getAction().equals(ACTION_SAFETY_CENTER);
+ if (maybeOpenSubpage && getIntent().hasExtra(EXTRA_SAFETY_SOURCES_GROUP_ID)) {
+ String groupId = getIntent().getStringExtra(EXTRA_SAFETY_SOURCES_GROUP_ID);
+ frag = openRelevantSubpage(groupId);
+ } else if (maybeOpenSubpage && getIntent().hasExtra(EXTRA_SETTINGS_FRAGMENT_ARGS_KEY)) {
+ String preferenceKey = getIntent().getStringExtra(EXTRA_SETTINGS_FRAGMENT_ARGS_KEY);
+ String groupId = getParentGroupId(preferenceKey);
+ frag = openRelevantSubpage(groupId);
+ } else if (getIntent().getAction().equals(PRIVACY_CONTROLS_ACTION)) {
+ setTitle(R.string.privacy_controls_title);
+ frag = PrivacyControlsFragment.newInstance();
+ } else {
+ frag = openHomepage();
+ }
+
+ if (savedInstanceState == null) {
+ getSupportFragmentManager()
+ .beginTransaction()
+ .add(R.id.content_frame, frag)
+ .commitNow();
+ }
- if (safetyCenterManager == null || !safetyCenterManager.isSafetyCenterEnabled()) {
+ ActionBar actionBar = getActionBar();
+ // 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
+ // Center ("third layer").
+ // 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)) {
+ 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));
+ startActivity(
+ new Intent(Settings.ACTION_SETTINGS).addFlags(FLAG_ACTIVITY_FORWARD_RESULT));
finish();
- return;
+ return true;
+ }
+ return false;
+ }
+
+ private boolean maybeRedirectIntoTwoPaneSettings() {
+ return shouldUseTwoPaneSettings() && tryRedirectTwoPaneSettings();
+ }
+
+ private boolean shouldUseTwoPaneSettings() {
+ if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this)) {
+ return false;
+ }
+
+ Bundle extras = getIntent().getExtras();
+ if (extras != null && extras.getBoolean(EXTRA_PREVENT_TRAMPOLINE_TO_SETTINGS, false)) {
+ return false;
}
+ return isTaskRoot() && !ActivityEmbeddingUtils.isActivityEmbedded(this);
+ }
+
+ /** Return {@code true} if the redirection was attempted. */
+ private boolean tryRedirectTwoPaneSettings() {
+ Intent twoPaneIntent = getTwoPaneIntent();
+ if (twoPaneIntent == null) {
+ return false;
+ }
+
+ Log.i(TAG, "Safety Center restarting in Settings two-pane layout");
+ startActivity(twoPaneIntent);
+ finishAndRemoveTask();
+ return true;
+ }
+
+ @Nullable
+ private Intent getTwoPaneIntent() {
+ Intent twoPaneIntent = ActivityEmbeddingUtils.buildEmbeddingActivityBaseIntent(this);
+ if (twoPaneIntent == null) {
+ return null;
+ }
+
+ twoPaneIntent.putExtras(getIntent());
+ twoPaneIntent.putExtra(
+ EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI,
+ getIntent().toUri(Intent.URI_INTENT_SCHEME));
+ twoPaneIntent.putExtra(
+ EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY, MENU_KEY_SAFETY_CENTER);
+ return twoPaneIntent;
+ }
+
+ private void logPrivacySourceMetric() {
+ Intent intent = getIntent();
+ if (intent != null && intent.hasExtra(Constants.EXTRA_PRIVACY_SOURCE)) {
+ int privacySource = intent.getIntExtra(Constants.EXTRA_PRIVACY_SOURCE, -1);
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ long sessionId =
+ intent.getLongExtra(Constants.EXTRA_SESSION_ID, Constants.INVALID_SESSION_ID);
+ Log.v(
+ TAG,
+ "privacy source notification metric, source "
+ + privacySource
+ + " uid "
+ + uid
+ + " sessionId "
+ + sessionId);
+ PermissionControllerStatsLog.write(
+ PRIVACY_SIGNAL_NOTIFICATION_INTERACTION,
+ privacySource,
+ uid,
+ PRIVACY_SIGNAL_NOTIFICATION_INTERACTION__ACTION__NOTIFICATION_CLICKED,
+ sessionId);
+ }
+ }
+
+ private Fragment openHomepage() {
+ logPrivacySourceMetric();
setTitle(getString(R.string.safety_center_dashboard_page_title));
- getSupportFragmentManager()
- .beginTransaction()
- .replace(R.id.content_frame, new SafetyCenterDashboardFragment())
- .commitNow();
+ return new SafetyCenterScrollWrapperFragment();
+ }
+
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ private Fragment openRelevantSubpage(String groupId) {
+ if (groupId.isEmpty()) {
+ return openHomepage();
+ }
+
+ long sessionId = Utils.getOrGenerateSessionId(getIntent());
+ if (Objects.equals(groupId, PRIVACY_SOURCES_GROUP_ID)) {
+ logPrivacySourceMetric();
+ return PrivacySubpageFragment.newInstance(sessionId);
+ }
+
+ return SafetyCenterSubpageFragment.newInstance(sessionId, groupId);
+ }
+
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ private String getParentGroupId(String preferenceKey) {
+ if (Pref.findByKey(preferenceKey) != null) {
+ return PRIVACY_SOURCES_GROUP_ID;
+ }
+
+ SafetyCenterConfig safetyCenterConfig = mSafetyCenterManager.getSafetyCenterConfig();
+ String[] splitKey;
+ if (preferenceKey.endsWith(PERSONAL_PROFILE_SUFFIX)) {
+ splitKey = preferenceKey.split("_" + PERSONAL_PROFILE_SUFFIX);
+ } else if (preferenceKey.endsWith(WORK_PROFILE_SUFFIX)) {
+ splitKey = preferenceKey.split("_" + WORK_PROFILE_SUFFIX);
+ } else {
+ return "";
+ }
+
+ if (safetyCenterConfig == null || splitKey.length == 0) {
+ return "";
+ }
+
+ List<SafetySourcesGroup> groups = safetyCenterConfig.getSafetySourcesGroups();
+ for (SafetySourcesGroup group : groups) {
+ if (group.getType() != SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATEFUL) {
+ // Hidden and static groups are not opened in a subpage.
+ continue;
+ }
+ for (SafetySource source : group.getSafetySources()) {
+ if (Objects.equals(source.getId(), splitKey[0])) {
+ return group.getId();
+ }
+ }
+ }
+ return "";
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterContentManager.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterContentManager.java
deleted file mode 100644
index e6738c29f..000000000
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterContentManager.java
+++ /dev/null
@@ -1,52 +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.permissioncontroller.safetycenter.ui;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** A helper for interacting with UI content from the SafetyCenter API. */
-public final class SafetyCenterContentManager {
-
- private static final Object sLock = new Object();
-
- /** Singleton instance. */
- static SafetyCenterContentManager sInstance;
-
- private SafetyCenterContentManager() {}
-
- /** Returns a singleton instance of {@link SafetyCenterContentManager}. */
- public static SafetyCenterContentManager getInstance() {
- if (sInstance != null) {
- return sInstance;
- }
-
- synchronized (sLock) {
- // Previously null sInstance can become non-null before lock is acquired.
- if (sInstance == null) {
- sInstance = new SafetyCenterContentManager();
- }
- return sInstance;
- }
- }
-
- /** Returns the list of safety entries. */
- public List<SafetyEntry> getSafetyEntries() {
- // TODO(b/206775474): Return entries from API
- return new ArrayList<>();
- }
-}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterDashboardFragment.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterDashboardFragment.java
index 443a56ac5..940cb2f69 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterDashboardFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterDashboardFragment.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,31 +16,49 @@
package com.android.permissioncontroller.safetycenter.ui;
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
+import static com.android.permissioncontroller.safetycenter.SafetyCenterConstants.QUICK_SETTINGS_SAFETY_CENTER_FRAGMENT;
+
+import static java.util.Collections.emptyList;
import static java.util.Objects.requireNonNull;
import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.safetycenter.SafetyCenterData;
+import android.safetycenter.SafetyCenterEntry;
+import android.safetycenter.SafetyCenterEntryGroup;
import android.safetycenter.SafetyCenterEntryOrGroup;
import android.safetycenter.SafetyCenterIssue;
-import android.safetycenter.SafetyCenterManager;
-import android.safetycenter.SafetyCenterManager.OnSafetyCenterDataChangedListener;
+import android.safetycenter.SafetyCenterStaticEntry;
import android.safetycenter.SafetyCenterStaticEntryGroup;
-import android.safetycenter.SafetyCenterStatus;
import android.util.Log;
-import androidx.annotation.NonNull;
-import androidx.core.content.ContextCompat;
-import androidx.preference.PreferenceFragmentCompat;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceGroup;
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 kotlin.Unit;
import java.util.List;
-import java.util.stream.Stream;
+import java.util.Map;
-/** Dashboard fragment for the Safety Center **/
-public final class SafetyCenterDashboardFragment extends PreferenceFragmentCompat {
+/** Dashboard fragment for the Safety Center. */
+@RequiresApi(TIRAMISU)
+public final class SafetyCenterDashboardFragment extends SafetyCenterFragment {
private static final String TAG = SafetyCenterDashboardFragment.class.getSimpleName();
@@ -48,105 +66,235 @@ public final class SafetyCenterDashboardFragment extends PreferenceFragmentCompa
private static final String ISSUES_GROUP_KEY = "issues_group";
private static final String ENTRIES_GROUP_KEY = "entries_group";
private static final String STATIC_ENTRIES_GROUP_KEY = "static_entries_group";
-
- private SafetyCenterManager mSafetyCenterManager;
+ private static final String SPACER_KEY = "spacer";
private SafetyStatusPreference mSafetyStatusPreference;
+ private final CollapsableGroupCardHelper mCollapsableGroupCardHelper =
+ new CollapsableGroupCardHelper();
private PreferenceGroup mIssuesGroup;
private PreferenceGroup mEntriesGroup;
private PreferenceGroup mStaticEntriesGroup;
+ private boolean mIsQuickSettingsFragment;
- private final OnSafetyCenterDataChangedListener mOnSafetyCenterDataChangedListener =
- new OnSafetyCenterDataChangedListener() {
- @Override
- public void onSafetyCenterDataChanged(@NonNull SafetyCenterData data) {
- Log.i(TAG, String.format("onSafetyCenterDataChanged called with: %s", data));
-
- Context context = getContext();
- if (context == null) {
- return;
- }
+ public SafetyCenterDashboardFragment() {}
- mSafetyStatusPreference.setSafetyStatus(data.getStatus());
+ /**
+ * Create instance of SafetyCenterDashboardFragment with the arguments set
+ *
+ * @param isQuickSettingsFragment Denoting if it is the quick settings fragment
+ * @return SafetyCenterDashboardFragment with the arguments set
+ */
+ public static SafetyCenterDashboardFragment newInstance(
+ long sessionId, boolean isQuickSettingsFragment) {
+ Bundle args = new Bundle();
+ args.putLong(EXTRA_SESSION_ID, sessionId);
+ args.putBoolean(QUICK_SETTINGS_SAFETY_CENTER_FRAGMENT, isQuickSettingsFragment);
- // TODO(b/208212820): Only update entries that have changed since last
- // update, rather than deleting and re-adding all.
-
- updateIssues(context, data.getIssues());
- updateSafetyEntries(context, data.getEntriesOrGroups());
- updateStaticSafetyEntries(context, data.getStaticEntryGroups());
- }
- };
+ SafetyCenterDashboardFragment frag = new SafetyCenterDashboardFragment();
+ frag.setArguments(args);
+ return frag;
+ }
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ super.onCreatePreferences(savedInstanceState, rootKey);
setPreferencesFromResource(R.xml.safety_center_dashboard, rootKey);
- Context context = requireNonNull(getContext());
-
- mSafetyCenterManager = requireNonNull(context.getSystemService(SafetyCenterManager.class));
+ if (getArguments() != null) {
+ mIsQuickSettingsFragment =
+ getArguments().getBoolean(QUICK_SETTINGS_SAFETY_CENTER_FRAGMENT, false);
+ }
+ mCollapsableGroupCardHelper.restoreState(savedInstanceState);
- mSafetyStatusPreference = requireNonNull(
- getPreferenceScreen().findPreference(SAFETY_STATUS_KEY));
- // TODO: Use real strings here, or set more sensible defaults in the layout
- mSafetyStatusPreference.setSafetyStatus(new SafetyCenterStatus.Builder("Looks good", "")
- .setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN)
- .build());
- mSafetyStatusPreference.setRescanButtonOnClickListener(unused ->
- mSafetyCenterManager.refreshSafetySources(
- SafetyCenterManager.REFRESH_REASON_RESCAN_BUTTON_CLICK));
+ mSafetyStatusPreference =
+ requireNonNull(getPreferenceScreen().findPreference(SAFETY_STATUS_KEY));
+ mSafetyStatusPreference.setViewModel(getSafetyCenterViewModel());
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;
+ getPreferenceScreen().removePreference(mStaticEntriesGroup);
+ mStaticEntriesGroup = null;
+ Preference spacerPreference = getPreferenceScreen().findPreference(SPACER_KEY);
+ getPreferenceScreen().removePreference(spacerPreference);
+ }
+ getSafetyCenterViewModel().getStatusUiLiveData().observe(this, this::updateStatus);
+
+ prerenderCurrentSafetyCenterData();
+ }
+
+ // Set the default divider line between preferences to be transparent
+ @Override
+ public void setDivider(Drawable divider) {
+ super.setDivider(new ColorDrawable(Color.TRANSPARENT));
+ }
+
+ @Override
+ public void setDividerHeight(int height) {
+ super.setDividerHeight(0);
}
@Override
public void onResume() {
super.onResume();
- mSafetyCenterManager.addOnSafetyCenterDataChangedListener(
- ContextCompat.getMainExecutor(requireNonNull(getContext())),
- mOnSafetyCenterDataChangedListener);
- mSafetyCenterManager.refreshSafetySources(SafetyCenterManager.REFRESH_REASON_PAGE_OPEN);
+ getSafetyCenterViewModel().pageOpen();
}
@Override
- public void onPause() {
- mSafetyCenterManager.removeOnSafetyCenterDataChangedListener(
- mOnSafetyCenterDataChangedListener);
- super.onPause();
+ public void configureInteractionLogger() {
+ InteractionLogger logger = getSafetyCenterViewModel().getInteractionLogger();
+ logger.setSessionId(getSafetyCenterSessionId());
+ logger.setViewType(mIsQuickSettingsFragment ? ViewType.QUICK_SETTINGS : ViewType.FULL);
+
+ Intent intent = requireActivity().getIntent();
+ logger.setNavigationSource(NavigationSource.fromIntent(intent));
+ logger.setNavigationSensor(Sensor.fromIntent(intent));
}
- private void updateIssues(Context context, List<SafetyCenterIssue> issues) {
- mIssuesGroup.removeAll();
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mCollapsableGroupCardHelper.saveState(outState);
+ }
+
+ private void updateStatus(StatusUiData statusUiData) {
+ if (mIsQuickSettingsFragment) {
+ SafetyCenterResourcesContext safetyCenterResourcesContext =
+ new SafetyCenterResourcesContext(requireContext());
+ boolean hasPendingActions =
+ safetyCenterResourcesContext
+ .getStringByName("overall_severity_level_ok_review_summary")
+ .equals(statusUiData.getOriginalSummary().toString());
- issues.stream()
- .map(issue -> new IssueCardPreference(context, issue))
- .forEachOrdered(mIssuesGroup::addPreference);
+ statusUiData = statusUiData.copyForPendingActions(hasPendingActions);
+ }
+
+ mSafetyStatusPreference.setData(statusUiData);
+ }
+
+ @Override
+ public void renderSafetyCenterData(@Nullable SafetyCenterUiData uiData) {
+ if (uiData == null) return;
+ SafetyCenterData data = uiData.getSafetyCenterData();
+
+ Log.i(TAG, String.format("renderSafetyCenterData called with: %s", data));
+
+ Context context = getContext();
+ if (context == null) {
+ return;
+ }
+
+ // TODO(b/208212820): Only update entries that have changed since last
+ // update, rather than deleting and re-adding all.
+ updateIssues(context, data.getIssues(), uiData.getResolvedIssues());
+
+ if (!mIsQuickSettingsFragment) {
+ updateSafetyEntries(context, data.getEntriesOrGroups());
+ updateStaticSafetyEntries(context, data);
+ }
+ }
+
+ private void updateIssues(
+ Context context, List<SafetyCenterIssue> issues, Map<String, String> resolvedIssues) {
+ mIssuesGroup.removeAll();
+ getCollapsableIssuesCardHelper()
+ .addIssues(
+ context,
+ getSafetyCenterViewModel(),
+ getChildFragmentManager(),
+ mIssuesGroup,
+ issues,
+ emptyList(),
+ resolvedIssues,
+ getActivity().getTaskId());
}
// TODO(b/208212820): Add groups and move to separate controller
- private void updateSafetyEntries(Context context,
- List<SafetyCenterEntryOrGroup> entriesOrGroups) {
+ private void updateSafetyEntries(
+ Context context, List<SafetyCenterEntryOrGroup> entriesOrGroups) {
mEntriesGroup.removeAll();
- entriesOrGroups.stream()
- .flatMap(entryOrGroup ->
- entryOrGroup.getEntry() != null
- ? Stream.of(entryOrGroup.getEntry())
- : entryOrGroup.getEntryGroup().getEntries().stream())
- .map(entry -> new SafetyEntryPreference(context, entry))
- .forEachOrdered(mEntriesGroup::addPreference);
+ for (int i = 0, size = entriesOrGroups.size(); i < size; i++) {
+ SafetyCenterEntryOrGroup entryOrGroup = entriesOrGroups.get(i);
+ SafetyCenterEntry entry = entryOrGroup.getEntry();
+ SafetyCenterEntryGroup group = entryOrGroup.getEntryGroup();
+
+ boolean isFirstElement = i == 0;
+ boolean isLastElement = i == size - 1;
+
+ if (SafetyCenterUiFlags.getShowSubpages() && group != null) {
+ mEntriesGroup.addPreference(
+ new SafetyHomepageEntryPreference(
+ context, group, getSafetyCenterSessionId()));
+ } else if (entry != null) {
+ addTopLevelEntry(context, entry, isFirstElement, isLastElement);
+ } else if (group != null) {
+ addGroupEntries(context, group, isFirstElement, isLastElement);
+ }
+ }
}
- private void updateStaticSafetyEntries(Context context,
- List<SafetyCenterStaticEntryGroup> staticEntryGroups) {
- mStaticEntriesGroup.removeAll();
+ private void addTopLevelEntry(
+ Context context,
+ SafetyCenterEntry entry,
+ boolean isFirstElement,
+ boolean isLastElement) {
+ mEntriesGroup.addPreference(
+ new SafetyEntryPreference(
+ context,
+ PendingIntentSender.getTaskIdForEntry(
+ entry.getId(), getSameTaskSourceIds(), requireActivity()),
+ entry,
+ PositionInCardList.calculate(isFirstElement, isLastElement),
+ getSafetyCenterViewModel()));
+ }
- staticEntryGroups.stream()
- .flatMap(group -> group.getStaticEntries().stream())
- .map(entry -> new StaticSafetyEntryPreference(context, entry))
- .forEachOrdered(mStaticEntriesGroup::addPreference);
+ private void addGroupEntries(
+ Context context,
+ SafetyCenterEntryGroup group,
+ boolean isFirstCard,
+ boolean isLastCard) {
+ mEntriesGroup.addPreference(
+ new SafetyGroupPreference(
+ context,
+ group,
+ mCollapsableGroupCardHelper::isGroupExpanded,
+ isFirstCard,
+ isLastCard,
+ (entryId) ->
+ PendingIntentSender.getTaskIdForEntry(
+ entryId, getSameTaskSourceIds(), requireActivity()),
+ getSafetyCenterViewModel(),
+ (groupId) -> {
+ mCollapsableGroupCardHelper.onGroupExpanded(groupId);
+ return Unit.INSTANCE;
+ },
+ (groupId) -> {
+ mCollapsableGroupCardHelper.onGroupCollapsed(groupId);
+ return Unit.INSTANCE;
+ }));
}
+ private void updateStaticSafetyEntries(Context context, SafetyCenterData data) {
+ mStaticEntriesGroup.removeAll();
+
+ for (SafetyCenterStaticEntryGroup group : data.getStaticEntryGroups()) {
+ PreferenceCategory category = new ComparablePreferenceCategory(context);
+ category.setTitle(group.getTitle());
+ mStaticEntriesGroup.addPreference(category);
+
+ for (SafetyCenterStaticEntry entry : group.getStaticEntries()) {
+ category.addPreference(
+ new StaticSafetyEntryPreference(
+ context,
+ requireActivity().getTaskId(),
+ entry,
+ SafetyCenterBundles.getStaticEntryId(data, entry),
+ getSafetyCenterViewModel()));
+ }
+ }
+ }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterFragment.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterFragment.kt
new file mode 100644
index 000000000..7d5dbb3cb
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterFragment.kt
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.permissioncontroller.safetycenter.ui
+
+import android.os.Build.VERSION_CODES.TIRAMISU
+import android.os.Bundle
+import android.safetycenter.SafetyCenterErrorDetails
+import android.widget.Toast
+import androidx.annotation.RequiresApi
+import androidx.lifecycle.ViewModelProvider
+import androidx.preference.PreferenceFragmentCompat
+import androidx.preference.PreferenceScreen
+import androidx.recyclerview.widget.RecyclerView
+import com.android.permissioncontroller.Constants.EXTRA_SESSION_ID
+import com.android.permissioncontroller.Constants.INVALID_SESSION_ID
+import com.android.permissioncontroller.safetycenter.SafetyCenterConstants.QUICK_SETTINGS_SAFETY_CENTER_FRAGMENT
+import com.android.permissioncontroller.safetycenter.ui.ParsedSafetyCenterIntent.Companion.toSafetyCenterIntent
+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
+
+/** A base fragment that represents a page in Safety Center. */
+@RequiresApi(TIRAMISU)
+abstract class SafetyCenterFragment : PreferenceFragmentCompat() {
+
+ lateinit var safetyCenterViewModel: SafetyCenterViewModel
+ lateinit var sameTaskSourceIds: List<String>
+ lateinit var collapsableIssuesCardHelper: CollapsableIssuesCardHelper
+ var safetyCenterSessionId = INVALID_SESSION_ID
+ private val highlightManager = PreferenceHighlightManager(this)
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ highlightManager.restoreState(savedInstanceState)
+ }
+
+ override fun onCreateAdapter(
+ preferenceScreen: PreferenceScreen?
+ ): RecyclerView.Adapter<RecyclerView.ViewHolder> {
+ /* The scroll-to-result functionality for settings search is currently implemented only for
+ * subpages i.e. non expand-and-collapse type entries. Hence, we check that the flag is
+ * enabled before using an adapter that does the highlighting and scrolling. */
+ val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
+ if (SafetyCenterUiFlags.getShowSubpages()) {
+ highlightManager.createAdapter(preferenceScreen)
+ } else {
+ super.onCreateAdapter(preferenceScreen)
+ }
+
+ /* By default, the PreferenceGroupAdapter does setHasStableIds(true). Since each Preference
+ * is internally allocated with an auto-incremented ID, it does not allow us to gracefully
+ * update only changed preferences based on SafetyPreferenceComparisonCallback. In order to
+ * allow the list to track the changes, we need to ignore the Preference IDs. */
+ adapter.setHasStableIds(false)
+ return adapter
+ }
+
+ override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
+ sameTaskSourceIds =
+ SafetyCenterResourcesContext(requireContext())
+ .getStringByName("config_same_task_safety_source_ids")
+ .split(",")
+ safetyCenterSessionId = requireArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID)
+
+ safetyCenterViewModel =
+ ViewModelProvider(
+ requireActivity(),
+ LiveSafetyCenterViewModelFactory(requireActivity().getApplication())
+ )
+ .get(SafetyCenterViewModel::class.java)
+ safetyCenterViewModel.safetyCenterUiLiveData.observe(this) { uiData: SafetyCenterUiData? ->
+ renderSafetyCenterData(uiData)
+ }
+ safetyCenterViewModel.errorLiveData.observe(this) { errorDetails: SafetyCenterErrorDetails?
+ ->
+ displayErrorDetails(errorDetails)
+ }
+
+ val safetyCenterIntent: ParsedSafetyCenterIntent =
+ requireActivity().getIntent().toSafetyCenterIntent()
+ val isQsFragment =
+ getArguments()?.getBoolean(QUICK_SETTINGS_SAFETY_CENTER_FRAGMENT, false) ?: false
+ collapsableIssuesCardHelper =
+ CollapsableIssuesCardHelper(safetyCenterViewModel, sameTaskSourceIds)
+ collapsableIssuesCardHelper.apply {
+ setFocusedIssueKey(safetyCenterIntent.safetyCenterIssueKey)
+ // Set quick settings state first and allow restored state to override if necessary
+ setQuickSettingsState(isQsFragment, safetyCenterIntent.shouldExpandIssuesGroup)
+ restoreState(savedInstanceState)
+ }
+
+ getPreferenceManager().setPreferenceComparisonCallback(SafetyPreferenceComparisonCallback())
+ }
+
+ override fun onBindPreferences() {
+ super.onBindPreferences()
+ highlightManager.registerObserverIfNeeded()
+ }
+
+ override fun onUnbindPreferences() {
+ super.onUnbindPreferences()
+ highlightManager.unregisterObserverIfNeeded()
+ }
+
+ override fun onStart() {
+ super.onStart()
+ configureInteractionLogger()
+ safetyCenterViewModel.interactionLogger.record(Action.SAFETY_CENTER_VIEWED)
+ }
+
+ override fun onResume() {
+ super.onResume()
+ highlightManager.highlightPreferenceIfNeeded()
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ collapsableIssuesCardHelper.saveState(outState)
+ highlightManager.saveState(outState)
+ }
+
+ override fun onStop() {
+ super.onStop()
+ safetyCenterViewModel.interactionLogger.clearViewedIssues()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ if (activity?.isChangingConfigurations == true) {
+ safetyCenterViewModel.changingConfigurations()
+ }
+ }
+
+ /**
+ * Insert preferences for whatever Safety Center data we currently have available.
+ *
+ * This should contain the groups and entries to render the basic page structure, even if no
+ * source has responded with data at this point.
+ *
+ * This should be called by subclasses in [onCreatePreferences] after they've pulled out the
+ * preferences they will modify in [renderSafetyCenterData].
+ */
+ protected fun prerenderCurrentSafetyCenterData() =
+ renderSafetyCenterData(safetyCenterViewModel.getCurrentSafetyCenterDataAsUiData())
+
+ abstract fun renderSafetyCenterData(uiData: SafetyCenterUiData?)
+
+ abstract fun configureInteractionLogger()
+
+ private fun displayErrorDetails(errorDetails: SafetyCenterErrorDetails?) {
+ if (errorDetails == null) return
+ Toast.makeText(requireContext(), errorDetails.errorMessage, Toast.LENGTH_LONG).show()
+ safetyCenterViewModel.clearError()
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/SafetyCenterQsActivity.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterQsActivity.java
index 5bdfbb453..2ad282449 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/SafetyCenterQsActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterQsActivity.java
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.ui;
-
-import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
+package com.android.permissioncontroller.safetycenter.ui;
+import android.content.Intent;
import android.os.Bundle;
import android.permission.PermissionGroupUsage;
import android.permission.PermissionManager;
@@ -25,15 +24,9 @@ import android.permission.PermissionManager;
import androidx.fragment.app.FragmentActivity;
import com.android.modules.utils.build.SdkLevel;
-import com.android.permissioncontroller.Constants;
-import com.android.permissioncontroller.permission.ui.handheld.v33.SafetyCenterQsFragment;
-
-import java.util.ArrayList;
-import java.util.Random;
+import com.android.permissioncontroller.permission.utils.Utils;
-/**
- * Activity for the Safety Center Quick Settings Activity
- */
+/** Activity for the Safety Center Quick Settings Activity */
public class SafetyCenterQsActivity extends FragmentActivity {
@Override
@@ -46,13 +39,28 @@ public class SafetyCenterQsActivity extends FragmentActivity {
return;
}
- long sessionId = getIntent().getLongExtra(Constants.EXTRA_SESSION_ID, INVALID_SESSION_ID);
- while (sessionId == INVALID_SESSION_ID) {
- sessionId = new Random().nextLong();
- }
- ArrayList<PermissionGroupUsage> permissionUsages = getIntent().getParcelableArrayListExtra(
- PermissionManager.EXTRA_PERMISSION_USAGES);
- getSupportFragmentManager().beginTransaction().replace(android.R.id.content,
- SafetyCenterQsFragment.newInstance(sessionId, permissionUsages)).commit();
+ configureFragment();
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ setIntent(intent);
+ configureFragment();
+ }
+
+ @SuppressWarnings("NewApi") // Before T, activity finishes before this is called
+ private void configureFragment() {
+ getSupportFragmentManager()
+ .beginTransaction()
+ .replace(
+ android.R.id.content,
+ SafetyCenterQsFragment.newInstance(
+ Utils.getOrGenerateSessionId(getIntent()),
+ getIntent()
+ .getParcelableArrayListExtra(
+ PermissionManager.EXTRA_PERMISSION_USAGES,
+ PermissionGroupUsage.class)))
+ .commit();
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterQsFragment.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterQsFragment.java
new file mode 100644
index 000000000..f69746e39
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterQsFragment.java
@@ -0,0 +1,785 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui;
+
+import static android.Manifest.permission_group.CAMERA;
+import static android.Manifest.permission_group.LOCATION;
+import static android.Manifest.permission_group.MICROPHONE;
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
+import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.permission.PermissionGroupUsage;
+import android.permission.PermissionManager;
+import android.transition.AutoTransition;
+import android.transition.TransitionManager;
+import android.util.ArrayMap;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+import androidx.fragment.app.Fragment;
+import androidx.lifecycle.ViewModelProvider;
+
+import com.android.permissioncontroller.R;
+import com.android.permissioncontroller.permission.utils.KotlinUtils;
+import com.android.permissioncontroller.permission.utils.Utils;
+import com.android.permissioncontroller.safetycenter.ui.model.LiveSafetyCenterViewModelFactory;
+import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterQsViewModel;
+import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterQsViewModel.SensorState;
+import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterQsViewModelFactory;
+import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterViewModel;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
+import com.google.android.material.button.MaterialButton;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The Quick Settings fragment for the safety center. Displays information to the user about the
+ * current safety and privacy status of their device, including showing mic/camera usage, and having
+ * mic/camera/location toggles.
+ */
+@RequiresApi(TIRAMISU)
+public class SafetyCenterQsFragment extends Fragment {
+ private static final List<String> TOGGLE_BUTTONS = List.of(CAMERA, MICROPHONE, LOCATION);
+ private static final String SETTINGS_TOGGLE_TAG = "settings_toggle";
+ private static final int MAX_TOGGLES_PER_ROW = 2;
+
+ private Context mContext;
+ private long mSessionId;
+ private List<PermissionGroupUsage> mPermGroupUsages;
+ private SafetyCenterQsViewModel mViewModel;
+ private boolean mIsPermissionUsageReady;
+ private boolean mAreSensorTogglesReady;
+
+ private SafetyCenterViewModel mSafetyCenterViewModel;
+
+ /**
+ * Create instance of SafetyCenterDashboardFragment with the arguments set
+ *
+ * @param sessionId The current session Id
+ * @param usages ArrayList of PermissionGroupUsage
+ * @return SafetyCenterQsFragment with the arguments set
+ */
+ public static SafetyCenterQsFragment newInstance(
+ long sessionId, ArrayList<PermissionGroupUsage> usages) {
+ Bundle args = new Bundle();
+ args.putLong(EXTRA_SESSION_ID, sessionId);
+ args.putParcelableArrayList(PermissionManager.EXTRA_PERMISSION_USAGES, usages);
+ SafetyCenterQsFragment frag = new SafetyCenterQsFragment();
+ frag.setArguments(args);
+ return frag;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mSessionId = INVALID_SESSION_ID;
+ if (getArguments() != null) {
+ mSessionId = getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID);
+ }
+ mContext = getContext();
+
+ mPermGroupUsages =
+ getArguments().getParcelableArrayList(PermissionManager.EXTRA_PERMISSION_USAGES);
+ if (mPermGroupUsages == null) {
+ mPermGroupUsages = new ArrayList<>();
+ }
+
+ getActivity().setTheme(R.style.Theme_SafetyCenterQs);
+
+ SafetyCenterQsViewModelFactory factory =
+ new SafetyCenterQsViewModelFactory(
+ getActivity().getApplication(), mSessionId, mPermGroupUsages);
+ mViewModel =
+ new ViewModelProvider(requireActivity(), factory)
+ .get(SafetyCenterQsViewModel.class);
+ mViewModel.getSensorPrivacyLiveData().observe(this, this::setSensorToggleState);
+ // LightAppPermGroupLiveDatas are kept track of in the view model,
+ // we need to start observing them here
+ if (!mPermGroupUsages.isEmpty()) {
+ mViewModel.getPermDataLoadedLiveData().observe(this, this::onPermissionGroupsLoaded);
+ } else {
+ mIsPermissionUsageReady = true;
+ }
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ ViewGroup root = (ViewGroup) inflater.inflate(R.layout.safety_center_qs, container, false);
+ root.setVisibility(View.GONE);
+
+ View closeButton = root.findViewById(R.id.close_button);
+ closeButton.setOnClickListener((v) -> requireActivity().finish());
+ SafetyCenterTouchTarget.configureSize(
+ closeButton, R.dimen.sc_icon_button_touch_target_size);
+
+ mSafetyCenterViewModel =
+ new ViewModelProvider(
+ requireActivity(),
+ new LiveSafetyCenterViewModelFactory(
+ requireActivity().getApplication()))
+ .get(SafetyCenterViewModel.class);
+
+ getChildFragmentManager()
+ .beginTransaction()
+ .add(
+ R.id.safety_center_prefs,
+ SafetyCenterDashboardFragment.newInstance(
+ mSessionId, /* isQuickSettingsFragment= */ true))
+ .commitNow();
+ return root;
+ }
+
+ private void maybeEnableView(@Nullable View rootView) {
+ if (rootView == null) {
+ return;
+ }
+ if (mIsPermissionUsageReady && mAreSensorTogglesReady) {
+ rootView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private void onPermissionGroupsLoaded(boolean initialized) {
+ if (initialized) {
+ if (!mIsPermissionUsageReady) {
+ mIsPermissionUsageReady = true;
+ maybeEnableView(getView());
+ }
+ addPermissionUsageInformation(getView());
+ }
+ }
+
+ private void addPermissionUsageInformation(@Nullable View rootView) {
+ if (rootView == null) {
+ return;
+ }
+ View permissionSectionTitleView = rootView.findViewById(R.id.permission_section_title);
+ View statusSectionTitleView = rootView.findViewById(R.id.status_section_title);
+ if (mPermGroupUsages == null || mPermGroupUsages.isEmpty()) {
+ permissionSectionTitleView.setVisibility(View.GONE);
+ statusSectionTitleView.setVisibility(View.GONE);
+ return;
+ }
+ permissionSectionTitleView.setVisibility(View.VISIBLE);
+ statusSectionTitleView.setVisibility(View.VISIBLE);
+ LinearLayout usageLayout = rootView.findViewById(R.id.permission_usage);
+ Collections.sort(
+ mPermGroupUsages,
+ (pguA, pguB) ->
+ getAppLabel(pguA).toString().compareTo(getAppLabel(pguB).toString()));
+
+ for (PermissionGroupUsage usage : mPermGroupUsages) {
+ View cardView = View.inflate(mContext, R.layout.indicator_card, usageLayout);
+ cardView.setId(View.generateViewId());
+ ConstraintLayout parentIndicatorLayout = cardView.findViewById(R.id.indicator_layout);
+ parentIndicatorLayout.setId(View.generateViewId());
+ ImageView expandView = parentIndicatorLayout.findViewById(R.id.expand_view);
+
+ // Update UI for the parent indicator card
+ updateIndicatorParentUi(
+ parentIndicatorLayout,
+ usage.getPermissionGroupName(),
+ generateUsageLabel(usage),
+ usage.isActive());
+
+ // If sensor usage is due to an active phone call, don't allow any actions
+ if (usage.isPhoneCall()) {
+ expandView.setVisibility(View.GONE);
+ continue;
+ }
+
+ ConstraintLayout expandedLayout = cardView.findViewById(R.id.expanded_layout);
+ expandedLayout.setId(View.generateViewId());
+
+ // Handle redraw on orientation changes if permission has been revoked
+ if (mViewModel.getRevokedUsages().contains(usage)) {
+ disableIndicatorCardUi(parentIndicatorLayout, expandView);
+ continue;
+ }
+
+ setIndicatorExpansionBehavior(parentIndicatorLayout, expandedLayout, expandView);
+ ViewCompat.replaceAccessibilityAction(
+ parentIndicatorLayout,
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
+ mContext.getString(R.string.safety_center_qs_expand_action),
+ null);
+
+ // Configure the indicator action buttons
+ configureIndicatorActionButtons(
+ usage, parentIndicatorLayout, expandedLayout, expandView);
+ }
+ }
+
+ private void configureIndicatorActionButtons(
+ PermissionGroupUsage usage,
+ ConstraintLayout parentIndicatorLayout,
+ ConstraintLayout expandedLayout,
+ ImageView expandView) {
+ configurePrimaryActionButton(usage, parentIndicatorLayout, expandedLayout, expandView);
+ configureSeeUsageButton(usage, expandedLayout);
+ }
+
+ private void configurePrimaryActionButton(
+ PermissionGroupUsage usage,
+ ConstraintLayout parentIndicatorLayout,
+ ConstraintLayout expandedLayout,
+ ImageView expandView) {
+ boolean shouldAllowRevoke = mViewModel.shouldAllowRevoke(usage);
+ Intent manageServiceIntent = null;
+
+ if (isSubAttributionUsage(usage.getAttributionLabel())) {
+ manageServiceIntent = mViewModel.getStartViewPermissionUsageIntent(mContext, usage);
+ }
+
+ int primaryActionButtonLabel =
+ getPrimaryActionButtonLabel(
+ manageServiceIntent != null,
+ shouldAllowRevoke,
+ usage.getPermissionGroupName());
+ MaterialButton primaryActionButton = expandedLayout.findViewById(R.id.primary_button);
+ primaryActionButton.setText(primaryActionButtonLabel);
+ primaryActionButton.setStrokeColorResource(
+ Utils.getColorResId(mContext, android.R.attr.colorAccent));
+
+ if (shouldAllowRevoke && manageServiceIntent == null) {
+ primaryActionButton.setOnClickListener(
+ l -> {
+ parentIndicatorLayout.callOnClick();
+ disableIndicatorCardUi(parentIndicatorLayout, expandView);
+ revokePermission(usage);
+ mSafetyCenterViewModel
+ .getInteractionLogger()
+ .recordForSensor(
+ Action.SENSOR_PERMISSION_REVOKE_CLICKED,
+ Sensor.fromPermissionGroupUsage(usage));
+ });
+ } else {
+ setPrimaryActionClickListener(primaryActionButton, usage, manageServiceIntent);
+ }
+ }
+
+ private void configureSeeUsageButton(
+ PermissionGroupUsage usage, ConstraintLayout expandedLayout) {
+ MaterialButton seeUsageButton = expandedLayout.findViewById(R.id.secondary_button);
+ seeUsageButton.setText(getSeeUsageText(usage.getPermissionGroupName()));
+
+ seeUsageButton.setStrokeColorResource(
+ Utils.getColorResId(mContext, android.R.attr.colorAccent));
+ seeUsageButton.setOnClickListener(
+ l -> {
+ mViewModel.navigateToSeeUsage(this, usage.getPermissionGroupName());
+ mSafetyCenterViewModel
+ .getInteractionLogger()
+ .recordForSensor(
+ Action.SENSOR_PERMISSION_SEE_USAGES_CLICKED,
+ Sensor.fromPermissionGroupUsage(usage));
+ });
+ }
+
+ private void setPrimaryActionClickListener(
+ Button primaryActionButton, PermissionGroupUsage usage, Intent manageServiceIntent) {
+ if (manageServiceIntent != null) {
+ primaryActionButton.setOnClickListener(
+ l -> {
+ mViewModel.navigateToManageService(this, manageServiceIntent);
+ mSafetyCenterViewModel
+ .getInteractionLogger()
+ .recordForSensor(
+ // Unfortunate name, but this is used for all primary
+ // CTAs on the permission usage cards.
+ Action.SENSOR_PERMISSION_REVOKE_CLICKED,
+ Sensor.fromPermissionGroupUsage(usage));
+ });
+ } else {
+ primaryActionButton.setOnClickListener(
+ l -> {
+ mViewModel.navigateToManageAppPermissions(this, usage);
+ mSafetyCenterViewModel
+ .getInteractionLogger()
+ .recordForSensor(
+ Action.SENSOR_PERMISSION_REVOKE_CLICKED,
+ Sensor.fromPermissionGroupUsage(usage));
+ });
+ }
+ }
+
+ private int getPrimaryActionButtonLabel(
+ boolean canHandleIntent, boolean shouldAllowRevoke, String permissionGroupName) {
+ if (canHandleIntent) {
+ return R.string.manage_service_qs;
+ }
+ if (!shouldAllowRevoke) {
+ return R.string.manage_permissions_qs;
+ }
+ return getRemovePermissionText(permissionGroupName);
+ }
+
+ private boolean isSubAttributionUsage(@Nullable CharSequence attributionLabel) {
+ if (attributionLabel == null || attributionLabel.length() == 0) {
+ return false;
+ }
+ return true;
+ }
+
+ private void revokePermission(PermissionGroupUsage usage) {
+ mViewModel.revokePermission(usage);
+ }
+
+ private void disableIndicatorCardUi(
+ ConstraintLayout parentIndicatorLayout, ImageView expandView) {
+ // Disable the parent indicator and the expand view
+ parentIndicatorLayout.setEnabled(false);
+ expandView.setEnabled(false);
+ expandView.setVisibility(View.GONE);
+
+ // Construct new icon for revoked permission
+ ImageView iconView = parentIndicatorLayout.findViewById(R.id.indicator_icon);
+ Drawable background = mContext.getDrawable(R.drawable.indicator_background_circle).mutate();
+ background.setTint(mContext.getColor(R.color.sc_surface_variant_dark));
+ Drawable icon = mContext.getDrawable(R.drawable.ic_check);
+ Utils.applyTint(mContext, icon, android.R.attr.textColorPrimary);
+ int bgSize = (int) getResources().getDimension(R.dimen.ongoing_appops_dialog_circle_size);
+ int iconSize = (int) getResources().getDimension(R.dimen.ongoing_appops_dialog_icon_size);
+ iconView.setImageDrawable(constructIcon(icon, background, bgSize, iconSize));
+
+ // Set label to show on permission revoke
+ TextView labelView = parentIndicatorLayout.findViewById(R.id.indicator_label);
+ labelView.setText(R.string.permissions_removed_qs);
+ labelView.setContentDescription(mContext.getString(R.string.permissions_removed_qs));
+ }
+
+ private void setIndicatorExpansionBehavior(
+ ConstraintLayout parentIndicatorLayout,
+ ConstraintLayout expandedLayout,
+ ImageView expandView) {
+ View rootView = getView();
+ if (rootView == null) {
+ return;
+ }
+ parentIndicatorLayout.setOnClickListener(
+ createExpansionListener(expandedLayout, expandView, rootView));
+ }
+
+ private View.OnClickListener createExpansionListener(
+ ConstraintLayout expandedLayout, ImageView expandView, View rootView) {
+ AutoTransition transition = new AutoTransition();
+ // Get the entire fragment as a viewgroup in order to animate it nicely in case of
+ // expand/collapse
+ ViewGroup indicatorCardViewGroup = (ViewGroup) rootView;
+ return v -> {
+ if (expandedLayout.getVisibility() == View.VISIBLE) {
+ // Enable -> Press -> Hide the expanded card for a continuous ripple effect
+ expandedLayout.setEnabled(true);
+ pressButton(expandedLayout);
+ expandedLayout.setVisibility(View.GONE);
+ TransitionManager.beginDelayedTransition(indicatorCardViewGroup, transition);
+ expandView.setImageDrawable(
+ mContext.getDrawable(R.drawable.ic_safety_group_expand));
+ ViewCompat.replaceAccessibilityAction(
+ v,
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
+ mContext.getString(R.string.safety_center_qs_expand_action),
+ null);
+ } else {
+ // Show -> Press -> Disable the expanded card for a continuous ripple effect
+ expandedLayout.setVisibility(View.VISIBLE);
+ pressButton(expandedLayout);
+ expandedLayout.setEnabled(false);
+ TransitionManager.beginDelayedTransition(indicatorCardViewGroup, transition);
+ expandView.setImageDrawable(
+ mContext.getDrawable(R.drawable.ic_safety_group_collapse));
+ ViewCompat.replaceAccessibilityAction(
+ v,
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
+ mContext.getString(R.string.safety_center_qs_collapse_action),
+ null);
+ }
+ };
+ }
+
+ /**
+ * To get the expanded card to ripple at the same time as the parent card we must simulate a
+ * user press on the expanded card
+ */
+ private void pressButton(View buttonToBePressed) {
+ buttonToBePressed.setPressed(true);
+ buttonToBePressed.setPressed(false);
+ buttonToBePressed.performClick();
+ }
+
+ private String generateUsageLabel(PermissionGroupUsage usage) {
+ if (usage.isPhoneCall() && usage.isActive()) {
+ return mContext.getString(R.string.active_call_usage_qs);
+ } else if (usage.isPhoneCall()) {
+ return mContext.getString(R.string.recent_call_usage_qs);
+ }
+ return generateAttributionUsageLabel(usage);
+ }
+
+ private String generateAttributionUsageLabel(PermissionGroupUsage usage) {
+ CharSequence appLabel = getAppLabel(usage);
+
+ final int usageResId =
+ usage.isActive() ? R.string.active_app_usage_qs : R.string.recent_app_usage_qs;
+ final int singleUsageResId =
+ usage.isActive() ? R.string.active_app_usage_1_qs : R.string.recent_app_usage_1_qs;
+ final int doubleUsageResId =
+ usage.isActive() ? R.string.active_app_usage_2_qs : R.string.recent_app_usage_2_qs;
+
+ CharSequence attributionLabel = usage.getAttributionLabel();
+ CharSequence proxyLabel = usage.getProxyLabel();
+
+ if (attributionLabel == null && proxyLabel == null) {
+ return mContext.getString(usageResId, appLabel);
+ } else if (attributionLabel != null && proxyLabel != null) {
+ return mContext.getString(doubleUsageResId, appLabel, attributionLabel, proxyLabel);
+ } else {
+ return mContext.getString(
+ singleUsageResId,
+ appLabel,
+ attributionLabel == null ? proxyLabel : attributionLabel);
+ }
+ }
+
+ private CharSequence getAppLabel(PermissionGroupUsage usage) {
+ return KotlinUtils.INSTANCE.getPackageLabel(
+ getActivity().getApplication(),
+ usage.getPackageName(),
+ UserHandle.getUserHandleForUid(usage.getUid()));
+ }
+
+ private void updateIndicatorParentUi(
+ ConstraintLayout indicatorParentLayout,
+ String permGroupName,
+ String usageText,
+ boolean isActiveUsage) {
+ CharSequence permGroupLabel = getPermGroupLabel(permGroupName);
+ ImageView iconView = indicatorParentLayout.findViewById(R.id.indicator_icon);
+
+ Drawable background = mContext.getDrawable(R.drawable.indicator_background_circle);
+ int indicatorColor =
+ Utils.getColorResId(
+ mContext,
+ isActiveUsage
+ ? android.R.attr.textColorPrimaryInverse
+ : android.R.attr.textColorPrimary);
+ Drawable indicatorIcon =
+ KotlinUtils.INSTANCE.getPermGroupIcon(
+ mContext, permGroupName, mContext.getColor(indicatorColor));
+ if (isActiveUsage) {
+ Utils.applyTint(mContext, background, android.R.attr.colorAccent);
+ } else {
+ background.setTint(mContext.getColor(R.color.sc_surface_variant_dark));
+ }
+ int bgSize = (int) getResources().getDimension(R.dimen.ongoing_appops_dialog_circle_size);
+ int iconSize = (int) getResources().getDimension(R.dimen.ongoing_appops_dialog_icon_size);
+ iconView.setImageDrawable(constructIcon(indicatorIcon, background, bgSize, iconSize));
+ iconView.setContentDescription(permGroupLabel);
+
+ TextView titleText = indicatorParentLayout.findViewById(R.id.indicator_title);
+ titleText.setText(permGroupLabel);
+ titleText.setTextColor(
+ mContext.getColor(Utils.getColorResId(mContext, android.R.attr.textColorPrimary)));
+ titleText.setContentDescription(permGroupLabel);
+
+ TextView labelText = indicatorParentLayout.findViewById(R.id.indicator_label);
+ labelText.setText(usageText);
+ labelText.setContentDescription(usageText);
+
+ ImageView expandView = indicatorParentLayout.findViewById(R.id.expand_view);
+ expandView.setImageDrawable(mContext.getDrawable(R.drawable.ic_safety_group_expand));
+ }
+
+ private Drawable constructIcon(Drawable icon, Drawable background, int bgSize, int iconSize) {
+ LayerDrawable layered = new LayerDrawable(new Drawable[] {background, icon});
+ final int bgLayerIndex = 0;
+ final int iconLayerIndex = 1;
+ layered.setLayerSize(bgLayerIndex, bgSize, bgSize);
+ layered.setLayerSize(iconLayerIndex, iconSize, iconSize);
+ layered.setLayerGravity(iconLayerIndex, Gravity.CENTER);
+ return layered;
+ }
+
+ private void setSensorToggleState(@Nullable Map<String, SensorState> sensorStates) {
+ if (!mAreSensorTogglesReady) {
+ mAreSensorTogglesReady = true;
+ maybeEnableView(getView());
+ setupSensorToggles(sensorStates, getView());
+ }
+ updateSensorToggleState(sensorStates, getView());
+ }
+
+ private void setupSensorToggles(
+ @Nullable Map<String, SensorState> sensorStates, @Nullable View rootView) {
+ if (rootView == null) {
+ return;
+ }
+
+ if (sensorStates == null) {
+ sensorStates = new ArrayMap<>();
+ }
+
+ LinearLayout toggleContainer = rootView.findViewById(R.id.toggle_container);
+
+ LinearLayout row = addRow(toggleContainer);
+
+ for (String groupName : TOGGLE_BUTTONS) {
+ boolean sensorVisible =
+ !sensorStates.containsKey(groupName)
+ || sensorStates.get(groupName).getVisible();
+ if (!sensorVisible) {
+ continue;
+ }
+
+ addToggle(groupName, row);
+
+ if (row.getChildCount() >= MAX_TOGGLES_PER_ROW) {
+ row = addRow(toggleContainer);
+ }
+ }
+ addSettingsToggle(row);
+ }
+
+ private LinearLayout addRow(ViewGroup parent) {
+ LinearLayout row =
+ new LinearLayout(parent.getContext(), null, 0, R.style.SafetyCenterQsToggleRow);
+ parent.addView(row);
+ return row;
+ }
+
+ private View addToggle(String tag, ViewGroup parent) {
+ View toggle =
+ getLayoutInflater().inflate(R.layout.safety_center_toggle_button, parent, false);
+ toggle.setTag(tag);
+ parent.addView(toggle);
+ return toggle;
+ }
+
+ private View addSettingsToggle(ViewGroup parent) {
+ View securitySettings = addToggle(SETTINGS_TOGGLE_TAG, parent);
+ securitySettings.setOnClickListener(
+ (v) ->
+ mSafetyCenterViewModel.navigateToSafetyCenter(
+ mContext, NavigationSource.QUICK_SETTINGS_TILE));
+ TextView securitySettingsText = securitySettings.findViewById(R.id.toggle_sensor_name);
+ securitySettingsText.setText(R.string.settings);
+ securitySettingsText.setSelected(true);
+ securitySettings.findViewById(R.id.toggle_sensor_status).setVisibility(View.GONE);
+ ImageView securitySettingsIcon = securitySettings.findViewById(R.id.toggle_sensor_icon);
+ securitySettingsIcon.setImageDrawable(
+ Utils.applyTint(
+ mContext,
+ mContext.getDrawable(R.drawable.ic_safety_center_shield),
+ android.R.attr.textColorPrimaryInverse));
+ securitySettings.findViewById(R.id.arrow_icon).setVisibility(View.VISIBLE);
+ ((ImageView) securitySettings.findViewById(R.id.arrow_icon))
+ .setImageDrawable(
+ Utils.applyTint(
+ mContext,
+ mContext.getDrawable(R.drawable.ic_chevron_right),
+ android.R.attr.textColorSecondaryInverse));
+ ViewCompat.replaceAccessibilityAction(
+ securitySettings,
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
+ mContext.getString(R.string.safety_center_qs_open_action),
+ null);
+ return securitySettings;
+ }
+
+ private void updateSensorToggleState(
+ @Nullable Map<String, SensorState> sensorStates, @Nullable View rootView) {
+ if (rootView == null) {
+ return;
+ }
+
+ if (sensorStates == null) {
+ sensorStates = new ArrayMap<>();
+ }
+
+ for (String groupName : TOGGLE_BUTTONS) {
+ View toggle = rootView.findViewWithTag(groupName);
+ if (toggle == null) {
+ continue;
+ }
+ EnforcedAdmin admin =
+ sensorStates.containsKey(groupName)
+ ? sensorStates.get(groupName).getAdmin()
+ : null;
+ boolean sensorBlockedByAdmin = admin != null;
+
+ if (sensorBlockedByAdmin) {
+ toggle.setOnClickListener(
+ (v) ->
+ startActivity(
+ RestrictedLockUtils.getShowAdminSupportDetailsIntent(
+ mContext, admin)));
+ } else {
+ toggle.setOnClickListener(
+ (v) -> {
+ mViewModel.toggleSensor(groupName);
+ mSafetyCenterViewModel
+ .getInteractionLogger()
+ .recordForSensor(
+ Action.PRIVACY_CONTROL_TOGGLE_CLICKED,
+ Sensor.fromPermissionGroupName(groupName));
+ });
+ }
+
+ TextView groupLabel = toggle.findViewById(R.id.toggle_sensor_name);
+ groupLabel.setText(getPermGroupLabel(groupName));
+ // Set the text as selected to get marquee to work
+ groupLabel.setSelected(true);
+ TextView blockedStatus = toggle.findViewById(R.id.toggle_sensor_status);
+ // Set the text as selected to get marquee to work
+ blockedStatus.setSelected(true);
+ ImageView iconView = toggle.findViewById(R.id.toggle_sensor_icon);
+ boolean sensorEnabled =
+ !sensorStates.containsKey(groupName)
+ || sensorStates.get(groupName).getEnabled();
+
+ Drawable icon;
+ boolean useEnabledBackground = sensorEnabled && !sensorBlockedByAdmin;
+ int colorPrimary = getTextColor(true, useEnabledBackground, sensorBlockedByAdmin);
+ int colorSecondary = getTextColor(false, useEnabledBackground, sensorBlockedByAdmin);
+ if (useEnabledBackground) {
+ toggle.setBackgroundResource(R.drawable.safety_center_sensor_toggle_enabled);
+ } else {
+ toggle.setBackgroundResource(R.drawable.safety_center_sensor_toggle_disabled);
+ }
+ if (sensorEnabled) {
+ icon = KotlinUtils.INSTANCE.getPermGroupIcon(mContext, groupName, colorPrimary);
+ } else {
+ icon = mContext.getDrawable(getBlockedIconResId(groupName));
+ icon.setTint(colorPrimary);
+ }
+ blockedStatus.setText(getSensorStatusTextResId(groupName, sensorEnabled));
+ blockedStatus.setTextColor(colorSecondary);
+ groupLabel.setTextColor(colorPrimary);
+ iconView.setImageDrawable(icon);
+
+ int contentDescriptionResId = R.string.safety_center_qs_privacy_control;
+ toggle.setContentDescription(
+ mContext.getString(
+ contentDescriptionResId,
+ groupLabel.getText(),
+ blockedStatus.getText()));
+ ViewCompat.replaceAccessibilityAction(
+ toggle,
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
+ mContext.getString(R.string.safety_center_qs_toggle_action),
+ null);
+ }
+ }
+
+ @ColorInt
+ private int getTextColor(boolean primary, boolean inverse, boolean useLowerOpacity) {
+ int primaryAttribute =
+ inverse ? android.R.attr.textColorPrimaryInverse : android.R.attr.textColorPrimary;
+ int secondaryAttribute =
+ inverse
+ ? android.R.attr.textColorSecondaryInverse
+ : android.R.attr.textColorSecondary;
+ int attribute = primary ? primaryAttribute : secondaryAttribute;
+ TypedValue value = new TypedValue();
+ mContext.getTheme().resolveAttribute(attribute, value, true);
+ int colorRes = value.resourceId != 0 ? value.resourceId : value.data;
+ int color = mContext.getColor(colorRes);
+ if (useLowerOpacity) {
+ color = colorWithAdjustedAlpha(color, 0.5f);
+ }
+ return color;
+ }
+
+ @ColorInt
+ private int colorWithAdjustedAlpha(@ColorInt int color, float factor) {
+ return Color.argb(
+ Math.round(Color.alpha(color) * factor),
+ Color.red(color),
+ Color.green(color),
+ Color.blue(color));
+ }
+
+ private CharSequence getPermGroupLabel(String permissionGroup) {
+ switch (permissionGroup) {
+ case MICROPHONE:
+ return mContext.getString(R.string.microphone_toggle_label_qs);
+ case CAMERA:
+ return mContext.getString(R.string.camera_toggle_label_qs);
+ }
+ return KotlinUtils.INSTANCE.getPermGroupLabel(mContext, permissionGroup);
+ }
+
+ private static int getRemovePermissionText(String permissionGroup) {
+ return CAMERA.equals(permissionGroup)
+ ? R.string.remove_camera_qs
+ : R.string.remove_microphone_qs;
+ }
+
+ private static int getSeeUsageText(String permissionGroup) {
+ return CAMERA.equals(permissionGroup)
+ ? R.string.camera_usage_qs
+ : R.string.microphone_usage_qs;
+ }
+
+ private static int getBlockedIconResId(String permissionGroup) {
+ switch (permissionGroup) {
+ case MICROPHONE:
+ return R.drawable.ic_mic_blocked;
+ case CAMERA:
+ return R.drawable.ic_camera_blocked;
+ case LOCATION:
+ return R.drawable.ic_location_blocked;
+ }
+ return -1;
+ }
+
+ private static int getSensorStatusTextResId(String permissionGroup, boolean enabled) {
+ switch (permissionGroup) {
+ case LOCATION:
+ return enabled ? R.string.on : R.string.off;
+ }
+ return enabled ? R.string.available : R.string.blocked;
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterScrollWrapperFragment.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterScrollWrapperFragment.kt
new file mode 100644
index 000000000..c064b94f0
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterScrollWrapperFragment.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.permissioncontroller.safetycenter.ui
+
+import android.os.Build
+import android.os.Bundle
+import androidx.annotation.RequiresApi
+import androidx.fragment.app.Fragment
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.utils.Utils
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+internal class SafetyCenterScrollWrapperFragment :
+ Fragment(
+ if (SafetyCenterUiFlags.getShowSubpages()) R.layout.safety_center_non_scroll_wrapper
+ else R.layout.safety_center_scroll_wrapper
+ ) {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if (savedInstanceState == null) {
+ childFragmentManager
+ .beginTransaction()
+ .add(
+ R.id.fragment_container,
+ SafetyCenterDashboardFragment.newInstance(
+ Utils.getOrGenerateSessionId(requireActivity().getIntent()),
+ /* isQuickSettingsFragment= */ false
+ )
+ )
+ .commitNow()
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterSubpageFragment.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterSubpageFragment.kt
new file mode 100644
index 000000000..5e45d2b3c
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterSubpageFragment.kt
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.permissioncontroller.safetycenter.ui
+
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import android.os.Bundle
+import android.safetycenter.SafetyCenterEntryGroup
+import android.util.Log
+import androidx.annotation.RequiresApi
+import androidx.preference.PreferenceGroup
+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.settingslib.widget.FooterPreference
+
+/** A fragment that represents a generic subpage in Safety Center. */
+@RequiresApi(UPSIDE_DOWN_CAKE)
+class SafetyCenterSubpageFragment : SafetyCenterFragment() {
+
+ private lateinit var sourceGroupId: String
+ private lateinit var subpageBrandChip: SafetyBrandChipPreference
+ private lateinit var subpageIllustration: SafetyIllustrationPreference
+ private lateinit var subpageIssueGroup: PreferenceGroup
+ private lateinit var subpageEntryGroup: PreferenceGroup
+ private lateinit var subpageFooter: FooterPreference
+
+ override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
+ super.onCreatePreferences(savedInstanceState, rootKey)
+ setPreferencesFromResource(R.xml.safety_center_subpage, rootKey)
+ sourceGroupId = requireArguments().getString(SOURCE_GROUP_ID_KEY)!!
+
+ subpageBrandChip = getPreferenceScreen().findPreference(BRAND_CHIP_KEY)!!
+ subpageIllustration = getPreferenceScreen().findPreference(ILLUSTRATION_KEY)!!
+ subpageIssueGroup = getPreferenceScreen().findPreference(ISSUE_GROUP_KEY)!!
+ subpageEntryGroup = getPreferenceScreen().findPreference(ENTRY_GROUP_KEY)!!
+ subpageFooter = getPreferenceScreen().findPreference(FOOTER_KEY)!!
+
+ subpageBrandChip.setupListener(requireActivity(), safetyCenterSessionId)
+ setupIllustration()
+ setupFooter()
+
+ prerenderCurrentSafetyCenterData()
+ }
+
+ override fun configureInteractionLogger() {
+ val logger = safetyCenterViewModel.interactionLogger
+ logger.sessionId = safetyCenterSessionId
+ logger.navigationSource = NavigationSource.fromIntent(requireActivity().getIntent())
+ logger.viewType = ViewType.SUBPAGE
+ logger.groupId = sourceGroupId
+ }
+
+ override fun onResume() {
+ super.onResume()
+ safetyCenterViewModel.pageOpen(sourceGroupId)
+ }
+
+ override fun renderSafetyCenterData(uiData: SafetyCenterUiData?) {
+ Log.d(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")
+ closeSubpage(requireActivity(), requireContext(), safetyCenterSessionId)
+ return
+ }
+
+ requireActivity().setTitle(entryGroup.title)
+ updateSafetyCenterIssues(uiData)
+ updateSafetyCenterEntries(entryGroup)
+ }
+
+ private fun setupIllustration() {
+ val resName = "illustration_${SnakeCaseConverter.fromCamelCase(sourceGroupId)}"
+ val context = requireContext()
+ val drawable =
+ SafetyCenterResourcesContext(context).getDrawableByName(resName, context.theme)
+ if (drawable == null) {
+ Log.w(TAG, "$sourceGroupId doesn't have any matching illustration")
+ subpageIllustration.setVisible(false)
+ }
+
+ subpageIllustration.illustrationDrawable = drawable
+ }
+
+ private fun setupFooter() {
+ val resName = "${SnakeCaseConverter.fromCamelCase(sourceGroupId)}_footer"
+ val footerText = SafetyCenterResourcesContext(requireContext()).getStringByName(resName)
+ if (footerText.isEmpty()) {
+ Log.w(TAG, "$sourceGroupId doesn't have any matching footer")
+ subpageFooter.setVisible(false)
+ }
+ // footer is ordered last by default
+ // in order to keep a spacer after the footer, footer needs to be the second from last
+ subpageFooter.setOrder(Int.MAX_VALUE - 2)
+ subpageFooter.setSummary(footerText)
+ }
+
+ private fun updateSafetyCenterIssues(uiData: SafetyCenterUiData?) {
+ subpageIssueGroup.removeAll()
+ val subpageIssues = uiData?.getMatchingIssues(sourceGroupId)
+ val subpageDismissedIssues = uiData?.getMatchingDismissedIssues(sourceGroupId)
+
+ subpageIllustration.isVisible =
+ subpageIssues.isNullOrEmpty() && subpageIllustration.illustrationDrawable != null
+
+ if (subpageIssues.isNullOrEmpty() && subpageDismissedIssues.isNullOrEmpty()) {
+ Log.w(TAG, "$sourceGroupId doesn't have any matching SafetyCenterIssues")
+ return
+ }
+
+ collapsableIssuesCardHelper.addIssues(
+ requireContext(),
+ safetyCenterViewModel,
+ getChildFragmentManager(),
+ subpageIssueGroup,
+ subpageIssues,
+ subpageDismissedIssues,
+ uiData.resolvedIssues,
+ requireActivity().getTaskId()
+ )
+ }
+
+ private fun updateSafetyCenterEntries(entryGroup: SafetyCenterEntryGroup) {
+ Log.d(TAG, "updateSafetyCenterEntries called with $entryGroup")
+ subpageEntryGroup.removeAll()
+ for (entry in entryGroup.entries) {
+ subpageEntryGroup.addPreference(
+ SafetySubpageEntryPreference(
+ requireContext(),
+ PendingIntentSender.getTaskIdForEntry(
+ entry.id,
+ sameTaskSourceIds,
+ requireActivity()
+ ),
+ entry,
+ safetyCenterViewModel
+ )
+ )
+ }
+ }
+
+ companion object {
+ private val TAG: String = SafetyCenterSubpageFragment::class.java.simpleName
+ private const val BRAND_CHIP_KEY: String = "subpage_brand_chip"
+ private const val ILLUSTRATION_KEY: String = "subpage_illustration"
+ private const val ISSUE_GROUP_KEY: String = "subpage_issue_group"
+ private const val ENTRY_GROUP_KEY: String = "subpage_entry_group"
+ private const val FOOTER_KEY: String = "subpage_footer"
+ private const val SOURCE_GROUP_ID_KEY: String = "source_group_id"
+
+ /** Creates an instance of SafetyCenterSubpageFragment with the arguments set */
+ @JvmStatic
+ fun newInstance(sessionId: Long, groupId: String): SafetyCenterSubpageFragment {
+ val args = Bundle()
+ args.putLong(EXTRA_SESSION_ID, sessionId)
+ args.putString(SOURCE_GROUP_ID_KEY, groupId)
+
+ val subpageFragment = SafetyCenterSubpageFragment()
+ subpageFragment.setArguments(args)
+ return subpageFragment
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterTouchTarget.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterTouchTarget.kt
new file mode 100644
index 000000000..0e368291e
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterTouchTarget.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.permissioncontroller.safetycenter.ui
+
+import android.graphics.Rect
+import android.os.Build
+import android.view.TouchDelegate
+import android.view.View
+import androidx.annotation.DimenRes
+import androidx.annotation.RequiresApi
+
+/** Class to configure touch targets for Safety Center. */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+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
+ */
+ @JvmStatic
+ fun configureSize(view: View, @DimenRes minTouchTargetSizeResource: Int) {
+ val parent = view.parent as View
+ val res = view.context.resources
+ val minTouchTargetSize = res.getDimensionPixelSize(minTouchTargetSizeResource)
+
+ // Defer getHitRect so that it's called after the parent's children are laid out.
+ parent.post {
+ val hitRect = Rect()
+ view.getHitRect(hitRect)
+ val currentTouchTargetWidth = hitRect.width()
+ if (currentTouchTargetWidth < minTouchTargetSize) {
+ // Divide width difference by two to get adjustment
+ val adjustInsetBy = (minTouchTargetSize - currentTouchTargetWidth) / 2
+
+ // Inset adjustment is applied to top, bottom, left, right
+ hitRect.inset(-adjustInsetBy, -adjustInsetBy)
+ parent.touchDelegate = TouchDelegate(hitRect, view)
+ }
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterUiFlags.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterUiFlags.kt
new file mode 100644
index 000000000..a8258d437
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterUiFlags.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.permissioncontroller.safetycenter.ui
+
+import android.provider.DeviceConfig
+import com.android.modules.utils.build.SdkLevel
+
+/** A class to access the Safety Center UI related {@link DeviceConfig} flags. */
+object SafetyCenterUiFlags {
+ private const val PROPERTY_SHOW_SUBPAGES = "safety_center_show_subpages"
+
+ /**
+ * Returns whether to show subpages in the Safety Center UI for Android-U instead of the
+ * expand-and-collapse list implementation.
+ */
+ @JvmStatic
+ fun getShowSubpages(): Boolean {
+ return SdkLevel.isAtLeastU() &&
+ DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_SHOW_SUBPAGES, true)
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyEntry.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyEntry.java
deleted file mode 100644
index 058b947b7..000000000
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyEntry.java
+++ /dev/null
@@ -1,117 +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.permissioncontroller.safetycenter.ui;
-
-/** An entry to be shown as a preference in Safety Center */
-public class SafetyEntry {
-
- /** Minimum entry order. Smaller values will be set to DEFAULT_ENTRY_ORDER. */
- private static final int MIN_ENTRY_ORDER = 1;
- /** Default entry order. Unspecified order values will be set to this. */
- private static final int DEFAULT_ENTRY_ORDER = 1000;
-
- private String mTitle;
- private String mSummary;
- private SeverityLevel mSeverityLevel;
- private int mOrder;
- private String mSafetySourceId;
-
- private SafetyEntry(SafetyEntry.Builder builder) {
- mTitle = builder.mTitle;
- mSummary = builder.mSummary;
- mSeverityLevel = builder.mSeverityLevel;
- mOrder = builder.mOrder;
- mSafetySourceId = builder.mSafetySourceId;
- }
-
- /** Builds the SafetyEntry. */
- public static SafetyEntry.Builder builder() {
- return new SafetyEntry.Builder();
- }
-
- /** Returns the title. */
- public String getTitle() {
- return mTitle;
- }
-
- /** Returns the summary. */
- public String getSummary() {
- return mSummary;
- }
-
- /** Returns the severity level. */
- public SeverityLevel getSeverityLevel() {
- return mSeverityLevel;
- }
-
- /** Returns the order that this entry should have in the entry list. */
- public int getOrder() {
- return mOrder;
- }
-
- /** Returns the safety source id. */
- public String getSafetySourceId() {
- return mSafetySourceId;
- }
-
- /** Builder for the SafetyEntry class. */
- public static class Builder {
- private String mTitle;
- private String mSummary;
- private SeverityLevel mSeverityLevel;
- private int mOrder = DEFAULT_ENTRY_ORDER;
- private String mSafetySourceId;
-
- /** Sets the title. */
- public SafetyEntry.Builder setTitle(String title) {
- mTitle = title;
- return this;
- }
-
- /** Sets the summary. */
- public SafetyEntry.Builder setSummary(String summary) {
- mSummary = summary;
- return this;
- }
-
- /** Sets the severity level. */
- public SafetyEntry.Builder setSeverityLevel(SeverityLevel severityLevel) {
- mSeverityLevel = severityLevel;
- return this;
- }
-
- /**
- * Sets the order that this entry should appear in the list of entries.
- * If <= 0, the value will be ignored and the entry will use a default order.
- */
- public SafetyEntry.Builder setOrder(int order) {
- mOrder = order >= MIN_ENTRY_ORDER ? order : DEFAULT_ENTRY_ORDER;
- return this;
- }
-
- /** Sets the safety source id. */
- public SafetyEntry.Builder setSafetySourceId(String safetySourceId) {
- mSafetySourceId = safetySourceId;
- return this;
- }
-
- /** Builds the SafetyEntry. */
- public SafetyEntry build() {
- return new SafetyEntry(this);
- }
- }
-}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyEntryPreference.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyEntryPreference.java
index e7751af4e..249354ad1 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyEntryPreference.java
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyEntryPreference.java
@@ -16,51 +16,65 @@
package com.android.permissioncontroller.safetycenter.ui;
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
import android.content.Context;
import android.safetycenter.SafetyCenterEntry;
-import android.util.Log;
+import android.text.TextUtils;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.permissioncontroller.R;
+import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterViewModel;
+import com.android.permissioncontroller.safetycenter.ui.view.SafetyEntryView;
/** A preference that displays a visual representation of a {@link SafetyCenterEntry}. */
-public class SafetyEntryPreference extends Preference {
+@RequiresApi(TIRAMISU)
+public final class SafetyEntryPreference extends Preference implements ComparablePreference {
- private static final String TAG = SafetyEntryPreference.class.getSimpleName();
+ private final PositionInCardList mPosition;
+ private final SafetyCenterEntry mEntry;
+ private final SafetyCenterViewModel mViewModel;
+ @Nullable private final Integer mLaunchTaskId;
- public SafetyEntryPreference(Context context, SafetyCenterEntry entry) {
+ public SafetyEntryPreference(
+ Context context,
+ @Nullable Integer launchTaskId,
+ SafetyCenterEntry entry,
+ PositionInCardList position,
+ SafetyCenterViewModel viewModel) {
super(context);
- setTitle(entry.getTitle());
- setSummary(entry.getSummary());
- setIcon(toSeverityLevel(entry.getSeverityLevel()).getEntryIconResId());
- if (entry.getPendingIntent() != null) {
- setOnPreferenceClickListener(unused -> {
- try {
- entry.getPendingIntent().send();
- } catch (Exception ex) {
- Log.e(TAG,
- String.format("Failed to execute pending intent for entry: %s", entry),
- ex);
- }
- return true;
- });
- }
+
+ mEntry = entry;
+ mPosition = position;
+ mViewModel = viewModel;
+ mLaunchTaskId = launchTaskId;
+
+ setLayoutResource(R.layout.preference_entry);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+
+ ((SafetyEntryView) holder.itemView).showEntry(mEntry, mPosition, mLaunchTaskId, mViewModel);
+ }
+
+ @Override
+ public boolean isSameItem(Preference other) {
+ return other instanceof SafetyEntryPreference
+ && TextUtils.equals(mEntry.getId(), ((SafetyEntryPreference) other).mEntry.getId());
}
- private static SeverityLevel toSeverityLevel(int entrySeverityLevel) {
- switch (entrySeverityLevel) {
- case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN:
- return SeverityLevel.SEVERITY_LEVEL_UNKNOWN;
- case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED:
- return SeverityLevel.NONE;
- case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK:
- return SeverityLevel.INFORMATION;
- case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION:
- return SeverityLevel.RECOMMENDATION;
- case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING:
- return SeverityLevel.CRITICAL_WARNING;
+ @Override
+ public boolean hasSameContents(Preference other) {
+ if (other instanceof SafetyEntryPreference) {
+ SafetyEntryPreference o = (SafetyEntryPreference) other;
+ return mEntry.equals(o.mEntry) && mPosition == o.mPosition;
}
- throw new IllegalArgumentException(
- String.format("Unexpected SafetyCenterEntry.EntrySeverityLevel: %s",
- entrySeverityLevel));
+ return false;
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyGroupPreference.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyGroupPreference.kt
new file mode 100644
index 000000000..2a9f6f780
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyGroupPreference.kt
@@ -0,0 +1,70 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui
+
+import android.content.Context
+import android.os.Build
+import android.safetycenter.SafetyCenterEntryGroup
+import android.text.TextUtils
+import androidx.annotation.RequiresApi
+import androidx.preference.Preference
+import androidx.preference.PreferenceViewHolder
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterViewModel
+import com.android.permissioncontroller.safetycenter.ui.view.SafetyEntryGroupView
+
+/** A preference that displays a visual representation of a {@link SafetyCenterEntryGroup}. */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class SafetyGroupPreference(
+ context: Context,
+ private val group: SafetyCenterEntryGroup,
+ private val isExpanded: (String) -> Boolean,
+ private val isFirstCard: Boolean,
+ private val isLastCard: Boolean,
+ private val getTaskIdForEntry: (String) -> Int,
+ private val viewModel: SafetyCenterViewModel,
+ private val onExpandedListener: (String) -> Unit,
+ private val onCollapsedListener: (String) -> Unit
+) : Preference(context), ComparablePreference {
+
+ init {
+ layoutResource = R.layout.preference_group
+ }
+
+ override fun onBindViewHolder(holder: PreferenceViewHolder?) {
+ super.onBindViewHolder(holder)
+
+ (holder?.itemView as? SafetyEntryGroupView)?.showGroup(
+ group,
+ isExpanded,
+ isFirstCard,
+ isLastCard,
+ getTaskIdForEntry,
+ viewModel,
+ onExpandedListener,
+ onCollapsedListener)
+ }
+
+ override fun isSameItem(preference: Preference): Boolean =
+ preference is SafetyGroupPreference && TextUtils.equals(group.id, preference.group.id)
+
+ override fun hasSameContents(preference: Preference): Boolean =
+ preference is SafetyGroupPreference &&
+ group == preference.group &&
+ isFirstCard == preference.isFirstCard &&
+ isLastCard == preference.isLastCard
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyHomepageEntryPreference.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyHomepageEntryPreference.kt
new file mode 100644
index 000000000..0cfc2ee50
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyHomepageEntryPreference.kt
@@ -0,0 +1,73 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui
+
+import android.content.Context
+import android.content.Intent
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import android.safetycenter.SafetyCenterEntryGroup
+import android.safetycenter.SafetyCenterManager
+import android.text.TextUtils
+import androidx.annotation.RequiresApi
+import androidx.preference.Preference
+import com.android.permissioncontroller.Constants.EXTRA_SESSION_ID
+import com.android.permissioncontroller.safetycenter.SafetyCenterConstants
+import java.util.Objects
+
+/**
+ * A preference that displays a visual representation of a {@link SafetyCenterEntryGroup} on the
+ * Safety Center homepage.
+ */
+@RequiresApi(UPSIDE_DOWN_CAKE)
+internal class SafetyHomepageEntryPreference(
+ context: Context,
+ private val entryGroup: SafetyCenterEntryGroup,
+ sessionId: Long
+) : Preference(context), ComparablePreference {
+
+ init {
+ setTitle(entryGroup.title)
+ setSummary(entryGroup.summary)
+ setIcon(
+ SeverityIconPicker.selectIconResId(
+ entryGroup.id,
+ entryGroup.severityLevel,
+ entryGroup.severityUnspecifiedIconType
+ )
+ )
+
+ val intent = Intent(Intent.ACTION_SAFETY_CENTER)
+ intent.putExtra(SafetyCenterManager.EXTRA_SAFETY_SOURCES_GROUP_ID, entryGroup.id)
+ intent.putExtra(SafetyCenterConstants.EXTRA_OPENED_FROM_HOMEPAGE, true)
+ intent.putExtra(EXTRA_SESSION_ID, sessionId)
+ NavigationSource.SAFETY_CENTER.addToIntent(intent)
+ setIntent(intent)
+ setKey(entryGroup.id)
+ }
+
+ override fun isSameItem(preference: Preference): Boolean =
+ preference is SafetyHomepageEntryPreference && entryGroup.id == preference.entryGroup.id
+
+ override fun hasSameContents(preference: Preference): Boolean =
+ preference is SafetyHomepageEntryPreference &&
+ Objects.equals(entryGroup.id, preference.entryGroup.id) &&
+ TextUtils.equals(entryGroup.title, preference.entryGroup.title) &&
+ TextUtils.equals(entryGroup.summary, preference.entryGroup.summary) &&
+ entryGroup.severityLevel == preference.entryGroup.severityLevel &&
+ entryGroup.severityUnspecifiedIconType ==
+ preference.entryGroup.severityUnspecifiedIconType
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyIllustrationPreference.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyIllustrationPreference.kt
new file mode 100644
index 000000000..5acb27131
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyIllustrationPreference.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.safetycenter.ui
+
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import android.util.AttributeSet
+import android.widget.ImageView
+import androidx.annotation.RequiresApi
+import androidx.preference.Preference
+import androidx.preference.PreferenceViewHolder
+import com.android.permissioncontroller.R
+
+/** A preference that displays the illustration on a Safety Center subpage. */
+@RequiresApi(UPSIDE_DOWN_CAKE)
+internal class SafetyIllustrationPreference(context: Context, attrs: AttributeSet) :
+ Preference(context, attrs) {
+
+ init {
+ layoutResource = R.layout.preference_illustration
+ }
+
+ var illustrationDrawable: Drawable? = null
+ set(drawable: Drawable?) {
+ if (drawable !== field) {
+ field = drawable
+ notifyChanged()
+ }
+ }
+
+ override fun onBindViewHolder(holder: PreferenceViewHolder) {
+ super.onBindViewHolder(holder)
+ val illustrationView = holder.findViewById(R.id.illustration_view) as ImageView
+ illustrationView.setImageDrawable(illustrationDrawable)
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyPreferenceComparisonCallback.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyPreferenceComparisonCallback.java
new file mode 100644
index 000000000..2daf1e06d
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyPreferenceComparisonCallback.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.permissioncontroller.safetycenter.ui;
+
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import androidx.annotation.RequiresApi;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceManager.SimplePreferenceComparisonCallback;
+
+/** A {@link PreferenceComparisonCallback} to identify changed preferences of Safety Center. */
+@RequiresApi(TIRAMISU)
+class SafetyPreferenceComparisonCallback extends SimplePreferenceComparisonCallback {
+
+ @Override
+ public boolean arePreferenceItemsTheSame(Preference oldPreference, Preference newPreference) {
+ if (oldPreference instanceof ComparablePreference) {
+ return ((ComparablePreference) oldPreference).isSameItem(newPreference);
+ }
+ return super.arePreferenceItemsTheSame(oldPreference, newPreference);
+ }
+
+ @Override
+ public boolean arePreferenceContentsTheSame(
+ Preference oldPreference, Preference newPreference) {
+ if (oldPreference instanceof ComparablePreference) {
+ return ((ComparablePreference) oldPreference).hasSameContents(newPreference);
+ }
+ return super.arePreferenceContentsTheSame(oldPreference, newPreference);
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusAnimationSequencer.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusAnimationSequencer.kt
new file mode 100644
index 000000000..c48ad734b
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusAnimationSequencer.kt
@@ -0,0 +1,168 @@
+/*
+ * 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.safetycenter.ui
+
+import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN
+
+/**
+ * Controls the animation flow and hold all the data necessary to determine the appearance of Status
+ * icon of [SafetyStatusPreference]. For each lifecycle event (such as [onUpdateReceived],
+ * [onStartScanningAnimationStart], [onStartScanningAnimationEnd], etc.) it changes its internal
+ * state and may provide a presentation instruction in the form of [Action].
+ */
+internal class SafetyStatusAnimationSequencer {
+
+ private var isIconChangeAnimationRunning: Boolean = false
+ private var isScanAnimationRunning: Boolean = false
+ private var shouldStartScanAnimation: Boolean = false
+ private var queuedIconChangeAnimationSeverityLevel: Int? = null
+ /**
+ * Stores the last known Severity Level that user could observe as a static status image, as
+ * scan animation, or as the beginning state of a changing status animation.
+ */
+ private var currentlyVisibleSeverityLevel: Int = OVERALL_SEVERITY_LEVEL_UNKNOWN
+
+ fun getCurrentlyVisibleSeverityLevel(): Int {
+ return currentlyVisibleSeverityLevel
+ }
+
+ fun onUpdateReceived(isRefreshInProgress: Boolean, severityLevel: Int): Action? {
+ if (isRefreshInProgress) {
+ if (isIconChangeAnimationRunning) {
+ shouldStartScanAnimation = true
+ return null
+ } else if (!isScanAnimationRunning) {
+ currentlyVisibleSeverityLevel = severityLevel
+ return Action.START_SCANNING_ANIMATION
+ }
+ // isRefreshInProgress && isScanAnimationRunning && !isIconChangeAnimationRunning
+ // Next action needs to wait for onStartScanningAnimationEnd or
+ // onContinueScanningAnimationEnd not to break currently running animation.
+ return null
+ } else {
+ val isDifferentSeverityQueued =
+ queuedIconChangeAnimationSeverityLevel != null &&
+ queuedIconChangeAnimationSeverityLevel != severityLevel
+ val shouldChangeIcon =
+ currentlyVisibleSeverityLevel != severityLevel || isDifferentSeverityQueued
+
+ if (isIconChangeAnimationRunning || shouldChangeIcon && isScanAnimationRunning) {
+ queuedIconChangeAnimationSeverityLevel = severityLevel
+ }
+ if (isScanAnimationRunning) {
+ return Action.FINISH_SCANNING_ANIMATION
+ } else if (shouldChangeIcon && !isIconChangeAnimationRunning) {
+ return Action.START_ICON_CHANGE_ANIMATION
+ } else if (!isIconChangeAnimationRunning) {
+ // Possible if status was finalized by Safety Center at the beginning,
+ // when no scanning animation is launched and refresh is not in progress.
+ // In this case we need to show the final icon straigt away without any animations.
+ return Action.CHANGE_ICON_WITHOUT_ANIMATION
+ }
+ // !isRefreshInProgress && !isScanAnimationRunning && isIconChangeAnimationRunning
+ // Next action needs to wait for onIconChangeAnimationEnd not to break currently
+ // running animation.
+ return null
+ }
+ }
+
+ fun onStartScanningAnimationStart() {
+ isScanAnimationRunning = true
+ }
+
+ fun onStartScanningAnimationEnd(): Action {
+ return Action.CONTINUE_SCANNING_ANIMATION
+ }
+
+ fun onContinueScanningAnimationEnd(isRefreshInProgress: Boolean, severityLevel: Int): Action? {
+ if (isRefreshInProgress) {
+ if (currentlyVisibleSeverityLevel != severityLevel) {
+ // onUpdateReceived does not handle this case since we should not break
+ // the animation while it is running. Once current scan cycle is finished, this
+ // call will return the request to restart animation with updated severity level.
+ currentlyVisibleSeverityLevel = severityLevel
+ return Action.RESET_SCANNING_ANIMATION
+ } else {
+ return Action.CONTINUE_SCANNING_ANIMATION
+ }
+ } else {
+ // Possible if scanning animation has been ended right after status is updated with
+ // final data, but before we got the onUpdateReceived call (that is posted to the
+ // message queue and will happen soon), so no need to do anything right now.
+ return null
+ }
+ }
+
+ fun onFinishScanAnimationEnd(isRefreshing: Boolean, severityLevel: Int): Action {
+ isScanAnimationRunning = false
+ currentlyVisibleSeverityLevel = severityLevel
+ return handleQueuedAction(isRefreshing, severityLevel)
+ }
+
+ fun onCouldNotStartIconChangeAnimation(isRefreshing: Boolean, severityLevel: Int): Action {
+ return handleQueuedAction(isRefreshing, severityLevel)
+ }
+
+ fun onIconChangeAnimationStart() {
+ isIconChangeAnimationRunning = true
+ }
+
+ fun onIconChangeAnimationEnd(isRefreshing: Boolean, severityLevel: Int): Action {
+ isIconChangeAnimationRunning = false
+ currentlyVisibleSeverityLevel = severityLevel
+ return handleQueuedAction(isRefreshing, severityLevel)
+ }
+
+ private fun handleQueuedAction(isRefreshing: Boolean, severityLevel: Int): Action {
+ if (shouldStartScanAnimation) {
+ shouldStartScanAnimation = false
+ if (isRefreshing) {
+ return Action.START_SCANNING_ANIMATION
+ } else {
+ return handleQueuedAction(isRefreshing, severityLevel)
+ }
+ } else if (queuedIconChangeAnimationSeverityLevel != null) {
+ val queuedSeverityLevel = queuedIconChangeAnimationSeverityLevel
+ queuedIconChangeAnimationSeverityLevel = null
+ if (currentlyVisibleSeverityLevel != queuedSeverityLevel) {
+ return Action.START_ICON_CHANGE_ANIMATION
+ } else {
+ return handleQueuedAction(isRefreshing, severityLevel)
+ }
+ }
+ currentlyVisibleSeverityLevel = severityLevel
+ return Action.CHANGE_ICON_WITHOUT_ANIMATION
+ }
+
+ /** Set of instructions of what should Status icon currently show. */
+ enum class Action {
+ START_SCANNING_ANIMATION,
+ /**
+ * Requests to continue the scanning animation with the same Severity Level as stored in
+ * [currentlyVisibleSeverityLevel].
+ */
+ CONTINUE_SCANNING_ANIMATION,
+ /**
+ * Requests to start scanning animation from the beginning when
+ * [currentlyVisibleSeverityLevel] has been changed.
+ */
+ RESET_SCANNING_ANIMATION,
+ FINISH_SCANNING_ANIMATION,
+ START_ICON_CHANGE_ANIMATION,
+ CHANGE_ICON_WITHOUT_ANIMATION
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusPreference.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusPreference.java
index eac224bc2..0b8706a38 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusPreference.java
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyStatusPreference.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,32 +16,59 @@
package com.android.permissioncontroller.safetycenter.ui;
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
import android.content.Context;
+import android.graphics.drawable.Animatable2;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
import android.safetycenter.SafetyCenterStatus;
+import android.text.TextUtils;
import android.util.AttributeSet;
-import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.permissioncontroller.R;
+import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterViewModel;
+import com.android.permissioncontroller.safetycenter.ui.model.StatusUiData;
+import com.android.permissioncontroller.safetycenter.ui.view.StatusCardView;
+
+import kotlin.Pair;
+
+import java.util.List;
+import java.util.Objects;
/** Preference which displays a visual representation of {@link SafetyCenterStatus}. */
-public class SafetyStatusPreference extends Preference {
+@RequiresApi(TIRAMISU)
+public class SafetyStatusPreference extends Preference implements ComparablePreference {
+
+ @Nullable private StatusUiData mStatus;
+ @Nullable private SafetyCenterViewModel mViewModel;
- @Nullable
- private SafetyCenterStatus mStatus;
- @Nullable
- private View.OnClickListener mRescanButtonOnClickListener;
+ private final TextFadeAnimator mTitleTextAnimator = new TextFadeAnimator(R.id.status_title);
+
+ private final TextFadeAnimator mSummaryTextAnimator = new TextFadeAnimator(R.id.status_summary);
+
+ private final TextFadeAnimator mAllTextAnimator =
+ new TextFadeAnimator(List.of(R.id.status_title, R.id.status_summary));
+
+ private boolean mFirstBind = true;
public SafetyStatusPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.preference_safety_status);
}
+ private boolean mIsTextChangeAnimationRunning;
+ private final SafetyStatusAnimationSequencer mSequencer = new SafetyStatusAnimationSequencer();
+
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
@@ -50,41 +77,293 @@ public class SafetyStatusPreference extends Preference {
return;
}
- ((ImageView) holder.findViewById(R.id.status_image))
- .setImageResource(toStatusImageResId(mStatus.getSeverityLevel()));
+ Context context = getContext();
+ StatusCardView statusCardView = (StatusCardView) holder.itemView;
+ configureButtons(context, statusCardView);
+ statusCardView
+ .getTitleAndSummaryContainerView()
+ .setContentDescription(mStatus.getContentDescription(context));
- ((TextView) holder.findViewById(R.id.status_title)).setText(mStatus.getTitle());
- ((TextView) holder.findViewById(R.id.status_summary)).setText(mStatus.getSummary());
+ updateStatusIcon(statusCardView);
+
+ updateStatusText(statusCardView.getTitleView(), statusCardView.getSummaryView());
+
+ mFirstBind = false;
+ }
+
+ private void configureButtons(Context context, StatusCardView statusCardView) {
+ statusCardView
+ .getRescanButton()
+ .setOnClickListener(
+ unused -> {
+ SafetyCenterViewModel viewModel = requireViewModel();
+ viewModel.rescan();
+ viewModel.getInteractionLogger().record(Action.SCAN_INITIATED);
+ });
+ statusCardView
+ .getReviewSettingsButton()
+ .setOnClickListener(
+ unused -> {
+ SafetyCenterViewModel viewModel = requireViewModel();
+ viewModel.navigateToSafetyCenter(
+ context, NavigationSource.QUICK_SETTINGS_TILE);
+ viewModel.getInteractionLogger().record(Action.REVIEW_SETTINGS_CLICKED);
+ });
+
+ updateButtonState(statusCardView);
+ }
+
+ private void updateButtonState(StatusCardView statusCardView) {
+ if (mStatus == null) return; // Shouldn't happen in practice but we do it for null safety.
+ statusCardView.showButtons(mStatus);
+ }
- if (mRescanButtonOnClickListener != null) {
- holder.findViewById(R.id.rescan_button)
- .setOnClickListener(mRescanButtonOnClickListener);
+ private void updateStatusText(TextView title, TextView summary) {
+ if (mFirstBind) {
+ title.setText(mStatus.getTitle());
+ summary.setText(mStatus.getSummary(getContext()));
}
+ runTextAnimationIfNeeded(title, summary);
}
- void setSafetyStatus(SafetyCenterStatus status) {
- mStatus = status;
- notifyChanged();
+ private void updateStatusIcon(StatusCardView statusCardView) {
+ int severityLevel = mStatus.getSeverityLevel();
+ boolean isRefreshing = mStatus.isRefreshInProgress();
+
+ handleAnimationSequencerAction(
+ mSequencer.onUpdateReceived(isRefreshing, severityLevel),
+ statusCardView,
+ /* scanningAnimation= */ null);
+ }
+
+ private void runTextAnimationIfNeeded(TextView titleView, TextView summaryView) {
+ if (mIsTextChangeAnimationRunning) {
+ return;
+ }
+ 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 =
+ () -> {
+ mIsTextChangeAnimationRunning = false;
+ runTextAnimationIfNeeded(titleView, summaryView);
+ };
+ mIsTextChangeAnimationRunning = !titleEquals || !summaryEquals;
+ if (!titleEquals && !summaryEquals) {
+ Pair<TextView, String> titleChange = new Pair<>(titleView, titleText);
+ Pair<TextView, String> summaryChange = new Pair<>(summaryView, summaryText);
+ mAllTextAnimator.animateChangeText(List.of(titleChange, summaryChange), onFinish);
+ } else if (!titleEquals) {
+ mTitleTextAnimator.animateChangeText(titleView, titleText, onFinish);
+ } else if (!summaryEquals) {
+ mSummaryTextAnimator.animateChangeText(summaryView, summaryText, onFinish);
+ }
}
- void setRescanButtonOnClickListener(View.OnClickListener listener) {
- mRescanButtonOnClickListener = listener;
- notifyChanged();
+ private void startScanningAnimation(StatusCardView statusCardView) {
+ mSequencer.onStartScanningAnimationStart();
+ ImageView statusImage = statusCardView.getStatusImageView();
+ statusImage.setImageResource(
+ StatusAnimationResolver.getScanningStartAnimation(
+ mSequencer.getCurrentlyVisibleSeverityLevel()));
+ AnimatedVectorDrawable animation = (AnimatedVectorDrawable) statusImage.getDrawable();
+ animation.registerAnimationCallback(
+ new Animatable2.AnimationCallback() {
+ @Override
+ public void onAnimationEnd(Drawable drawable) {
+ handleAnimationSequencerAction(
+ mSequencer.onStartScanningAnimationEnd(),
+ statusCardView,
+ /* scanningAnimation= */ null);
+ }
+ });
+ animation.start();
}
- private static int toStatusImageResId(int overallSeverityLevel) {
- switch (overallSeverityLevel) {
- case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN:
- return R.drawable.safety_status_info;
- case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK:
- return R.drawable.safety_status_info;
- case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION:
- return R.drawable.safety_status_recommendation;
- case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING:
- return R.drawable.safety_status_warn;
+ private void continueScanningAnimation(StatusCardView statusCardView) {
+ ImageView statusImage = statusCardView.getStatusImageView();
+
+ // clear previous scan animation in case we need to continue with different severity level
+ Drawable statusDrawable = statusImage.getDrawable();
+ if (statusDrawable instanceof AnimatedVectorDrawable) {
+ ((AnimatedVectorDrawable) statusDrawable).clearAnimationCallbacks();
+ }
+
+ statusImage.setImageResource(
+ StatusAnimationResolver.getScanningAnimation(
+ mSequencer.getCurrentlyVisibleSeverityLevel()));
+ AnimatedVectorDrawable scanningAnim = (AnimatedVectorDrawable) statusImage.getDrawable();
+ scanningAnim.registerAnimationCallback(
+ new Animatable2.AnimationCallback() {
+ @Override
+ public void onAnimationEnd(Drawable drawable) {
+ handleAnimationSequencerAction(
+ mSequencer.onContinueScanningAnimationEnd(
+ mStatus.isRefreshInProgress(), mStatus.getSeverityLevel()),
+ statusCardView,
+ scanningAnim);
+ }
+ });
+ scanningAnim.start();
+ }
+
+ private void endScanningAnimation(StatusCardView statusCardView) {
+ ImageView statusImage = statusCardView.getStatusImageView();
+ Drawable statusDrawable = statusImage.getDrawable();
+ int finishingSeverityLevel = mStatus.getSeverityLevel();
+ if (!(statusDrawable instanceof AnimatedVectorDrawable)) {
+ finishScanAnimation(statusCardView, finishingSeverityLevel);
+ return;
+ }
+ AnimatedVectorDrawable animatedStatusDrawable = (AnimatedVectorDrawable) statusDrawable;
+
+ if (!animatedStatusDrawable.isRunning()) {
+ finishScanAnimation(statusCardView, finishingSeverityLevel);
+ return;
+ }
+
+ int scanningSeverityLevel = mSequencer.getCurrentlyVisibleSeverityLevel();
+ animatedStatusDrawable.clearAnimationCallbacks();
+ animatedStatusDrawable.registerAnimationCallback(
+ new Animatable2.AnimationCallback() {
+ @Override
+ public void onAnimationEnd(Drawable drawable) {
+ statusImage.setImageResource(
+ StatusAnimationResolver.getScanningEndAnimation(
+ scanningSeverityLevel, finishingSeverityLevel));
+ AnimatedVectorDrawable animatedDrawable =
+ (AnimatedVectorDrawable) statusImage.getDrawable();
+ animatedDrawable.registerAnimationCallback(
+ new Animatable2.AnimationCallback() {
+ @Override
+ public void onAnimationEnd(Drawable drawable) {
+ super.onAnimationEnd(drawable);
+ finishScanAnimation(statusCardView, finishingSeverityLevel);
+ }
+ });
+ animatedDrawable.start();
+ }
+ });
+ }
+
+ private void finishScanAnimation(StatusCardView statusCardView, int finishedSeverityLevel) {
+ updateButtonState(statusCardView);
+ handleAnimationSequencerAction(
+ mSequencer.onFinishScanAnimationEnd(
+ mStatus.isRefreshInProgress(), finishedSeverityLevel),
+ statusCardView,
+ /* scanningAnimation= */ null);
+ }
+
+ private void startIconChangeAnimation(StatusCardView statusCardView) {
+ int finalSeverityLevel = mStatus.getSeverityLevel();
+ int changeAnimationResId =
+ StatusAnimationResolver.getStatusChangeAnimation(
+ mSequencer.getCurrentlyVisibleSeverityLevel(), finalSeverityLevel);
+ if (changeAnimationResId == 0) {
+ handleAnimationSequencerAction(
+ mSequencer.onCouldNotStartIconChangeAnimation(
+ mStatus.isRefreshInProgress(), finalSeverityLevel),
+ statusCardView,
+ /* scanningAnimation= */ null);
+ return;
+ }
+ mSequencer.onIconChangeAnimationStart();
+ statusCardView.getStatusImageView().setImageResource(changeAnimationResId);
+ AnimatedVectorDrawable animation =
+ (AnimatedVectorDrawable) statusCardView.getStatusImageView().getDrawable();
+ animation.clearAnimationCallbacks();
+ animation.registerAnimationCallback(
+ new Animatable2.AnimationCallback() {
+ @Override
+ public void onAnimationEnd(Drawable drawable) {
+ handleAnimationSequencerAction(
+ mSequencer.onIconChangeAnimationEnd(
+ mStatus.isRefreshInProgress(), finalSeverityLevel),
+ statusCardView,
+ /* scanningAnimation= */ null);
+ }
+ });
+ animation.start();
+ }
+
+ private void handleAnimationSequencerAction(
+ @Nullable SafetyStatusAnimationSequencer.Action action,
+ StatusCardView statusCardView,
+ @Nullable AnimatedVectorDrawable scanningAnimation) {
+ if (action == null) {
+ return;
+ }
+ switch (action) {
+ case START_SCANNING_ANIMATION:
+ startScanningAnimation(statusCardView);
+ break;
+ case CONTINUE_SCANNING_ANIMATION:
+ if (scanningAnimation != null) {
+ scanningAnimation.start();
+ } else {
+ continueScanningAnimation(statusCardView);
+ }
+ break;
+ case RESET_SCANNING_ANIMATION:
+ continueScanningAnimation(statusCardView);
+ break;
+ case FINISH_SCANNING_ANIMATION:
+ endScanningAnimation(statusCardView);
+ break;
+ case START_ICON_CHANGE_ANIMATION:
+ startIconChangeAnimation(statusCardView);
+ break;
+ case CHANGE_ICON_WITHOUT_ANIMATION:
+ setSettledStatus(statusCardView);
+ break;
+ }
+ }
+
+ private void setSettledStatus(StatusCardView statusCardView) {
+ Drawable statusDrawable = statusCardView.getStatusImageView().getDrawable();
+ if (statusDrawable instanceof AnimatedVectorDrawable) {
+ ((AnimatedVectorDrawable) statusDrawable).clearAnimationCallbacks();
+ }
+ statusCardView
+ .getStatusImageView()
+ .setImageResource(
+ StatusUiData.Companion.getStatusImageResId(
+ mSequencer.getCurrentlyVisibleSeverityLevel()));
+ }
+
+ void setData(StatusUiData statusUiData) {
+ mStatus = statusUiData;
+ safeNotifyChanged();
+ }
+
+ void setViewModel(SafetyCenterViewModel viewModel) {
+ mViewModel = Objects.requireNonNull(viewModel);
+ }
+
+ private SafetyCenterViewModel requireViewModel() {
+ return Objects.requireNonNull(mViewModel);
+ }
+
+ // 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);
+ }
+
+ @Override
+ public boolean isSameItem(Preference preference) {
+ return preference instanceof SafetyStatusPreference
+ && TextUtils.equals(getKey(), preference.getKey());
+ }
+
+ @Override
+ public boolean hasSameContents(Preference preference) {
+ if (!(preference instanceof SafetyStatusPreference)) {
+ return false;
}
- throw new IllegalArgumentException(
- String.format("Unexpected SafetyCenterStatus.OverallSeverityLevel: %s",
- overallSeverityLevel));
+ SafetyStatusPreference other = (SafetyStatusPreference) preference;
+ return Objects.equals(mStatus, other.mStatus);
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetySubpageEntryPreference.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetySubpageEntryPreference.kt
new file mode 100644
index 000000000..313798088
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetySubpageEntryPreference.kt
@@ -0,0 +1,139 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui
+
+import android.content.Context
+import android.os.Build
+import android.os.UserManager
+import android.safetycenter.SafetyCenterEntry
+import android.safetycenter.SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR
+import android.text.TextUtils
+import android.util.Log
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.annotation.RequiresApi
+import androidx.preference.Preference
+import androidx.preference.PreferenceViewHolder
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.safetycenter.SafetyCenterConstants.PERSONAL_PROFILE_SUFFIX
+import com.android.permissioncontroller.safetycenter.SafetyCenterConstants.WORK_PROFILE_SUFFIX
+import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterViewModel
+import com.android.permissioncontroller.safetycenter.ui.view.SafetyEntryCommonViewsManager.Companion.changeEnabledState
+import com.android.safetycenter.internaldata.SafetyCenterEntryId
+import com.android.safetycenter.internaldata.SafetyCenterIds
+import com.android.settingslib.widget.TwoTargetPreference
+
+/**
+ * A preference that displays a visual representation of a {@link SafetyCenterEntry} on the Safety
+ * Center subpage.
+ */
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+class SafetySubpageEntryPreference(
+ context: Context,
+ private val launchTaskId: Int?,
+ private val entry: SafetyCenterEntry,
+ private val viewModel: SafetyCenterViewModel
+) : TwoTargetPreference(context), ComparablePreference {
+
+ init {
+ setupIconActionButton()
+ setupClickListener()
+ setTitle(entry.title)
+ setSummary(entry.summary)
+ setSelectable(true)
+ setupPreferenceKey()
+ }
+
+ private fun setupIconActionButton() {
+ if (entry.iconAction != null) {
+ setIconSize(ICON_SIZE_MEDIUM)
+ setWidgetLayoutResource(
+ if (entry.iconAction!!.type == ICON_ACTION_TYPE_GEAR) {
+ R.layout.preference_entry_icon_action_gear_widget
+ } else {
+ R.layout.preference_entry_icon_action_info_widget
+ }
+ )
+ }
+ }
+
+ private fun setupClickListener() {
+ val pendingIntent = entry.pendingIntent
+ if (pendingIntent != null) {
+ setOnPreferenceClickListener {
+ try {
+ PendingIntentSender.send(pendingIntent, launchTaskId)
+ viewModel.interactionLogger.recordForEntry(Action.ENTRY_CLICKED, entry)
+ true
+ } catch (ex: Exception) {
+ Log.e(TAG, "Failed to execute pending intent for $entry", ex)
+ false
+ }
+ }
+ setEnabled(true)
+ } else {
+ Log.w(TAG, "Pending intent is null for $entry")
+ setEnabled(false)
+ }
+ }
+
+ private fun setupPreferenceKey() {
+ val entryId: SafetyCenterEntryId = SafetyCenterIds.entryIdFromString(entry.id)
+ val isWorkProfile =
+ context.getSystemService(UserManager::class.java).isManagedProfile(entryId.userId)
+ val keySuffix = if (isWorkProfile) WORK_PROFILE_SUFFIX else PERSONAL_PROFILE_SUFFIX
+ setKey("${entryId.safetySourceId}_$keySuffix")
+ }
+
+ override fun onBindViewHolder(holder: PreferenceViewHolder) {
+ super.onBindViewHolder(holder)
+ val iconAction = entry.iconAction
+ if (iconAction == null) {
+ Log.w(TAG, "Icon action is null for $entry")
+ } else {
+ val iconActionButton = holder.findViewById(R.id.icon_action_button) as? ImageView?
+ iconActionButton?.setOnClickListener {
+ try {
+ PendingIntentSender.send(iconAction.pendingIntent, launchTaskId)
+ viewModel.interactionLogger.recordForEntry(
+ Action.ENTRY_ICON_ACTION_CLICKED,
+ entry
+ )
+ } catch (ex: Exception) {
+ Log.e(TAG, "Failed to execute icon action intent for $entry", ex)
+ }
+ }
+ }
+
+ val titleView = holder.findViewById(android.R.id.title) as? TextView?
+ val summaryView = holder.findViewById(android.R.id.summary) as? TextView?
+ changeEnabledState(context, entry.isEnabled, isEnabled(), titleView, summaryView)
+ }
+
+ override fun shouldHideSecondTarget(): Boolean = entry.iconAction == null
+
+ override fun isSameItem(preference: Preference): Boolean =
+ preference is SafetySubpageEntryPreference &&
+ TextUtils.equals(entry.id, preference.entry.id)
+
+ override fun hasSameContents(preference: Preference): Boolean =
+ preference is SafetySubpageEntryPreference && entry == preference.entry
+
+ companion object {
+ private val TAG: String = SafetySubpageEntryPreference::class.java.simpleName
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SeverityIconPicker.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SeverityIconPicker.kt
new file mode 100644
index 000000000..752d7ed4a
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SeverityIconPicker.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui
+
+import android.safetycenter.SafetyCenterEntry
+import android.util.Log
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.safetycenter.SafetyCenterConstants.PRIVACY_SOURCES_GROUP_ID
+
+internal object SeverityIconPicker {
+
+ private val TAG = SeverityIconPicker::class.java.simpleName
+
+ @JvmStatic
+ fun selectIconResId(id: String, severityLevel: Int, severityUnspecifiedIconType: Int): Int {
+ if (id == PRIVACY_SOURCES_GROUP_ID) {
+ return R.drawable.ic_privacy
+ }
+
+ when (severityLevel) {
+ SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN -> return R.drawable.ic_safety_null_state
+ SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED ->
+ return selectSeverityUnspecifiedIconResId(severityUnspecifiedIconType)
+ SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK -> return R.drawable.ic_safety_info
+ SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION ->
+ return R.drawable.ic_safety_recommendation
+ SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING ->
+ return R.drawable.ic_safety_warn
+ }
+ Log.e(
+ TAG,
+ String.format("Unexpected SafetyCenterEntry.EntrySeverityLevel: %s", severityLevel)
+ )
+ return R.drawable.ic_safety_null_state
+ }
+
+ private fun selectSeverityUnspecifiedIconResId(severityUnspecifiedIconType: Int): Int {
+ when (severityUnspecifiedIconType) {
+ SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON ->
+ return R.drawable.ic_safety_empty
+ SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY -> return R.drawable.ic_privacy
+ SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION ->
+ return R.drawable.ic_safety_null_state
+ }
+ Log.e(
+ TAG,
+ String.format(
+ "Unexpected SafetyCenterEntry.SeverityNoneIconType: %s",
+ severityUnspecifiedIconType
+ )
+ )
+ return R.drawable.ic_safety_null_state
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SeverityLevel.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SeverityLevel.java
deleted file mode 100644
index 1edd83a47..000000000
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SeverityLevel.java
+++ /dev/null
@@ -1,63 +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.permissioncontroller.safetycenter.ui;
-
-import com.android.permissioncontroller.R;
-
-/** A severity level used for Safety Center entries and warnings. */
-enum SeverityLevel {
-
- SEVERITY_LEVEL_UNKNOWN(
- R.drawable.ic_safety_empty,
- R.drawable.ic_safety_empty
- ),
- NONE(
- R.drawable.ic_safety_null_state,
- R.drawable.ic_safety_null_state
- ),
- INFORMATION(
- R.drawable.ic_safety_info,
- R.drawable.ic_safety_info_outline
- ),
- RECOMMENDATION(
- R.drawable.ic_safety_recommendation,
- R.drawable.ic_safety_recommendation_outline
- ),
- CRITICAL_WARNING(
- R.drawable.ic_safety_warn,
- R.drawable.ic_safety_warn_outline
- );
-
- private final int mEntryIconResId;
- private final int mWarningCardIconResId;
-
- SeverityLevel(int entryIconResId, int warningCardIconResId) {
- mEntryIconResId = entryIconResId;
- mWarningCardIconResId = warningCardIconResId;
- }
-
- /** Returns the res id of the icon that should be used for a safety entry of this severity. */
- public int getEntryIconResId() {
- return mEntryIconResId;
- }
-
- /** Returns the res id of the icon that should be used for a warning card of this severity. */
- public int getWarningCardIconResId() {
- return mWarningCardIconResId;
- }
-
-}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SnakeCaseConverter.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SnakeCaseConverter.kt
new file mode 100644
index 000000000..4456bfa4d
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SnakeCaseConverter.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.safetycenter.ui
+
+/** Class used to convert a [String] to the `snake_case` format */
+internal object SnakeCaseConverter {
+
+ /** Converts a [String] from `camelCase` to `snake_case` */
+ fun fromCamelCase(input: String): String {
+ if (isFullyCapitalized(input)) {
+ return input.lowercase()
+ }
+
+ val camelRegex = "(?<=[a-zA-Z])[A-Z]".toRegex()
+ return camelRegex.replace(input) { "_${it.value}" }.lowercase()
+ }
+
+ private fun isFullyCapitalized(input: String): Boolean {
+ val uppercaseInput = input.uppercase()
+ if (input == uppercaseInput) {
+ return true
+ }
+ return false
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SpacerPreference.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SpacerPreference.kt
new file mode 100644
index 000000000..bb09783be
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SpacerPreference.kt
@@ -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.permissioncontroller.safetycenter.ui
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewTreeObserver
+import androidx.preference.Preference
+import androidx.preference.PreferenceScreen
+import androidx.preference.PreferenceViewHolder
+import com.android.permissioncontroller.R
+import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity
+import com.android.settingslib.widget.FooterPreference
+import kotlin.math.max
+
+/**
+ * A preference that adds an empty space to the bottom of a Safety Center subpage.
+ *
+ * Due to the logic of [CollapsingToolbarBaseActivity], its content won't be scrollable if it fits
+ * the single page. This logic conflicts with the UX of collapsible and expandable items of Safety
+ * Center, and with some other use cases (i.e. opening the page from Search might scroll to bottom
+ * while the scroll is disabled). In such cases user won't be able to expand the collapsed toolbar
+ * by scrolling the screen content.
+ *
+ * [SpacerPreference] makes the page to be slightly bigger than the screen size to unlock the scroll
+ * regardless of the content length and to mitigate this UX problem.
+ *
+ * If a [FooterPreference] is added to the same [PreferenceScreen], its order should be decreased to
+ * keep it with the last visible content above the [SpacerPreference].
+ */
+internal class SpacerPreference(context: Context, attrs: AttributeSet) :
+ Preference(context, attrs) {
+
+ init {
+ setLayoutResource(R.layout.preference_spacer)
+ isVisible = SafetyCenterUiFlags.getShowSubpages()
+ // spacer should be the last item on screen
+ setOrder(Int.MAX_VALUE - 1)
+ }
+
+ private var maxKnownToolbarHeight = 0
+ override fun onBindViewHolder(holder: PreferenceViewHolder) {
+ super.onBindViewHolder(holder)
+ val spacer = holder.itemView
+
+ // 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 }
+
+ spacer.removeOnLayoutChangeListener(listener)
+ spacer.addOnLayoutChangeListener(listener)
+ }
+
+ private fun adjustHeight(spacer: View) {
+ val root = spacer.rootView as? ViewGroup
+ if (root == null) {
+ return
+ }
+
+ val contentParent = root.findViewById<ViewGroup>(R.id.content_parent)
+ if (contentParent == null) {
+ return
+ }
+ // when opening the Subpage from Search the layout pass may be triggered
+ // 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)
+ }
+ }
+ contentParent.viewTreeObserver.addOnGlobalLayoutListener(globalLayoutObserver)
+ return
+ }
+
+ val collapsingToolbar = root.findViewById<View>(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 layoutParams = spacer.layoutParams
+ if (layoutParams.height != desiredSpacerHeight) {
+ layoutParams.height = desiredSpacerHeight
+ spacer.layoutParams = layoutParams
+ // need to let RecyclerView to update scroll position
+ spacer.post(::notifyChanged)
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/StaticSafetyEntryPreference.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/StaticSafetyEntryPreference.java
index 6b076ffaa..8864da07b 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/StaticSafetyEntryPreference.java
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/StaticSafetyEntryPreference.java
@@ -16,33 +16,93 @@
package com.android.permissioncontroller.safetycenter.ui;
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import static com.android.permissioncontroller.safetycenter.SafetyCenterConstants.PERSONAL_PROFILE_SUFFIX;
+import static com.android.permissioncontroller.safetycenter.SafetyCenterConstants.WORK_PROFILE_SUFFIX;
+
import android.content.Context;
+import android.os.UserManager;
import android.safetycenter.SafetyCenterStaticEntry;
+import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import androidx.preference.Preference;
+import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterViewModel;
+import com.android.safetycenter.internaldata.SafetyCenterEntryId;
+
/** A preference which displays a visual representation of a {@link SafetyCenterStaticEntry}. */
-public class StaticSafetyEntryPreference extends Preference {
+@RequiresApi(TIRAMISU)
+public class StaticSafetyEntryPreference extends Preference implements ComparablePreference {
private static final String TAG = StaticSafetyEntryPreference.class.getSimpleName();
- public StaticSafetyEntryPreference(Context context, SafetyCenterStaticEntry entry) {
+ private final SafetyCenterStaticEntry mEntry;
+ private final SafetyCenterViewModel mViewModel;
+
+ public StaticSafetyEntryPreference(
+ Context context,
+ @Nullable Integer launchTaskId,
+ SafetyCenterStaticEntry entry,
+ @Nullable SafetyCenterEntryId entryId,
+ SafetyCenterViewModel viewModel) {
super(context);
+ mEntry = entry;
+ mViewModel = viewModel;
setTitle(entry.getTitle());
setSummary(entry.getSummary());
if (entry.getPendingIntent() != null) {
- setOnPreferenceClickListener(unused -> {
- try {
- entry.getPendingIntent().send();
- } catch (Exception ex) {
- Log.e(TAG,
- String.format(
- "Failed to execute pending intent for static entry: %s", entry),
- ex);
- }
- return true;
- });
+ setOnPreferenceClickListener(
+ unused -> {
+ try {
+ PendingIntentSender.send(mEntry.getPendingIntent(), launchTaskId);
+ } catch (Exception ex) {
+ Log.e(
+ TAG,
+ String.format(
+ "Failed to execute pending intent for static entry: %s",
+ mEntry),
+ ex);
+ }
+
+ // SafetyCenterStaticEntry does not expose an ID, so we're unable to log
+ // what source this static entry belonged to.
+ mViewModel.getInteractionLogger().record(Action.STATIC_ENTRY_CLICKED);
+
+ return true;
+ });
+ }
+ if (entryId != null) {
+ setupPreferenceKey(entryId);
}
}
+
+ private void setupPreferenceKey(SafetyCenterEntryId entryId) {
+ boolean isWorkProfile =
+ getContext()
+ .getSystemService(UserManager.class)
+ .isManagedProfile(entryId.getUserId());
+ if (isWorkProfile) {
+ setKey(String.format("%s_%s", entryId.getSafetySourceId(), WORK_PROFILE_SUFFIX));
+ } else {
+ setKey(String.format("%s_%s", entryId.getSafetySourceId(), PERSONAL_PROFILE_SUFFIX));
+ }
+ }
+
+ @Override
+ public boolean isSameItem(Preference preference) {
+ return preference instanceof StaticSafetyEntryPreference
+ && TextUtils.equals(
+ mEntry.getTitle(),
+ ((StaticSafetyEntryPreference) preference).mEntry.getTitle());
+ }
+
+ @Override
+ public boolean hasSameContents(Preference preference) {
+ return preference instanceof StaticSafetyEntryPreference
+ && mEntry.equals(((StaticSafetyEntryPreference) preference).mEntry);
+ }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/StatusAnimationResolver.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/StatusAnimationResolver.kt
new file mode 100644
index 000000000..55288564c
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/StatusAnimationResolver.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 com.android.permissioncontroller.safetycenter.ui
+
+import android.os.Build
+import android.safetycenter.SafetyCenterStatus
+import android.util.Log
+import androidx.annotation.RequiresApi
+import com.android.permissioncontroller.R
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+object StatusAnimationResolver {
+
+ private val LOG_TAG = StatusAnimationResolver::class.java.simpleName
+
+ @JvmStatic
+ fun getScanningStartAnimation(severityLevel: Int): Int {
+ return when (severityLevel) {
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN,
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK -> R.drawable.status_info_to_scanning_anim
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION ->
+ R.drawable.status_recommend_to_scanning_anim
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING ->
+ R.drawable.status_warn_to_scanning_anim
+ else -> {
+ Log.w(LOG_TAG, String.format("Unexpected severity level: %s", severityLevel))
+ R.drawable.status_info_to_scanning_anim
+ }
+ }
+ }
+
+ @JvmStatic
+ fun getScanningAnimation(severityLevel: Int): Int {
+ return when (severityLevel) {
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN,
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK -> R.drawable.status_scanning_anim_info
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION ->
+ R.drawable.status_scanning_anim_recommend
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING ->
+ R.drawable.status_scanning_anim_warn
+ else -> {
+ Log.w(LOG_TAG, String.format("Unexpected severity level: %s", severityLevel))
+ R.drawable.status_scanning_anim_info
+ }
+ }
+ }
+
+ @JvmStatic
+ fun getScanningEndAnimation(fromSeverityLevel: Int, toSeverityLevel: Int): Int {
+ return when (fromSeverityLevel) {
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN,
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK ->
+ getTransitionAnimationFromInfo(toSeverityLevel)
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING ->
+ getTransitionAnimationFromWarn(toSeverityLevel)
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION ->
+ getTransitionAnimationFromRecommend(toSeverityLevel)
+ else -> {
+ Log.w(LOG_TAG, String.format("Unexpected severity level: %s", fromSeverityLevel))
+ getTransitionAnimationFromInfo(toSeverityLevel)
+ }
+ }
+ }
+
+ @JvmStatic
+ private fun getTransitionAnimationFromInfo(toSeverityLevel: Int): Int {
+ return when (toSeverityLevel) {
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN,
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK ->
+ R.drawable.status_scanning_end_anim_info_to_info
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING ->
+ R.drawable.status_scanning_end_anim_info_to_warn
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION ->
+ R.drawable.status_scanning_end_anim_info_to_recommend
+ else -> {
+ Log.w(LOG_TAG, String.format("Unexpected severity level: %s", toSeverityLevel))
+ R.drawable.status_scanning_end_anim_info_to_info
+ }
+ }
+ }
+
+ @JvmStatic
+ private fun getTransitionAnimationFromRecommend(toSeverityLevel: Int): Int {
+ return when (toSeverityLevel) {
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN,
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK ->
+ R.drawable.status_scanning_end_anim_recommend_to_info
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING ->
+ R.drawable.status_scanning_end_anim_recommend_to_warn
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION ->
+ R.drawable.status_scanning_end_anim_recommend_to_recommend
+ else -> {
+ Log.w(LOG_TAG, String.format("Unexpected severity level: %s", toSeverityLevel))
+ R.drawable.status_scanning_end_anim_recommend_to_recommend
+ }
+ }
+ }
+
+ @JvmStatic
+ private fun getTransitionAnimationFromWarn(toSeverityLevel: Int): Int {
+ return when (toSeverityLevel) {
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN,
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK ->
+ R.drawable.status_scanning_end_anim_warn_to_info
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION ->
+ R.drawable.status_scanning_end_anim_warn_to_recommend
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING ->
+ R.drawable.status_scanning_end_anim_warn_to_warn
+ else -> {
+ Log.w(LOG_TAG, String.format("Unexpected severity level: %s", toSeverityLevel))
+ R.drawable.status_scanning_end_anim_warn_to_warn
+ }
+ }
+ }
+
+ @JvmStatic
+ fun getStatusChangeAnimation(fromSeverity: Int, toSeverity: Int): Int =
+ 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 -> 0
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/TextFadeAnimator.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/TextFadeAnimator.kt
new file mode 100644
index 000000000..a98fcf2ad
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/TextFadeAnimator.kt
@@ -0,0 +1,124 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui
+
+import android.transition.AutoTransition
+import android.transition.Transition
+import android.transition.TransitionListenerAdapter
+import android.transition.TransitionManager
+import android.transition.TransitionSet
+import android.view.View
+import android.view.ViewGroup
+import android.view.animation.LinearInterpolator
+import android.widget.TextView
+import java.time.Duration
+
+/**
+ * An animator which can animate a fade in/fade out of either one textView, or several textViews
+ * that are in the same ViewGroup.
+ */
+class TextFadeAnimator
+@JvmOverloads
+constructor(targetIds: List<Int>, changeDuration: Duration = DEFAULT_TEXT_CHANGE_DURATION) {
+
+ @JvmOverloads
+ constructor(
+ targetId: Int,
+ changeDuration: Duration = DEFAULT_TEXT_CHANGE_DURATION
+ ) : this(listOf(targetId), changeDuration)
+
+ private val textChangeTransition: TransitionSet
+ init {
+ var transition =
+ AutoTransition()
+ .setInterpolator(linearInterpolator)
+ .setDuration(changeDuration.toMillis())
+ for (targetId in targetIds) {
+ transition = transition.addTarget(targetId)
+ }
+ textChangeTransition = transition
+ }
+
+ @JvmOverloads
+ fun animateChangeText(textView: TextView, text: String, onFinish: Runnable? = null) {
+ animateChangeText(listOf(textView to text), onFinish)
+ }
+
+ /** Animate changes for a set of textViews under the same parent. */
+ @JvmOverloads
+ fun animateChangeText(textChanges: List<Pair<TextView, String>>, onFinish: Runnable? = null) {
+ if (textChanges.isEmpty()) {
+ return
+ }
+ val firstView = textChanges[0].first
+ val parentViewGroup: ViewGroup = firstView.parent as ViewGroup
+ val fadeOutTransition =
+ textChangeTransition
+ .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)
+ for ((textView, _) in textChanges) {
+ textView.visibility = View.INVISIBLE
+ }
+ }
+ }
+
+ private fun fadeTextIn(
+ textChanges: List<Pair<TextView, String>>,
+ parent: ViewGroup,
+ onFinish: Runnable?
+ ) {
+ val fadeInTransition =
+ textChangeTransition
+ .clone()
+ .addListener(
+ object : TransitionListenerAdapter() {
+ override fun onTransitionEnd(transition: Transition?) {
+ super.onTransitionEnd(transition)
+ onFinish?.run()
+ }
+ })
+
+ parent.post {
+ TransitionManager.beginDelayedTransition(parent, fadeInTransition)
+ for ((textView, text) in textChanges) {
+ textView.text = text
+ textView.visibility = View.VISIBLE
+ }
+ }
+ }
+
+ fun cancelTextChangeAnimation(textView: TextView) {
+ TransitionManager.endTransitions(textView.parent as ViewGroup)
+ }
+
+ companion object {
+ // 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/LiveSafetyCenterViewModel.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt
new file mode 100644
index 000000000..4ddcf1c3d
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt
@@ -0,0 +1,316 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui.model
+
+import android.app.Application
+import android.content.Context
+import android.content.Intent
+import android.content.Intent.ACTION_SAFETY_CENTER
+import android.os.Build
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import android.safetycenter.SafetyCenterData
+import android.safetycenter.SafetyCenterErrorDetails
+import android.safetycenter.SafetyCenterIssue
+import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetyCenterStatus
+import android.util.Log
+import androidx.annotation.MainThread
+import androidx.annotation.RequiresApi
+import androidx.core.content.ContextCompat.getMainExecutor
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.map
+import com.android.modules.utils.build.SdkLevel
+import com.android.permissioncontroller.safetycenter.ui.InteractionLogger
+import com.android.permissioncontroller.safetycenter.ui.NavigationSource
+import com.android.safetycenter.internaldata.SafetyCenterIds
+
+/* A SafetyCenterViewModel that talks to the real backing service for Safety Center. */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class LiveSafetyCenterViewModel(app: Application) : SafetyCenterViewModel(app) {
+
+ private val TAG: String = LiveSafetyCenterViewModel::class.java.simpleName
+ override val statusUiLiveData: LiveData<StatusUiData>
+ get() = safetyCenterUiLiveData.map { StatusUiData(it.safetyCenterData) }
+ override val safetyCenterUiLiveData: LiveData<SafetyCenterUiData> by this::_safetyCenterLiveData
+ override val errorLiveData: LiveData<SafetyCenterErrorDetails> by this::_errorLiveData
+
+ private val _safetyCenterLiveData = SafetyCenterLiveData()
+ private val _errorLiveData = MutableLiveData<SafetyCenterErrorDetails>()
+
+ override val interactionLogger: InteractionLogger by lazy {
+ // Fetching the config to build this set of source IDs requires IPC, so we do this
+ // initialization lazily.
+ InteractionLogger(safetyCenterManager.safetyCenterConfig)
+ }
+
+ private var changingConfigurations = false
+
+ private val safetyCenterManager = app.getSystemService(SafetyCenterManager::class.java)!!
+
+ override fun getCurrentSafetyCenterDataAsUiData(): SafetyCenterUiData =
+ SafetyCenterUiData(safetyCenterManager.safetyCenterData)
+
+ override fun dismissIssue(issue: SafetyCenterIssue) {
+ safetyCenterManager.dismissSafetyCenterIssue(issue.id)
+ }
+
+ override fun executeIssueAction(
+ issue: SafetyCenterIssue,
+ action: SafetyCenterIssue.Action,
+ launchTaskId: Int?
+ ) {
+ val issueId =
+ if (launchTaskId != null) {
+ SafetyCenterIds.encodeToString(
+ SafetyCenterIds.issueIdFromString(issue.id)
+ .toBuilder()
+ .setTaskId(launchTaskId)
+ .build()
+ )
+ } else {
+ issue.id
+ }
+ safetyCenterManager.executeSafetyCenterIssueAction(issueId, action.id)
+ }
+
+ override fun markIssueResolvedUiCompleted(issueId: IssueId) {
+ _safetyCenterLiveData.markIssueResolvedUiCompleted(issueId)
+ }
+
+ override fun rescan() {
+ safetyCenterManager.refreshSafetySources(
+ SafetyCenterManager.REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+ }
+
+ override fun clearError() {
+ _errorLiveData.value = null
+ }
+
+ override fun navigateToSafetyCenter(context: Context, navigationSource: NavigationSource?) {
+ val intent = Intent(ACTION_SAFETY_CENTER)
+
+ if (navigationSource != null) {
+ navigationSource.addToIntent(intent)
+ }
+
+ context.startActivity(intent)
+ }
+
+ override fun pageOpen() {
+ executeIfNotChangingConfigurations {
+ safetyCenterManager.refreshSafetySources(SafetyCenterManager.REFRESH_REASON_PAGE_OPEN)
+ }
+ }
+
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ override fun pageOpen(sourceGroupId: String) {
+ executeIfNotChangingConfigurations {
+ val safetySourceIds = getSafetySourceIdsToRefresh(sourceGroupId)
+ if (safetySourceIds == null) {
+ Log.w(TAG, "$sourceGroupId has no matching source IDs, so refreshing all sources")
+ safetyCenterManager.refreshSafetySources(
+ SafetyCenterManager.REFRESH_REASON_PAGE_OPEN
+ )
+ } else {
+ safetyCenterManager.refreshSafetySources(
+ SafetyCenterManager.REFRESH_REASON_PAGE_OPEN,
+ safetySourceIds
+ )
+ }
+ }
+ }
+
+ override fun changingConfigurations() {
+ changingConfigurations = true
+ }
+
+ private fun executeIfNotChangingConfigurations(block: () -> Unit) {
+ if (changingConfigurations) {
+ // Don't refresh when changing configurations, but reset for the next pageOpen call
+ changingConfigurations = false
+ return
+ }
+
+ block()
+ }
+
+ private fun getSafetySourceIdsToRefresh(sourceGroupId: String): List<String>? {
+ val safetySourcesGroup =
+ safetyCenterManager.safetyCenterConfig?.safetySourcesGroups?.find {
+ it.id == sourceGroupId
+ }
+ return safetySourcesGroup?.safetySources?.map { it.id }
+ }
+
+ private inner class SafetyCenterLiveData :
+ MutableLiveData<SafetyCenterUiData>(),
+ SafetyCenterManager.OnSafetyCenterDataChangedListener {
+
+ // Managing the data queue isn't designed to support multithreading. Any methods that
+ // manipulate it, or the inFlight or resolved issues lists should only be called on the
+ // main thread, and are marked accordingly.
+ private val safetyCenterDataQueue = ArrayDeque<SafetyCenterData>()
+ private var issuesPendingResolution = mapOf<IssueId, ActionId>()
+ private val currentResolvedIssues = mutableMapOf<IssueId, ActionId>()
+
+ override fun onActive() {
+ safetyCenterManager.addOnSafetyCenterDataChangedListener(
+ getMainExecutor(app.applicationContext),
+ this
+ )
+ super.onActive()
+ }
+
+ override fun onInactive() {
+ safetyCenterManager.removeOnSafetyCenterDataChangedListener(this)
+
+ if (!changingConfigurations) {
+ // Remove all the tracked state and start from scratch when active again.
+ issuesPendingResolution = mapOf()
+ currentResolvedIssues.clear()
+ safetyCenterDataQueue.clear()
+ }
+ super.onInactive()
+ }
+
+ @MainThread
+ override fun onSafetyCenterDataChanged(data: SafetyCenterData) {
+ safetyCenterDataQueue.addLast(data)
+ maybeProcessDataToNextResolvedIssues()
+ }
+
+ override fun onError(errorDetails: SafetyCenterErrorDetails) {
+ _errorLiveData.value = errorDetails
+ }
+
+ @MainThread
+ private fun maybeProcessDataToNextResolvedIssues() {
+ // Only process data updates while we aren't waiting for issue resolution animations
+ // to complete.
+ if (currentResolvedIssues.isNotEmpty()) {
+ Log.d(
+ TAG,
+ "Received SafetyCenterData while issue resolution animations" +
+ " occurring. Will update UI with new data soon."
+ )
+ return
+ }
+
+ while (safetyCenterDataQueue.isNotEmpty() && currentResolvedIssues.isEmpty()) {
+ val nextData = safetyCenterDataQueue.first()
+
+ // Calculate newly resolved issues by diffing the tracked in-flight issues and the
+ // current update. Resolved issues are formerly in-flight issues that no longer
+ // appear in a subsequent SafetyCenterData update.
+ val nextResolvedIssues: Map<IssueId, ActionId> =
+ determineResolvedIssues(nextData.buildIssueIdSet())
+
+ // Save the set of in-flight issues to diff against the next data update, removing
+ // the now-resolved, formerly in-flight issues. If these are not tracked separately
+ // the queue will not progress once the issue resolution animations complete.
+ issuesPendingResolution = nextData.getInFlightIssues()
+
+ if (nextResolvedIssues.isNotEmpty()) {
+ currentResolvedIssues.putAll(nextResolvedIssues)
+ sendResolvedIssuesAndCurrentData()
+ } else if (shouldEndScan(nextData) || shouldSendLastDataInQueue()) {
+ sendNextData()
+ } else {
+ skipNextData()
+ }
+ }
+ }
+
+ private fun determineResolvedIssues(nextIssueIds: Set<IssueId>): Map<IssueId, ActionId> {
+ // Any previously in-flight issue that does not appear in the incoming SafetyCenterData
+ // is considered resolved.
+ return issuesPendingResolution.filterNot { issue -> nextIssueIds.contains(issue.key) }
+ }
+
+ private fun shouldEndScan(nextData: SafetyCenterData): Boolean =
+ isCurrentlyScanning() && !nextData.isScanning()
+
+ private fun shouldSendLastDataInQueue(): Boolean =
+ !isCurrentlyScanning() && safetyCenterDataQueue.size == 1
+
+ private fun isCurrentlyScanning(): Boolean = value?.safetyCenterData?.isScanning() ?: false
+
+ private fun sendNextData() {
+ value = SafetyCenterUiData(safetyCenterDataQueue.removeFirst())
+ }
+
+ private fun skipNextData() = safetyCenterDataQueue.removeFirst()
+
+ private fun sendResolvedIssuesAndCurrentData() {
+ val currentData = value?.safetyCenterData
+ if (currentData == null || currentResolvedIssues.isEmpty()) {
+ // There can only be resolved issues after receiving data with in-flight issues,
+ // so we should always have already sent data here.
+ throw IllegalArgumentException("No current data or no resolved issues")
+ }
+
+ // The current SafetyCenterData still contains the resolved SafetyCenterIssue objects.
+ // Send it with the resolved IDs so the UI can generate the correct preferences and
+ // trigger the right animations for issue resolution.
+ value = SafetyCenterUiData(currentData, currentResolvedIssues)
+ }
+
+ @MainThread
+ fun markIssueResolvedUiCompleted(issueId: IssueId) {
+ currentResolvedIssues.remove(issueId)
+ maybeProcessDataToNextResolvedIssues()
+ }
+ }
+}
+
+/** Returns inflight issues pending resolution */
+private fun SafetyCenterData.getInFlightIssues(): Map<IssueId, ActionId> =
+ allResolvableIssues
+ .map { issue ->
+ issue.actions
+ // UX requirements require skipping resolution UI for issues that do not have a
+ // valid successMessage
+ .filter { it.isInFlight && !it.successMessage.isNullOrEmpty() }
+ .map { issue.id to it.id }
+ }
+ .flatten()
+ .toMap()
+
+private fun SafetyCenterData.isScanning() =
+ status.refreshStatus == SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS
+
+private fun SafetyCenterData.buildIssueIdSet(): Set<IssueId> =
+ allResolvableIssues.map { it.id }.toSet()
+
+private val SafetyCenterData.allResolvableIssues: Sequence<SafetyCenterIssue>
+ get() =
+ if (SdkLevel.isAtLeastU()) {
+ issues.asSequence() + dismissedIssues.asSequence()
+ } else {
+ issues.asSequence()
+ }
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class LiveSafetyCenterViewModelFactory(private val app: Application) : ViewModelProvider.Factory {
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ @Suppress("UNCHECKED_CAST") return LiveSafetyCenterViewModel(app) as T
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/PrivacyControlsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/PrivacyControlsViewModel.kt
new file mode 100644
index 000000000..2f5702321
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/PrivacyControlsViewModel.kt
@@ -0,0 +1,217 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui.model
+
+import android.app.Application
+import android.content.Intent
+import android.hardware.SensorPrivacyManager
+import android.hardware.SensorPrivacyManager.Sensors
+import android.hardware.SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE
+import android.os.Build
+import android.os.Process
+import android.os.UserManager
+import android.provider.DeviceConfig
+import android.provider.Settings
+import androidx.annotation.RequiresApi
+import androidx.annotation.StringRes
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData
+import com.android.settingslib.RestrictedLockUtils
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
+
+/** Viewmodel for the privacy controls page. */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class PrivacyControlsViewModel(private val app: Application) : AndroidViewModel(app) {
+
+ private val sensorPrivacyManager: SensorPrivacyManager =
+ app.getSystemService(SensorPrivacyManager::class.java)!!
+ private val userManager: UserManager = app.getSystemService(UserManager::class.java)!!
+
+ private val CONFIG_CLIPBOARD_SHOW_ACCESS_NOTIFICATIONS =
+ app.getString(R.string.clipboard_show_access_notifications_config)
+ private val CONFIG_SHOW_ACCESS_NOTIFICATIONS_DEFAULT =
+ app.getString(R.string.show_access_notifications_default_config)
+ private val CONFIG_MIC_TOGGLE_ENABLED = app.getString(R.string.mic_toggle_enable_config)
+ private val CONFIG_CAMERA_TOGGLE_ENABLED = app.getString(R.string.camera_toggle_enable_config)
+
+ enum class Pref(val key: String, @StringRes val titleResId: Int) {
+ MIC("privacy_mic_toggle", R.string.mic_toggle_title),
+ CAMERA("privacy_camera_toggle", R.string.camera_toggle_title),
+ LOCATION("privacy_location_access", R.string.location_settings),
+ CLIPBOARD("show_clip_access_notification", R.string.show_clip_access_notification_title),
+ SHOW_PASSWORD("show_password", R.string.show_password_title);
+
+ companion object {
+ @JvmStatic fun findByKey(inputKey: String) = values().find { it.key == inputKey }
+ }
+ }
+
+ data class PrefState(val visible: Boolean, val checked: Boolean, val admin: EnforcedAdmin?)
+
+ val controlStateLiveData: SmartUpdateMediatorLiveData<Map<Pref, PrefState>> =
+ object :
+ SmartUpdateMediatorLiveData<@JvmSuppressWildcards Map<Pref, PrefState>>(),
+ SensorPrivacyManager.OnSensorPrivacyChangedListener {
+
+ override fun onUpdate() {
+ val shownPrefs = mutableMapOf<Pref, PrefState>()
+ shownPrefs[Pref.CAMERA] =
+ getSensorToggleState(
+ Sensors.CAMERA,
+ UserManager.DISALLOW_CAMERA_TOGGLE,
+ CONFIG_CAMERA_TOGGLE_ENABLED
+ )
+ shownPrefs[Pref.MIC] =
+ getSensorToggleState(
+ Sensors.MICROPHONE,
+ UserManager.DISALLOW_MICROPHONE_TOGGLE,
+ CONFIG_MIC_TOGGLE_ENABLED
+ )
+ shownPrefs[Pref.CLIPBOARD] =
+ PrefState(visible = true, checked = isClipboardEnabled(), admin = null)
+ shownPrefs[Pref.SHOW_PASSWORD] =
+ PrefState(
+ visible = shouldDisplayShowPasswordToggle(),
+ checked = isShowPasswordEnabled(),
+ admin = null
+ )
+ value = shownPrefs
+ }
+
+ override fun onActive() {
+ sensorPrivacyManager.addSensorPrivacyListener(this)
+ super.onActive()
+ update()
+ }
+
+ override fun onInactive() {
+ super.onInactive()
+ sensorPrivacyManager.removeSensorPrivacyListener(this)
+ }
+
+ @Suppress("OVERRIDE_DEPRECATION")
+ override fun onSensorPrivacyChanged(sensor: Int, enabled: Boolean) {
+ update()
+ }
+ }
+
+ fun handlePrefClick(fragment: Fragment, pref: Pref, admin: EnforcedAdmin?) {
+ when (pref) {
+ Pref.MIC -> toggleSensorOrShowAdmin(fragment, Sensors.MICROPHONE, admin)
+ Pref.CAMERA -> toggleSensorOrShowAdmin(fragment, Sensors.CAMERA, admin)
+ Pref.LOCATION -> goToLocation(fragment)
+ Pref.CLIPBOARD -> toggleClipboard()
+ Pref.SHOW_PASSWORD -> toggleShowPassword()
+ }
+ }
+
+ private fun toggleSensorOrShowAdmin(fragment: Fragment, sensor: Int, admin: EnforcedAdmin?) {
+ if (admin != null) {
+ RestrictedLockUtils.sendShowAdminSupportDetailsIntent(fragment.context, admin)
+ return
+ }
+ val blocked = sensorPrivacyManager.isSensorPrivacyEnabled(TOGGLE_TYPE_SOFTWARE, sensor)
+ sensorPrivacyManager.setSensorPrivacy(sensor, !blocked)
+ }
+
+ private fun goToLocation(fragment: Fragment) {
+ fragment.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
+ }
+
+ private fun getSensorToggleState(
+ sensor: Int,
+ restriction: String,
+ enableConfig: String
+ ): PrefState {
+ val admin = RestrictedLockUtils.getProfileOrDeviceOwner(app, Process.myUserHandle())
+ val sensorConfigEnabled =
+ DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, enableConfig, true)
+ return PrefState(
+ visible = sensorConfigEnabled && sensorPrivacyManager.supportsSensorToggle(sensor),
+ checked = !sensorPrivacyManager.isSensorPrivacyEnabled(TOGGLE_TYPE_SOFTWARE, sensor),
+ admin =
+ if (
+ userManager
+ .getUserRestrictionSources(restriction, Process.myUserHandle())
+ .isNotEmpty()
+ ) {
+ admin
+ } else {
+ null
+ }
+ )
+ }
+
+ private fun isClipboardEnabled(): Boolean {
+ val clipboardDefaultEnabled =
+ DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_CLIPBOARD,
+ CONFIG_SHOW_ACCESS_NOTIFICATIONS_DEFAULT,
+ true
+ )
+ val defaultSetting = if (clipboardDefaultEnabled) 1 else 0
+ return Settings.Secure.getInt(
+ app.contentResolver,
+ CONFIG_CLIPBOARD_SHOW_ACCESS_NOTIFICATIONS,
+ defaultSetting
+ ) != 0
+ }
+
+ private fun toggleClipboard() {
+ val newState = if (isClipboardEnabled()) 0 else 1
+ Settings.Secure.putInt(
+ app.contentResolver,
+ CONFIG_CLIPBOARD_SHOW_ACCESS_NOTIFICATIONS,
+ newState
+ )
+ }
+
+ private fun isShowPasswordEnabled(): Boolean {
+ return Settings.System.getInt(app.contentResolver, Settings.System.TEXT_SHOW_PASSWORD, 1) !=
+ 0
+ }
+
+ private fun toggleShowPassword() {
+ Settings.System.putInt(
+ app.contentResolver,
+ Settings.System.TEXT_SHOW_PASSWORD,
+ if (isShowPasswordEnabled()) 0 else 1
+ )
+ }
+
+ private fun shouldDisplayShowPasswordToggle(): Boolean {
+ return app.resources.getBoolean(R.bool.config_display_show_password_toggle)
+ }
+}
+
+/**
+ * Factory for a PrivacyControlsViewModel
+ *
+ * @param app The current application
+ */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+class PrivacyControlsViewModelFactory(
+ private val app: Application,
+) : ViewModelProvider.Factory {
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ @Suppress("UNCHECKED_CAST") return PrivacyControlsViewModel(app) as T
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v33/SafetyCenterQsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterQsViewModel.kt
index a5f5c5b08..73c7da99f 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v33/SafetyCenterQsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterQsViewModel.kt
@@ -15,7 +15,7 @@
*/
@file:Suppress("DEPRECATION")
-package com.android.permissioncontroller.permission.ui.model.v33
+package com.android.permissioncontroller.safetycenter.ui.model
import android.Manifest.permission_group.CAMERA
import android.Manifest.permission_group.LOCATION
@@ -28,22 +28,28 @@ import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.hardware.SensorPrivacyManager
import android.hardware.SensorPrivacyManager.Sensors
+import android.hardware.SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE
import android.location.LocationManager
import android.os.Build
import android.os.Process
import android.os.UserHandle
+import android.os.UserManager
import android.permission.PermissionGroupUsage
+import android.provider.DeviceConfig
import android.provider.Settings
import androidx.annotation.RequiresApi
import androidx.fragment.app.Fragment
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
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.model.livedatatypes.LightAppPermGroup
import com.android.permissioncontroller.permission.utils.KotlinUtils
import com.android.permissioncontroller.permission.utils.LocationUtils
+import com.android.settingslib.RestrictedLockUtils
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
import kotlin.collections.set
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@@ -52,63 +58,80 @@ class SafetyCenterQsViewModel(
private val sessionId: Long,
private val permGroupUsages: List<PermissionGroupUsage>
) : AndroidViewModel(app) {
+ private val configMicToggleEnabled = app.getString(R.string.mic_toggle_enable_config)
+ private val configCameraToggleEnabled = app.getString(R.string.camera_toggle_enable_config)
private val sensorPrivacyManager: SensorPrivacyManager =
app.getSystemService(SensorPrivacyManager::class.java)!!
private val locationManager: LocationManager =
app.getSystemService(LocationManager::class.java)!!
+ private val userManager: UserManager = app.getSystemService(UserManager::class.java)!!
- val lightAppPermMap = mutableMapOf<Triple<String, String, UserHandle>, LightAppPermGroup?>()
+ val lightAppPermMap = mutableMapOf<LightAppPermissionGroupUsageKey, LightAppPermGroup?>()
+ val revokedUsages = mutableSetOf<PermissionGroupUsage>()
- val permDataLoadedLiveData = object
- : SmartUpdateMediatorLiveData<Boolean>() {
+ val permDataLoadedLiveData =
+ object : SmartUpdateMediatorLiveData<Boolean>() {
- private val lightAppPermLiveDatas = mutableMapOf<Triple<String, String, UserHandle>,
- LightAppPermGroupLiveData>()
+ private val lightAppPermLiveDatas =
+ mutableMapOf<LightAppPermissionGroupUsageKey, LightAppPermGroupLiveData>()
- init {
- for (permGroupUsage in permGroupUsages) {
- val pgTriple = Triple(permGroupUsage.packageName,
- permGroupUsage.permissionGroupName,
- UserHandle.getUserHandleForUid(permGroupUsage.uid))
- val appPermGroupLiveData = LightAppPermGroupLiveData[pgTriple]
- lightAppPermLiveDatas[pgTriple] = appPermGroupLiveData
- addSource(appPermGroupLiveData) {
- update()
+ init {
+ for (permGroupUsage in permGroupUsages) {
+ val packageName = permGroupUsage.packageName
+ val permissionGroupName = permGroupUsage.permissionGroupName
+ val userHandle = UserHandle.getUserHandleForUid(permGroupUsage.uid)
+ val lightAppPermissionGroupUsageKey =
+ LightAppPermissionGroupUsageKey(
+ packageName, permissionGroupName, userHandle)
+ val appPermGroupLiveData: LightAppPermGroupLiveData =
+ LightAppPermGroupLiveData[
+ Triple(packageName, permissionGroupName, userHandle)]
+ lightAppPermLiveDatas[lightAppPermissionGroupUsageKey] = appPermGroupLiveData
+ addSource(appPermGroupLiveData) { update() }
}
}
- }
- override fun onUpdate() {
- if (!lightAppPermLiveDatas.all { it.value.isInitialized }) {
- return
- }
- for ((pgTriple, lightAppPermLiveData) in lightAppPermLiveDatas) {
- lightAppPermMap[pgTriple] = lightAppPermLiveData.value
+ override fun onUpdate() {
+ if (!lightAppPermLiveDatas.all { it.value.isInitialized }) {
+ return
+ }
+ for ((lightAppPermissionGroupUsageKey, lightAppPermLiveData) in
+ lightAppPermLiveDatas) {
+ lightAppPermMap[lightAppPermissionGroupUsageKey] = lightAppPermLiveData.value
+ }
+ value = true
}
- value = true
}
- }
fun shouldAllowRevoke(usage: PermissionGroupUsage): Boolean {
- val pgTriple = Triple(usage.packageName,
- usage.permissionGroupName,
- UserHandle.getUserHandleForUid(usage.uid))
- val group = lightAppPermMap[pgTriple] ?: return false
+ val group =
+ lightAppPermMap[
+ LightAppPermissionGroupUsageKey(
+ usage.packageName,
+ usage.permissionGroupName,
+ UserHandle.getUserHandleForUid(usage.uid))]
+ ?: return false
return group.supportsRuntimePerms &&
- !group.hasInstallToRuntimeSplit &&
- !group.isBackgroundFixed &&
- !group.isForegroundFixed &&
- !group.isGrantedByDefault
+ !group.hasInstallToRuntimeSplit &&
+ !group.isBackgroundFixed &&
+ !group.isForegroundFixed &&
+ !group.isGrantedByDefault
}
fun revokePermission(usage: PermissionGroupUsage) {
- val group = lightAppPermMap.get(Triple(usage.packageName, usage.permissionGroupName,
- UserHandle.getUserHandleForUid(usage.uid))) ?: return
+ val group =
+ lightAppPermMap[
+ LightAppPermissionGroupUsageKey(
+ usage.packageName,
+ usage.permissionGroupName,
+ UserHandle.getUserHandleForUid(usage.uid))]
+ ?: return
KotlinUtils.revokeForegroundRuntimePermissions(app, group)
KotlinUtils.revokeBackgroundRuntimePermissions(app, group)
+ revokedUsages.add(usage)
}
fun toggleSensor(groupName: String) {
@@ -135,16 +158,32 @@ class SafetyCenterQsViewModel(
fragment.startActivity(Intent(Settings.ACTION_SECURITY_SETTINGS))
}
- val sensorPrivacyLiveData: SmartUpdateMediatorLiveData<Map<String, Boolean>> =
- object : SmartUpdateMediatorLiveData<Map<String, Boolean>>(),
- SensorPrivacyManager.OnSensorPrivacyChangedListener, LocationUtils.LocationListener {
+ data class SensorState(val visible: Boolean, val enabled: Boolean, val admin: EnforcedAdmin?)
+
+ val sensorPrivacyLiveData: SmartUpdateMediatorLiveData<Map<String, SensorState>> =
+ object :
+ SmartUpdateMediatorLiveData<Map<String, SensorState>>(),
+ SensorPrivacyManager.OnSensorPrivacyChangedListener,
+ LocationUtils.LocationListener {
override fun onUpdate() {
- val cameraEnabled = !sensorPrivacyManager.isSensorPrivacyEnabled(Sensors.CAMERA)
- val micEnabled = !sensorPrivacyManager.isSensorPrivacyEnabled(Sensors.MICROPHONE)
val locationEnabled =
locationManager.isLocationEnabledForUser(Process.myUserHandle())
- value = mapOf(CAMERA to cameraEnabled, MICROPHONE to micEnabled,
- LOCATION to locationEnabled)
+ val locationEnforcedAdmin =
+ getEnforcedAdmin(UserManager.DISALLOW_SHARE_LOCATION)
+ ?: getEnforcedAdmin(UserManager.DISALLOW_CONFIG_LOCATION)
+ value =
+ mapOf(
+ CAMERA to
+ getSensorState(
+ Sensors.CAMERA,
+ UserManager.DISALLOW_CAMERA_TOGGLE,
+ configCameraToggleEnabled),
+ MICROPHONE to
+ getSensorState(
+ Sensors.MICROPHONE,
+ UserManager.DISALLOW_MICROPHONE_TOGGLE,
+ configMicToggleEnabled),
+ LOCATION to SensorState(true, locationEnabled, locationEnforcedAdmin))
}
@Suppress("OVERRIDE_DEPRECATION")
@@ -172,6 +211,28 @@ class SafetyCenterQsViewModel(
}
}
+ private fun getSensorState(
+ sensor: Int,
+ restriction: String,
+ enableConfig: String
+ ): SensorState {
+ val sensorConfigEnabled =
+ DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, enableConfig, true)
+ return SensorState(
+ sensorConfigEnabled && sensorPrivacyManager.supportsSensorToggle(sensor),
+ !sensorPrivacyManager.isSensorPrivacyEnabled(TOGGLE_TYPE_SOFTWARE, sensor),
+ getEnforcedAdmin(restriction))
+ }
+
+ private fun getEnforcedAdmin(restriction: String) =
+ if (userManager
+ .getUserRestrictionSources(restriction, Process.myUserHandle())
+ .isNotEmpty()) {
+ RestrictedLockUtils.getProfileOrDeviceOwner(app, Process.myUserHandle())
+ } else {
+ null
+ }
+
fun navigateToManageService(fragment: Fragment, navigationIntent: Intent) {
fragment.startActivity(navigationIntent)
}
@@ -180,19 +241,19 @@ class SafetyCenterQsViewModel(
fragment.startActivity(getDefaultManageAppPermissionsIntent(usage.packageName, usage.uid))
}
- fun getStartViewPermissionUsageIntent(context: Context, usage: PermissionGroupUsage):
- Intent? {
+ fun getStartViewPermissionUsageIntent(context: Context, usage: PermissionGroupUsage): Intent? {
var intent: Intent = Intent(Intent.ACTION_MANAGE_PERMISSION_USAGE)
intent.setPackage(usage.packageName)
intent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, usage.permissionGroupName)
intent.putExtra(Intent.EXTRA_ATTRIBUTION_TAGS, arrayOf(usage.attributionTag.toString()))
intent.putExtra(Intent.EXTRA_SHOWING_ATTRIBUTION, true)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- val resolveInfo: ResolveInfo? = context.packageManager.resolveActivity(
- intent, PackageManager.ResolveInfoFlags.of(0))
- if (resolveInfo != null && resolveInfo.activityInfo != null &&
+ 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) {
+ android.Manifest.permission.START_VIEW_PERMISSION_USAGE) {
intent.component = ComponentName(usage.packageName, resolveInfo.activityInfo.name)
return intent
}
@@ -212,6 +273,12 @@ class SafetyCenterQsViewModel(
seeUsageIntent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, permGroupName)
fragment.startActivity(seeUsageIntent)
}
+
+ data class LightAppPermissionGroupUsageKey(
+ val packageName: String,
+ val permissionGroupName: String,
+ val userHandle: UserHandle
+ )
}
/**
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterUiData.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterUiData.kt
new file mode 100644
index 000000000..39241ff9a
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterUiData.kt
@@ -0,0 +1,71 @@
+/*
+ * 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.safetycenter.ui.model
+
+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 androidx.annotation.RequiresApi
+import com.android.safetycenter.internaldata.SafetyCenterBundles.ISSUES_TO_GROUPS_BUNDLE_KEY
+
+/** UI model representation of Safety Center Data */
+data class SafetyCenterUiData(
+ val safetyCenterData: SafetyCenterData,
+ val resolvedIssues: Map<IssueId, ActionId> = emptyMap()
+) {
+ /** Returns the [SafetyCenterEntryGroup] corresponding to the provided ID */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ fun getMatchingGroup(groupId: String): SafetyCenterEntryGroup? {
+ val entryOrGroups: List<SafetyCenterEntryOrGroup> = safetyCenterData.entriesOrGroups
+ val entryGroups = entryOrGroups.mapNotNull { it.entryGroup }
+ return entryGroups.find { it.id == groupId }
+ }
+
+ /**
+ * Returns a list of [SafetyCenterIssue] corresponding to the provided ID. This will be
+ * displayed as warning cards on a subpage in Safety Center.
+ */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ fun getMatchingIssues(groupId: String): List<SafetyCenterIssue> =
+ selectMatchingIssuesForGroup(groupId, safetyCenterData.issues)
+
+ /**
+ * Returns a list of dismissed [SafetyCenterIssue] corresponding to the provided ID. This will
+ * be displayed as dismissed warning cards on a subpage in Safety Center.
+ */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ fun getMatchingDismissedIssues(groupId: String): List<SafetyCenterIssue> =
+ selectMatchingIssuesForGroup(groupId, safetyCenterData.dismissedIssues)
+
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ private fun selectMatchingIssuesForGroup(
+ groupId: String,
+ issues: List<SafetyCenterIssue>
+ ): List<SafetyCenterIssue> {
+ val issuesToGroups = safetyCenterData.extras.getBundle(ISSUES_TO_GROUPS_BUNDLE_KEY)
+ return issues.filter {
+ val mappingExists = issuesToGroups?.containsKey(it.id) ?: false
+ val matchesInMapping =
+ issuesToGroups?.getStringArrayList(it.id)?.contains(groupId) ?: false
+ val matchesByDefault = it.groupId == groupId
+
+ if (mappingExists) matchesInMapping else matchesByDefault
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterViewModel.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterViewModel.kt
new file mode 100644
index 000000000..73814ff88
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterViewModel.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui.model
+
+import android.app.Application
+import android.content.Context
+import android.os.Build
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import android.safetycenter.SafetyCenterErrorDetails
+import android.safetycenter.SafetyCenterIssue
+import androidx.annotation.RequiresApi
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.LiveData
+import com.android.permissioncontroller.safetycenter.ui.InteractionLogger
+import com.android.permissioncontroller.safetycenter.ui.NavigationSource
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+abstract class SafetyCenterViewModel(protected val app: Application) : AndroidViewModel(app) {
+
+ abstract val statusUiLiveData: LiveData<StatusUiData>
+ abstract val safetyCenterUiLiveData: LiveData<SafetyCenterUiData>
+ abstract val errorLiveData: LiveData<SafetyCenterErrorDetails>
+ abstract val interactionLogger: InteractionLogger
+
+ abstract fun dismissIssue(issue: SafetyCenterIssue)
+
+ /**
+ * Execute the [action] to act on the given [issue]
+ *
+ * If [launchTaskId] is provided, this should be used to force the action to be associated with
+ * a particular taskId (if applicable).
+ */
+ abstract fun executeIssueAction(
+ issue: SafetyCenterIssue,
+ action: SafetyCenterIssue.Action,
+ launchTaskId: Int?
+ )
+
+ /**
+ * Marks a resolved [SafetyCenterIssue] as fully complete, meaning the resolution success
+ * message has been shown
+ *
+ * @param issueId Resolved issue that has completed its UI update and view can be removed
+ */
+ abstract fun markIssueResolvedUiCompleted(issueId: IssueId)
+
+ abstract fun rescan()
+
+ abstract fun clearError()
+
+ abstract fun navigateToSafetyCenter(
+ context: Context,
+ navigationSource: NavigationSource? = null
+ )
+
+ abstract fun pageOpen()
+
+ /**
+ * Refreshes a specific subset of safety sources on page-open.
+ *
+ * This is an overload of the [pageOpen] method and is used to request data from safety sources
+ * that are part of a subpage in the Safety Center UI.
+ *
+ * @param sourceGroupId represents ID of the corresponding safety sources group
+ */
+ @RequiresApi(UPSIDE_DOWN_CAKE) abstract fun pageOpen(sourceGroupId: String)
+
+ abstract fun changingConfigurations()
+
+ /**
+ * Returns the [SafetyCenterData] currently stored by the Safety Center service.
+ *
+ * Note about current impl: This is drawn directly from SafetyCenterManager and will not contain
+ * any data about currently in-flight issues.
+ */
+ abstract fun getCurrentSafetyCenterDataAsUiData(): SafetyCenterUiData
+}
+
+typealias IssueId = String
+
+typealias ActionId = String
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/StatusUiData.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/StatusUiData.kt
new file mode 100644
index 000000000..741745c19
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/StatusUiData.kt
@@ -0,0 +1,101 @@
+package com.android.permissioncontroller.safetycenter.ui.model
+
+import android.content.Context
+import android.os.Build.VERSION_CODES.TIRAMISU
+import android.safetycenter.SafetyCenterData
+import android.safetycenter.SafetyCenterStatus
+import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK
+import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN
+import android.util.Log
+import androidx.annotation.RequiresApi
+import com.android.permissioncontroller.R
+
+/** UI model representation of a Status Card. */
+@RequiresApi(TIRAMISU)
+data class StatusUiData(
+ private val status: SafetyCenterStatus,
+ @get:JvmName("hasIssues") val hasIssues: Boolean = false,
+ @get:JvmName("hasPendingActions") val hasPendingActions: Boolean = false
+) {
+
+ constructor(
+ safetyCenterData: SafetyCenterData
+ ) : this(safetyCenterData.status, hasIssues = safetyCenterData.issues.size > 0)
+
+ // For convenience use in Java.
+ fun copyForPendingActions(hasPendingActions: Boolean) =
+ copy(hasPendingActions = hasPendingActions)
+
+ companion object {
+ private val TAG: String = StatusUiData::class.java.simpleName
+ fun getStatusImageResId(severityLevel: Int) =
+ when (severityLevel) {
+ OVERALL_SEVERITY_LEVEL_UNKNOWN,
+ OVERALL_SEVERITY_LEVEL_OK -> R.drawable.safety_status_info
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION ->
+ R.drawable.safety_status_recommendation
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING ->
+ R.drawable.safety_status_warn
+ else -> {
+ Log.w(TAG, "Unexpected OverallSeverityLevel: $severityLevel")
+ R.drawable.safety_status_info
+ }
+ }
+ }
+
+ val title: CharSequence by status::title
+ val originalSummary: CharSequence by status::summary
+ val severityLevel: Int by status::severityLevel
+
+ val statusImageResId: Int
+ get() = getStatusImageResId(severityLevel)
+
+ fun getSummary(context: Context): CharSequence {
+ return if (hasPendingActions) {
+ // Use a different string for the special quick-settings-only hasPendingActions state.
+ context.getString(R.string.safety_center_qs_status_summary)
+ } else {
+ originalSummary
+ }
+ }
+
+ fun getContentDescription(context: Context): CharSequence {
+ return context.getString(
+ R.string.safety_status_preference_title_and_summary_content_description,
+ title,
+ getSummary(context)
+ )
+ }
+
+ val isRefreshInProgress: Boolean
+ get() =
+ when (status.refreshStatus) {
+ SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS,
+ SafetyCenterStatus.REFRESH_STATUS_DATA_FETCH_IN_PROGRESS -> true
+ else -> false
+ }
+
+ fun shouldShowRescanButton(): Boolean {
+ return !hasIssues &&
+ !hasPendingActions &&
+ when (severityLevel) {
+ OVERALL_SEVERITY_LEVEL_OK,
+ OVERALL_SEVERITY_LEVEL_UNKNOWN -> true
+ else -> false
+ }
+ }
+
+ enum class ButtonToShow {
+ RESCAN,
+ REVIEW_SETTINGS
+ }
+ val buttonToShow: ButtonToShow?
+ get() =
+ when {
+ hasIssues -> null
+ hasPendingActions -> ButtonToShow.REVIEW_SETTINGS
+ severityLevel == OVERALL_SEVERITY_LEVEL_OK ||
+ severityLevel == OVERALL_SEVERITY_LEVEL_UNKNOWN -> ButtonToShow.RESCAN
+ else -> null
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/package-info.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/package-info.java
new file mode 100644
index 000000000..00fda1f5b
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@NonNullByDefault
+package com.android.permissioncontroller.safetycenter.ui.model;
+
+import com.android.safetycenter.annotations.NonNullByDefault;
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/package-info.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/package-info.java
new file mode 100644
index 000000000..3389e3a3b
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@NonNullByDefault
+package com.android.permissioncontroller.safetycenter.ui;
+
+import com.android.safetycenter.annotations.NonNullByDefault;
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/MoreIssuesHeaderView.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/MoreIssuesHeaderView.kt
new file mode 100644
index 000000000..264aa488e
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/MoreIssuesHeaderView.kt
@@ -0,0 +1,255 @@
+package com.android.permissioncontroller.safetycenter.ui.view
+
+import android.animation.ValueAnimator
+import android.content.Context
+import android.graphics.drawable.Animatable2
+import android.graphics.drawable.AnimatedVectorDrawable
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.graphics.drawable.RippleDrawable
+import android.os.Build
+import android.safetycenter.SafetyCenterIssue
+import android.text.TextUtils
+import android.util.AttributeSet
+import android.util.Log
+import android.view.View
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.annotation.DrawableRes
+import androidx.annotation.RequiresApi
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.view.ViewCompat
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
+import androidx.core.view.isVisible
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.utils.StringUtils
+import com.android.permissioncontroller.safetycenter.ui.MoreIssuesCardAnimator
+import com.android.permissioncontroller.safetycenter.ui.MoreIssuesCardData
+import java.text.NumberFormat
+import java.time.Duration
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+internal class MoreIssuesHeaderView
+@JvmOverloads
+constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+ defStyleRes: Int = 0
+) : ConstraintLayout(context, attrs, defStyleAttr, defStyleRes) {
+
+ init {
+ inflate(context, R.layout.view_more_issues, this)
+ }
+
+ 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 expandCollapseIcon: ImageView by lazy {
+ expandCollapseLayout.findViewById(R.id.widget_icon)
+ }
+ private var cornerAnimator: ValueAnimator? = null
+
+ fun showExpandableHeader(
+ previousData: MoreIssuesCardData?,
+ nextData: MoreIssuesCardData,
+ title: String,
+ @DrawableRes overrideChevronIconResId: Int?,
+ onClick: () -> Unit
+ ) {
+ titleView.text = title
+ updateStatusIcon(previousData?.severityLevel, nextData.severityLevel)
+ updateExpandCollapseButton(
+ previousData?.isExpanded,
+ nextData.isExpanded,
+ overrideChevronIconResId
+ )
+ updateIssueCount(previousData?.hiddenIssueCount, nextData.hiddenIssueCount)
+ updateBackground(previousData?.isExpanded, nextData.isExpanded)
+ setOnClickListener { onClick() }
+
+ val expansionString =
+ StringUtils.getIcuPluralsString(
+ context,
+ R.string.safety_center_more_issues_card_expand_action,
+ nextData.hiddenIssueCount
+ )
+ // Replacing the on-click label to indicate the number of hidden issues. The on-click
+ // command is set to null so that it uses the existing expansion behaviour.
+ ViewCompat.replaceAccessibilityAction(
+ this,
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
+ expansionString,
+ null
+ )
+ }
+
+ fun showStaticHeader(title: String, severityLevel: Int) {
+ titleView.text = title
+ updateStatusIcon(previousSeverityLevel = null, severityLevel)
+ expandCollapseLayout.isVisible = false
+ setOnClickListener(null)
+ isClickable = false
+ setBackgroundResource(android.R.color.transparent)
+ }
+
+ private fun updateExpandCollapseButton(
+ wasExpanded: Boolean?,
+ isExpanded: Boolean,
+ @DrawableRes overrideChevronIconResId: Int?
+ ) {
+ expandCollapseLayout.isVisible = true
+ if (overrideChevronIconResId != null) {
+ expandCollapseIcon.setImageResource(overrideChevronIconResId)
+ } else if (wasExpanded != null && wasExpanded != isExpanded) {
+ if (isExpanded) {
+ expandCollapseIcon.animate(
+ R.drawable.more_issues_expand_anim,
+ R.drawable.ic_collapse_issues
+ )
+ } else {
+ expandCollapseIcon.animate(
+ R.drawable.more_issues_collapse_anim,
+ R.drawable.ic_expand_issues
+ )
+ }
+ } else {
+ expandCollapseIcon.setImageResource(
+ if (isExpanded) {
+ R.drawable.ic_collapse_issues
+ } else {
+ R.drawable.ic_expand_issues
+ }
+ )
+ }
+ }
+
+ private fun updateStatusIcon(previousSeverityLevel: Int?, endSeverityLevel: Int) {
+ statusIconView.isVisible = true
+ moreIssuesCardAnimator.cancelStatusAnimation(statusIconView)
+ if (previousSeverityLevel != null && previousSeverityLevel != endSeverityLevel) {
+ moreIssuesCardAnimator.animateStatusIconsChange(
+ statusIconView,
+ previousSeverityLevel,
+ endSeverityLevel,
+ selectIconResId(endSeverityLevel)
+ )
+ } else {
+ statusIconView.setImageResource(selectIconResId(endSeverityLevel))
+ }
+ }
+
+ @DrawableRes
+ private fun selectIconResId(severityLevel: Int): Int {
+ return when (severityLevel) {
+ SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK -> R.drawable.ic_safety_info
+ SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION ->
+ R.drawable.ic_safety_recommendation
+ SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING -> R.drawable.ic_safety_warn
+ else -> {
+ Log.e(TAG, "Unexpected SafetyCenterIssue.IssueSeverityLevel: $severityLevel")
+ R.drawable.ic_safety_null_state
+ }
+ }
+ }
+
+ private fun updateIssueCount(previousCount: Int?, endCount: Int) {
+ moreIssuesCardAnimator.cancelTextChangeAnimation(counterView)
+
+ val numberFormat = NumberFormat.getInstance()
+ val previousText = previousCount?.let(numberFormat::format)
+ val newText = numberFormat.format(endCount)
+ val animateTextChange =
+ !previousText.isNullOrEmpty() && !TextUtils.equals(previousText, newText)
+
+ if (animateTextChange) {
+ counterView.text = previousText
+ moreIssuesCardAnimator.animateChangeText(counterView, newText)
+ } else {
+ counterView.text = newText
+ }
+ }
+
+ private fun updateBackground(wasExpanded: Boolean?, isExpanded: Boolean) {
+ if (background !is RippleDrawable) {
+ setBackgroundResource(R.drawable.safety_center_more_issues_card_background)
+ }
+ (background?.mutate() as? RippleDrawable)?.let { ripple ->
+ val topRadius = context.resources.getDimension(R.dimen.sc_card_corner_radius_large)
+ val bottomRadiusStart =
+ if (wasExpanded ?: isExpanded) {
+ context.resources.getDimension(R.dimen.sc_card_corner_radius_xsmall)
+ } else {
+ topRadius
+ }
+ val bottomRadiusEnd =
+ if (isExpanded) {
+ context.resources.getDimension(R.dimen.sc_card_corner_radius_xsmall)
+ } else {
+ topRadius
+ }
+ val cornerRadii =
+ floatArrayOf(
+ topRadius,
+ topRadius,
+ topRadius,
+ topRadius,
+ bottomRadiusStart,
+ bottomRadiusStart,
+ bottomRadiusStart,
+ bottomRadiusStart
+ )
+ setCornerRadii(ripple, cornerRadii)
+ if (bottomRadiusEnd != bottomRadiusStart) {
+ cornerAnimator?.removeAllUpdateListeners()
+ cornerAnimator?.removeAllListeners()
+ cornerAnimator?.cancel()
+ val animator =
+ ValueAnimator.ofFloat(bottomRadiusStart, bottomRadiusEnd)
+ .setDuration(CORNER_RADII_ANIMATION_DURATION.toMillis())
+ if (isExpanded) {
+ animator.startDelay = CORNER_RADII_ANIMATION_DELAY.toMillis()
+ }
+ animator.addUpdateListener {
+ cornerRadii.fill(it.animatedValue as Float, fromIndex = 4, toIndex = 8)
+ setCornerRadii(ripple, cornerRadii)
+ }
+ animator.start()
+ cornerAnimator = animator
+ }
+ }
+ }
+
+ private fun setCornerRadii(ripple: RippleDrawable, cornerRadii: FloatArray) {
+ for (index in 0 until ripple.numberOfLayers) {
+ (ripple.getDrawable(index).mutate() as? GradientDrawable)?.let {
+ it.cornerRadii = cornerRadii
+ }
+ }
+ }
+
+ private fun ImageView.animate(@DrawableRes animationRes: Int, @DrawableRes imageRes: Int) {
+ (drawable as? AnimatedVectorDrawable)?.clearAnimationCallbacks()
+ setImageResource(animationRes)
+ (drawable as? AnimatedVectorDrawable)?.apply {
+ registerAnimationCallback(
+ object : Animatable2.AnimationCallback() {
+ override fun onAnimationEnd(drawable: Drawable?) {
+ setImageResource(imageRes)
+ }
+ }
+ )
+ start()
+ }
+ }
+
+ companion object {
+ val TAG: String = MoreIssuesHeaderView::class.java.simpleName
+ private val CORNER_RADII_ANIMATION_DELAY = Duration.ofMillis(250)
+ private val CORNER_RADII_ANIMATION_DURATION = Duration.ofMillis(120)
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryCommonViewsManager.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryCommonViewsManager.kt
new file mode 100644
index 000000000..4be327285
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryCommonViewsManager.kt
@@ -0,0 +1,109 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui.view
+
+import android.content.Context
+import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED
+import android.safetycenter.SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.TextView
+import com.android.permissioncontroller.R
+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) }
+
+ fun showDetails(
+ id: String,
+ title: CharSequence,
+ summary: CharSequence?,
+ severityLevel: Int,
+ severityUnspecifiedIconType: Int
+ ) {
+ titleView?.text = title
+ summaryView?.showText(summary)
+
+ iconView?.setImageResource(
+ SeverityIconPicker.selectIconResId(id, severityLevel, severityUnspecifiedIconType)
+ )
+
+ val hideIcon =
+ (severityLevel == ENTRY_SEVERITY_LEVEL_UNSPECIFIED &&
+ severityUnspecifiedIconType == SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON)
+ iconFrame?.visibility = if (hideIcon) LinearLayout.GONE else LinearLayout.VISIBLE
+ emptySpace?.visibility = if (hideIcon) LinearLayout.VISIBLE else LinearLayout.GONE
+ }
+
+ private fun TextView.showText(text: CharSequence?) {
+ if (text != null && text.isNotEmpty()) {
+ visibility = View.VISIBLE
+ this.text = text
+ } else {
+ visibility = View.GONE
+ }
+ }
+
+ companion object {
+
+ private const val DEFAULT_DISABLED_ALPHA = 0.4f
+
+ /**
+ * Change opacity to make some entries look disabled but still be clickable
+ *
+ * @param isEntryEnabled whether the [android.safetycenter.SafetyCenterEntry] is enabled
+ * @param isPreferenceEnabled whether the corresponding preference is enabled
+ * @param titleView view displaying the title text of the entry
+ * @param summaryView view displaying the summary text of the entry
+ */
+ fun changeEnabledState(
+ context: Context,
+ isEntryEnabled: Boolean,
+ isPreferenceEnabled: Boolean,
+ titleView: TextView?,
+ summaryView: TextView?
+ ) {
+ val disabledAlpha = getDisabledAlpha(context)
+ if (isEntryEnabled) {
+ titleView?.alpha = 1f
+ summaryView?.alpha = 1f
+ } else if (isPreferenceEnabled) {
+ /* Check that preference is enabled before lowering because disabled preferences
+ * already have a low visibility */
+ titleView?.alpha = disabledAlpha
+ summaryView?.alpha = disabledAlpha
+ }
+ }
+
+ private fun getDisabledAlpha(context: Context): Float {
+ val styledAttributes =
+ context.obtainStyledAttributes(intArrayOf(android.R.attr.disabledAlpha))
+ try {
+ return styledAttributes.getFloat(0, DEFAULT_DISABLED_ALPHA)
+ } finally {
+ styledAttributes.recycle()
+ }
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryGroupView.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryGroupView.kt
new file mode 100644
index 000000000..318ade5cb
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryGroupView.kt
@@ -0,0 +1,279 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui.view
+
+import android.content.Context
+import android.graphics.drawable.Animatable2.AnimationCallback
+import android.graphics.drawable.AnimatedVectorDrawable
+import android.graphics.drawable.Drawable
+import android.os.Build
+import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION
+import android.safetycenter.SafetyCenterEntryGroup
+import android.util.AttributeSet
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.annotation.DrawableRes
+import androidx.annotation.RequiresApi
+import androidx.core.view.ViewCompat
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
+import androidx.transition.AutoTransition
+import androidx.transition.TransitionManager
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.safetycenter.ui.PositionInCardList
+import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterViewModel
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+internal class SafetyEntryGroupView
+@JvmOverloads
+constructor(
+ context: Context?,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+ defStyleRes: Int = 0
+) : LinearLayout(context, attrs, defStyleAttr, defStyleRes) {
+
+ private companion object {
+ val TAG = SafetyEntryGroupView::class.java.simpleName
+ const val EXPAND_COLLAPSE_ANIMATION_DURATION_MS = 183L
+ }
+
+ init {
+ inflate(context, R.layout.safety_center_group, this)
+ }
+
+ private val groupHeaderView: LinearLayout? by lazy { findViewById(R.id.group_header) }
+
+ private val expandedHeaderView: ViewGroup? by lazy { findViewById(R.id.expanded_header) }
+ private val expandedTitleView: TextView? by lazy {
+ expandedHeaderView?.findViewById(R.id.title)
+ }
+
+ private val collapsedHeaderView: ViewGroup? by lazy { findViewById(R.id.collapsed_header) }
+ private val commonEntryView: SafetyEntryCommonViewsManager? by lazy {
+ 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 var isExpanded: Boolean? = null
+
+ fun showGroup(
+ group: SafetyCenterEntryGroup,
+ initiallyExpanded: (String) -> Boolean,
+ isFirstCard: Boolean,
+ isLastCard: Boolean,
+ getTaskIdForEntry: (String) -> Int,
+ viewModel: SafetyCenterViewModel,
+ onGroupExpanded: (String) -> Unit,
+ onGroupCollapsed: (String) -> Unit
+ ) {
+ applyPosition(isFirstCard, isLastCard)
+ showGroupDetails(group)
+ showGroupEntries(group, getTaskIdForEntry, viewModel)
+ setupExpandedState(group, initiallyExpanded(group.id))
+ setOnClickListener { toggleExpandedState(group, onGroupExpanded, onGroupCollapsed) }
+ }
+
+ private fun applyPosition(isFirstCard: Boolean, isLastCard: Boolean) {
+ val position =
+ when {
+ isFirstCard && isLastCard -> PositionInCardList.LIST_START_END
+ isFirstCard && !isLastCard -> PositionInCardList.LIST_START_CARD_END
+ !isFirstCard && isLastCard -> PositionInCardList.CARD_START_LIST_END
+ /* !isFirstCard && !isLastCard */ else -> PositionInCardList.CARD_START_END
+ }
+ setBackgroundResource(position.backgroundDrawableResId)
+ val topMargin: Int = position.getTopMargin(context)
+
+ val params = layoutParams as MarginLayoutParams
+ if (params.topMargin != topMargin) {
+ params.topMargin = topMargin
+ layoutParams = params
+ }
+ }
+
+ private fun showGroupDetails(group: SafetyCenterEntryGroup) {
+ expandedTitleView?.text = group.title
+ commonEntryView?.showDetails(
+ group.id,
+ group.title,
+ group.summary,
+ group.severityLevel,
+ group.severityUnspecifiedIconType
+ )
+ }
+
+ private fun setupExpandedState(group: SafetyCenterEntryGroup, shouldBeExpanded: Boolean) {
+ if (isExpanded == shouldBeExpanded) {
+ return
+ }
+
+ collapsedHeaderView?.visibility = if (shouldBeExpanded) View.GONE else View.VISIBLE
+ expandedHeaderView?.visibility = if (shouldBeExpanded) View.VISIBLE else View.GONE
+ entriesContainerView?.visibility = if (shouldBeExpanded) View.VISIBLE else View.GONE
+
+ if (shouldBeExpanded) {
+ groupHeaderView?.gravity = Gravity.TOP
+ } else {
+ groupHeaderView?.gravity = Gravity.CENTER_VERTICAL
+ }
+
+ if (isExpanded == null) {
+ chevronIconView?.setImageResource(
+ if (shouldBeExpanded) {
+ R.drawable.ic_safety_group_collapse
+ } else {
+ R.drawable.ic_safety_group_expand
+ }
+ )
+ } else if (shouldBeExpanded) {
+ chevronIconView?.animate(
+ R.drawable.safety_center_group_expand_anim,
+ R.drawable.ic_safety_group_collapse
+ )
+ } else {
+ chevronIconView?.animate(
+ R.drawable.safety_center_group_collapse_anim,
+ R.drawable.ic_safety_group_expand
+ )
+ }
+
+ isExpanded = shouldBeExpanded
+
+ val newPaddingTop =
+ context.resources.getDimensionPixelSize(
+ if (shouldBeExpanded) {
+ R.dimen.sc_entry_group_expanded_padding_top
+ } else {
+ R.dimen.sc_entry_group_collapsed_padding_top
+ }
+ )
+ val newPaddingBottom =
+ context.resources.getDimensionPixelSize(
+ if (shouldBeExpanded) {
+ R.dimen.sc_entry_group_expanded_padding_bottom
+ } else {
+ R.dimen.sc_entry_group_collapsed_padding_bottom
+ }
+ )
+ setPaddingRelative(paddingStart, newPaddingTop, paddingEnd, newPaddingBottom)
+
+ // accessibility attributes depend on the expanded state
+ // and should be updated every time this state changes
+ setAccessibilityAttributes(group)
+ }
+
+ private fun ImageView.animate(@DrawableRes animationRes: Int, @DrawableRes imageRes: Int) {
+ (drawable as? AnimatedVectorDrawable)?.clearAnimationCallbacks()
+ setImageResource(animationRes)
+ (drawable as? AnimatedVectorDrawable)?.apply {
+ registerAnimationCallback(
+ object : AnimationCallback() {
+ override fun onAnimationEnd(drawable: Drawable?) {
+ setImageResource(imageRes)
+ }
+ }
+ )
+ start()
+ }
+ }
+
+ private fun showGroupEntries(
+ group: SafetyCenterEntryGroup,
+ getTaskIdForEntry: (String) -> Int,
+ viewModel: SafetyCenterViewModel
+ ) {
+ val entriesCount = group.entries.size
+ val existingViewsCount = entriesContainerView?.childCount ?: 0
+ if (entriesCount > existingViewsCount) {
+ for (i in 1..(entriesCount - existingViewsCount)) {
+ inflate(context, R.layout.safety_center_group_entry, entriesContainerView)
+ }
+ } else if (entriesCount < existingViewsCount) {
+ for (i in 1..(existingViewsCount - entriesCount)) {
+ entriesContainerView?.removeViewAt(0)
+ }
+ }
+
+ group.entries.forEachIndexed { index, entry ->
+ val childAt = entriesContainerView?.getChildAt(index)
+ val entryView = childAt as? SafetyEntryView
+ entryView?.showEntry(
+ entry,
+ PositionInCardList.INSIDE_GROUP,
+ getTaskIdForEntry(entry.id),
+ viewModel
+ )
+ }
+ }
+
+ private fun setAccessibilityAttributes(group: SafetyCenterEntryGroup) {
+ // When status is yellow/red, adding an "Actions needed" before the summary is read.
+ contentDescription =
+ if (isExpanded == true) {
+ null
+ } else {
+ val isActionNeeded = group.severityLevel >= ENTRY_SEVERITY_LEVEL_RECOMMENDATION
+ val contentDescriptionResId =
+ if (isActionNeeded) {
+ R.string.safety_center_entry_group_with_actions_needed_content_description
+ } else {
+ R.string.safety_center_entry_group_content_description
+ }
+ context.getString(contentDescriptionResId, group.title, group.summary)
+ }
+
+ // Replacing the on-click label to indicate the expand/collapse action. The on-click command
+ // is set to null so that it uses the existing expand/collapse behaviour.
+ val accessibilityActionResId =
+ if (isExpanded == true) {
+ R.string.safety_center_entry_group_collapse_action
+ } else {
+ R.string.safety_center_entry_group_expand_action
+ }
+ ViewCompat.replaceAccessibilityAction(
+ this,
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
+ context.getString(accessibilityActionResId),
+ null
+ )
+ }
+
+ private fun toggleExpandedState(
+ group: SafetyCenterEntryGroup,
+ onGroupExpanded: (String) -> Unit,
+ onGroupCollapsed: (String) -> Unit
+ ) {
+ val transition = AutoTransition()
+ transition.duration = EXPAND_COLLAPSE_ANIMATION_DURATION_MS
+ TransitionManager.beginDelayedTransition(rootView as ViewGroup, transition)
+
+ val shouldBeExpanded = isExpanded != true
+ setupExpandedState(group, shouldBeExpanded)
+
+ if (shouldBeExpanded) {
+ onGroupExpanded(group.id)
+ } else {
+ onGroupCollapsed(group.id)
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryView.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryView.kt
new file mode 100644
index 000000000..ff7233686
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/SafetyEntryView.kt
@@ -0,0 +1,197 @@
+/*
+ * 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.permissioncontroller.safetycenter.ui.view
+
+import android.content.Context
+import android.os.Build
+import android.safetycenter.SafetyCenterEntry
+import android.safetycenter.SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR
+import android.util.AttributeSet
+import android.util.Log
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.annotation.RequiresApi
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.safetycenter.ui.Action
+import com.android.permissioncontroller.safetycenter.ui.PendingIntentSender
+import com.android.permissioncontroller.safetycenter.ui.PositionInCardList
+import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterViewModel
+import com.android.permissioncontroller.safetycenter.ui.view.SafetyEntryCommonViewsManager.Companion.changeEnabledState
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+internal class SafetyEntryView
+@JvmOverloads
+constructor(
+ context: Context?,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+ defStyleRes: Int = 0
+) : LinearLayout(context, attrs, defStyleAttr, defStyleRes) {
+
+ private companion object {
+ val TAG = SafetyEntryView::class.java.simpleName
+ }
+
+ init {
+ inflate(context, R.layout.view_entry, this)
+ }
+
+ private val commonEntryView: SafetyEntryCommonViewsManager? by lazy {
+ SafetyEntryCommonViewsManager(this)
+ }
+ private val widgetFrame: ViewGroup? by lazy { findViewById(R.id.widget_frame) }
+
+ fun showEntry(
+ entry: SafetyCenterEntry,
+ position: PositionInCardList,
+ launchTaskId: Int?,
+ viewModel: SafetyCenterViewModel
+ ) {
+ setBackgroundResource(position.backgroundDrawableResId)
+ val topMargin: Int = position.getTopMargin(context)
+
+ val params = layoutParams as MarginLayoutParams
+ if (params.topMargin != topMargin) {
+ params.topMargin = topMargin
+ layoutParams = params
+ }
+
+ showEntryDetails(entry)
+ setupEntryClickListener(entry, launchTaskId, viewModel)
+ enableOrDisableEntry(entry)
+ setupIconActionButton(entry, launchTaskId, viewModel)
+ setContentDescription(entry, position == PositionInCardList.INSIDE_GROUP)
+ }
+
+ private fun showEntryDetails(entry: SafetyCenterEntry) {
+ commonEntryView?.showDetails(
+ entry.id,
+ entry.title,
+ entry.summary,
+ entry.severityLevel,
+ entry.severityUnspecifiedIconType
+ )
+ }
+
+ private fun TextView.showText(text: CharSequence?) {
+ if (text?.isNotEmpty() != true) {
+ visibility = GONE
+ } else {
+ visibility = VISIBLE
+ this.text = text
+ }
+ }
+
+ private fun setupEntryClickListener(
+ entry: SafetyCenterEntry,
+ launchTaskId: Int?,
+ viewModel: SafetyCenterViewModel
+ ) {
+ val pendingIntent = entry.pendingIntent
+ if (pendingIntent != null) {
+ setOnClickListener {
+ try {
+ PendingIntentSender.send(entry.pendingIntent, launchTaskId)
+ viewModel.interactionLogger.recordForEntry(Action.ENTRY_CLICKED, entry)
+ } catch (ex: java.lang.Exception) {
+ Log.e(TAG, "Failed to execute pending intent for entry: $entry", ex)
+ }
+ }
+ } else {
+ // Ensure that views without listeners can still be focused by accessibility services
+ // TODO b/243713158: Set the proper accessibility focus in style, rather than in code
+ isFocusable = true
+ }
+ }
+
+ private fun setupIconActionButton(
+ entry: SafetyCenterEntry,
+ launchTaskId: Int?,
+ viewModel: SafetyCenterViewModel
+ ) {
+ val iconAction = entry.iconAction
+ if (iconAction != null) {
+ val iconActionButton =
+ widgetFrame?.findViewById(R.id.icon_action_button)
+ ?: kotlin.run {
+ val widgetLayout =
+ if (iconAction.type == ICON_ACTION_TYPE_GEAR) {
+ R.layout.preference_entry_icon_action_gear_widget
+ } else {
+ R.layout.preference_entry_icon_action_info_widget
+ }
+ inflate(context, widgetLayout, widgetFrame)
+ widgetFrame?.findViewById<ImageView>(R.id.icon_action_button)
+ }
+ widgetFrame?.visibility = VISIBLE
+ iconActionButton?.setOnClickListener {
+ sendIconActionIntent(iconAction, launchTaskId, entry)
+ viewModel.interactionLogger.recordForEntry(Action.ENTRY_ICON_ACTION_CLICKED, entry)
+ }
+ setPaddingRelative(paddingStart, paddingTop, /* end = */ 0, paddingBottom)
+ } else {
+ widgetFrame?.visibility = GONE
+ setPaddingRelative(
+ paddingStart,
+ paddingTop,
+ context.resources.getDimensionPixelSize(R.dimen.sc_entry_padding_end),
+ paddingBottom
+ )
+ }
+ }
+
+ private fun sendIconActionIntent(
+ iconAction: SafetyCenterEntry.IconAction,
+ launchTaskId: Int?,
+ entry: SafetyCenterEntry
+ ) {
+ try {
+ PendingIntentSender.send(iconAction.pendingIntent, launchTaskId)
+ } catch (ex: Exception) {
+ Log.e(TAG, "Failed to execute icon action intent for entry: $entry", ex)
+ }
+ }
+
+ /** We are doing this because we need some entries to look disabled but still be clickable. */
+ private fun enableOrDisableEntry(entry: SafetyCenterEntry) {
+ // Making it clickable allows a disabled Entry View to consume its click which would
+ // otherwise be sent to the parent and cause the entry group to collapse.
+ isClickable = true
+ isEnabled = entry.pendingIntent != null
+ changeEnabledState(
+ context,
+ entry.isEnabled,
+ isEnabled,
+ commonEntryView?.titleView,
+ commonEntryView?.summaryView
+ )
+ }
+
+ private fun setContentDescription(entry: SafetyCenterEntry, isGroupEntry: Boolean) {
+ // Setting a customized description for entries that are part of an expandable group.
+ // Whereas for non-expandable entries, the default description of title and summary is used.
+ val resourceId =
+ if (isGroupEntry) {
+ R.string.safety_center_entry_group_item_content_description
+ } else {
+ R.string.safety_center_entry_content_description
+ }
+ contentDescription = context.getString(resourceId, entry.title, entry.summary)
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/StatusCardView.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/StatusCardView.kt
new file mode 100644
index 000000000..013f32c85
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/StatusCardView.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.permissioncontroller.safetycenter.ui.view
+
+import android.content.Context
+import android.os.Build
+import android.util.AttributeSet
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.annotation.RequiresApi
+import androidx.constraintlayout.widget.ConstraintLayout
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.safetycenter.ui.model.StatusUiData
+import com.google.android.material.button.MaterialButton
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+internal class StatusCardView
+@JvmOverloads
+constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+ defStyleRes: Int = 0
+) : ConstraintLayout(context, attrs, defStyleAttr, defStyleRes) {
+
+ init {
+ 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) }
+
+ fun showButtons(statusUiData: StatusUiData) {
+ rescanButton.isEnabled = !statusUiData.isRefreshInProgress
+
+ when (statusUiData.buttonToShow) {
+ StatusUiData.ButtonToShow.RESCAN -> {
+ rescanButton.visibility = VISIBLE
+ reviewSettingsButton.visibility = GONE
+ }
+ StatusUiData.ButtonToShow.REVIEW_SETTINGS -> {
+ rescanButton.visibility = GONE
+ reviewSettingsButton.visibility = VISIBLE
+ }
+ null -> {
+ rescanButton.visibility = GONE
+ reviewSettingsButton.visibility = GONE
+ }
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/package-info.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/package-info.java
new file mode 100644
index 000000000..88037aa61
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/view/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@NonNullByDefault
+package com.android.permissioncontroller.safetycenter.ui.view;
+
+import com.android.safetycenter.annotations.NonNullByDefault;
diff --git a/PermissionController/src/com/android/permissioncontroller/safetylabel/AppsSafetyLabelHistory.kt b/PermissionController/src/com/android/permissioncontroller/safetylabel/AppsSafetyLabelHistory.kt
new file mode 100644
index 000000000..26f327e96
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetylabel/AppsSafetyLabelHistory.kt
@@ -0,0 +1,150 @@
+/*
+ * 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.permissioncontroller.safetylabel
+
+import com.android.permission.safetylabel.DataCategory as AppMetadataDataCategory
+import com.android.permission.safetylabel.DataCategoryConstants
+import com.android.permission.safetylabel.DataLabel as AppMetadataDataLabel
+import com.android.permission.safetylabel.DataPurposeConstants.PURPOSE_ADVERTISING
+import com.android.permission.safetylabel.SafetyLabel as AppMetadataSafetyLabel
+import java.time.Instant
+
+/** Data class representing safety label history of installed apps. */
+data class AppsSafetyLabelHistory(val appSafetyLabelHistories: List<AppSafetyLabelHistory>) {
+
+ /** Data class representing the safety label history of an app. */
+ data class AppSafetyLabelHistory(
+ /** Information about the app. */
+ val appInfo: AppInfo,
+ /**
+ * A list of [SafetyLabel]s that this app has had in the past, ordered by
+ * [SafetyLabel.receivedAt].
+ *
+ * The last [SafetyLabel] in this list can be considered the last known [SafetyLabel] of the
+ * app.
+ */
+ val safetyLabelHistory: List<SafetyLabel>
+ ) {
+ init {
+ require(safetyLabelHistory.sortedBy { it.receivedAt } == safetyLabelHistory)
+ require(safetyLabelHistory.all { it.appInfo == appInfo })
+ }
+
+ /**
+ * Returns an [AppSafetyLabelHistory] with the original history as well the provided safety
+ * label, ensuring that the maximum number of safety labels stored for this app does not
+ * exceed [maxToPersist].
+ *
+ * If the storage already has [maxToPersist] labels or more, the oldest will be discarded to
+ * make space for the newly added safety label.
+ */
+ fun withSafetyLabel(safetyLabel: SafetyLabel, maxToPersist: Int): AppSafetyLabelHistory =
+ AppSafetyLabelHistory(
+ appInfo,
+ safetyLabelHistory
+ .toMutableList()
+ .apply { add(safetyLabel) }
+ .sortedBy { it.receivedAt }
+ .takeLast(maxToPersist))
+ }
+
+ /** Data class representing the information about an app. */
+ data class AppInfo(
+ val packageName: String,
+ )
+
+ /** Data class representing an app's safety label. */
+ data class SafetyLabel(
+ /** Information about the app. */
+ val appInfo: AppInfo,
+ /** Earliest time at which the safety label was known to be accurate. */
+ val receivedAt: Instant,
+ /** Information about data use policies for an app. */
+ val dataLabel: DataLabel
+ ) {
+ /** Companion object for [SafetyLabel]. */
+ companion object {
+ /**
+ * Creates a safety label for persistence from the safety label parsed from
+ * PackageManager app metadata.
+ */
+ fun extractLocationSharingSafetyLabel(
+ packageName: String,
+ receivedAt: Instant,
+ appMetadataSafetyLabel: AppMetadataSafetyLabel
+ ): SafetyLabel =
+ SafetyLabel(
+ AppInfo(packageName),
+ receivedAt,
+ DataLabel.extractLocationSharingDataLabel(appMetadataSafetyLabel.dataLabel))
+ }
+ }
+
+ /** Data class representing an app's data use policies. */
+ data class DataLabel(
+ /** Map of category to [DataCategory] */
+ val dataShared: Map<String, DataCategory>
+ ) {
+ /** Companion object for [DataCategory]. */
+ companion object {
+ /**
+ * Creates a data label for persistence from a data label parsed from PackageManager app
+ * metadata.
+ */
+ fun extractLocationSharingDataLabel(
+ appMetadataDataLabel: AppMetadataDataLabel
+ ): DataLabel =
+ DataLabel(
+ appMetadataDataLabel.dataShared
+ .filter { it.key == DataCategoryConstants.CATEGORY_LOCATION }
+ .mapValues { categoryEntry ->
+ DataCategory.fromAppMetadataDataCategory(categoryEntry.value)
+ })
+ }
+ }
+
+ /** Data class representing an app's data use for a particular category of data. */
+ data class DataCategory(
+ /** Whether any data in this category has been used for Advertising. */
+ val containsAdvertisingPurpose: Boolean
+ ) {
+ /** Companion object for [DataCategory]. */
+ companion object {
+ /**
+ * Creates a data category for persistence from a data category parsed from
+ * PackageManager app metadata.
+ */
+ fun fromAppMetadataDataCategory(
+ appMetadataDataCategory: AppMetadataDataCategory
+ ): DataCategory =
+ DataCategory(
+ appMetadataDataCategory.dataTypes.values.any {
+ it.purposeSet.contains(PURPOSE_ADVERTISING)
+ })
+ }
+ }
+
+ /** Data class representing a change of an app's safety label over time. */
+ data class AppSafetyLabelDiff(
+ val safetyLabelBefore: SafetyLabel,
+ val safetyLabelAfter: SafetyLabel
+ ) {
+ init {
+ require(safetyLabelBefore.appInfo == safetyLabelAfter.appInfo)
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetylabel/AppsSafetyLabelHistoryPersistence.kt b/PermissionController/src/com/android/permissioncontroller/safetylabel/AppsSafetyLabelHistoryPersistence.kt
new file mode 100644
index 000000000..9bb7e819f
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetylabel/AppsSafetyLabelHistoryPersistence.kt
@@ -0,0 +1,608 @@
+/*
+ * 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.permissioncontroller.safetylabel
+
+import android.content.Context
+import android.os.Build
+import android.provider.DeviceConfig
+import android.util.AtomicFile
+import android.util.Log
+import android.util.Xml
+import androidx.annotation.RequiresApi
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.AppInfo
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.AppSafetyLabelDiff
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.AppSafetyLabelHistory
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.DataCategory
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.DataLabel
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.SafetyLabel
+import java.io.File
+import java.io.FileNotFoundException
+import java.io.FileOutputStream
+import java.io.IOException
+import java.nio.charset.StandardCharsets
+import java.time.Instant
+import org.xmlpull.v1.XmlPullParser
+import org.xmlpull.v1.XmlPullParserException
+import org.xmlpull.v1.XmlSerializer
+
+/** Persists safety label history to disk and allows reading from and writing to this storage */
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+object AppsSafetyLabelHistoryPersistence {
+ private const val TAG_DATA_SHARED_MAP = "shared"
+ private const val TAG_DATA_SHARED_ENTRY = "entry"
+ private const val TAG_APP_INFO = "app-info"
+ private const val TAG_DATA_LABEL = "data-lbl"
+ private const val TAG_SAFETY_LABEL = "sfty-lbl"
+ private const val TAG_APP_SAFETY_LABEL_HISTORY = "app-hstry"
+ private const val TAG_APPS_SAFETY_LABEL_HISTORY = "apps-hstry"
+ private const val ATTRIBUTE_VERSION = "vrs"
+ private const val ATTRIBUTE_PACKAGE_NAME = "pkg-name"
+ private const val ATTRIBUTE_RECEIVED_AT = "rcvd"
+ private const val ATTRIBUTE_CATEGORY = "cat"
+ private const val ATTRIBUTE_CONTAINS_ADS = "ads"
+ private const val CURRENT_VERSION = 0
+ private const val INITIAL_VERSION = 0
+
+ /** The name of the file used to persist Safety Label history. */
+ private const val APPS_SAFETY_LABEL_HISTORY_PERSISTENCE_FILE_NAME =
+ "apps_safety_label_history_persistence.xml"
+ private val LOG_TAG = "AppsSafetyLabelHistoryPersistence".take(23)
+ private val readWriteLock = Any()
+
+ private var listeners = mutableSetOf<ChangeListener>()
+
+ /** Adds a listener to listen for changes to persisted safety labels. */
+ fun addListener(listener: ChangeListener) {
+ synchronized(readWriteLock) { listeners.add(listener) }
+ }
+
+ /** Removes a listener from listening for changes to persisted safety labels. */
+ fun removeListener(listener: ChangeListener) {
+ synchronized(readWriteLock) { listeners.remove(listener) }
+ }
+
+ /**
+ * Reads the provided file storing safety label history and returns the parsed
+ * [AppsSafetyLabelHistoryFileContent].
+ */
+ fun read(file: File): AppsSafetyLabelHistoryFileContent {
+ val parser = Xml.newPullParser()
+ try {
+ AtomicFile(file).openRead().let { inputStream ->
+ parser.setInput(inputStream, StandardCharsets.UTF_8.name())
+ return parser.parseHistoryFile()
+ }
+ } catch (e: FileNotFoundException) {
+ Log.e(LOG_TAG, "File not found: $file")
+ } catch (e: IOException) {
+ Log.e(
+ 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}")
+ }
+
+ return AppsSafetyLabelHistoryFileContent(appsSafetyLabelHistory = null, INITIAL_VERSION)
+ }
+
+ /** Returns the last updated time for each stored [AppSafetyLabelHistory]. */
+ fun getSafetyLabelsLastUpdatedTimes(file: File): Map<AppInfo, Instant> {
+ synchronized(readWriteLock) {
+ val appHistories =
+ read(file).appsSafetyLabelHistory?.appSafetyLabelHistories ?: return emptyMap()
+
+ val lastUpdatedTimes = mutableMapOf<AppInfo, Instant>()
+ for (appHistory in appHistories) {
+ val lastSafetyLabelReceiptTime: Instant? = appHistory.getLastReceiptTime()
+ if (lastSafetyLabelReceiptTime != null) {
+ lastUpdatedTimes[appHistory.appInfo] = lastSafetyLabelReceiptTime
+ }
+ }
+
+ return lastUpdatedTimes
+ }
+ }
+
+ /**
+ * Writes a new safety label to the provided file, if the provided safety label has changed from
+ * the last recorded.
+ */
+ fun recordSafetyLabel(safetyLabel: SafetyLabel, file: File) {
+ synchronized(readWriteLock) {
+ val currentAppsSafetyLabelHistory =
+ read(file).appsSafetyLabelHistory ?: AppsSafetyLabelHistory(listOf())
+ val appInfo = safetyLabel.appInfo
+ val currentHistories = currentAppsSafetyLabelHistory.appSafetyLabelHistories
+
+ val updatedAppsSafetyLabelHistory: AppsSafetyLabelHistory =
+ if (currentHistories.all { it.appInfo != appInfo }) {
+ 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)
+ }
+ }
+
+ /**
+ * Writes new safety labels to the provided file, if the provided safety labels have changed
+ * from the last recorded (when considered in order of [SafetyLabel.receivedAt]).
+ */
+ fun recordSafetyLabels(safetyLabelsToAdd: Set<SafetyLabel>, file: File) {
+ if (safetyLabelsToAdd.isEmpty()) return
+
+ synchronized(readWriteLock) {
+ val currentAppsSafetyLabelHistory =
+ read(file).appsSafetyLabelHistory ?: AppsSafetyLabelHistory(listOf())
+ val appInfoToOrderedSafetyLabels =
+ safetyLabelsToAdd
+ .groupBy { it.appInfo }
+ .mapValues { (_, safetyLabels) -> safetyLabels.sortedBy { it.receivedAt } }
+ val currentAppHistories = currentAppsSafetyLabelHistory.appSafetyLabelHistories
+ val newApps =
+ appInfoToOrderedSafetyLabels.keys - currentAppHistories.map { it.appInfo }.toSet()
+
+ // For apps that already have some safety labels persisted, add the provided safety
+ // labels to the history.
+ var updatedAppHistories: List<AppSafetyLabelHistory> =
+ currentAppHistories.map { currentAppHistory: AppSafetyLabelHistory ->
+ val safetyLabels = appInfoToOrderedSafetyLabels[currentAppHistory.appInfo]
+ if (safetyLabels != null) {
+ currentAppHistory.addSafetyLabelsIfChanged(safetyLabels)
+ } else {
+ currentAppHistory
+ }
+ }
+
+ // For apps that don't already have some safety labels persisted, add new
+ // AppSafetyLabelHistory instances for them with the provided safety labels.
+ updatedAppHistories =
+ updatedAppHistories.toMutableList().apply {
+ newApps.forEach { newAppInfo ->
+ val safetyLabelsForNewApp = appInfoToOrderedSafetyLabels[newAppInfo]
+ if (safetyLabelsForNewApp != null) {
+ add(AppSafetyLabelHistory(newAppInfo, safetyLabelsForNewApp))
+ }
+ }
+ }
+
+ write(file, AppsSafetyLabelHistory(updatedAppHistories))
+ }
+ }
+
+ /** Deletes stored safety labels for all apps in [appInfosToRemove]. */
+ fun deleteSafetyLabelsForApps(appInfosToRemove: Set<AppInfo>, file: File) {
+ if (appInfosToRemove.isEmpty()) return
+
+ synchronized(readWriteLock) {
+ val currentAppsSafetyLabelHistory =
+ read(file).appsSafetyLabelHistory ?: AppsSafetyLabelHistory(listOf())
+ val historiesWithAppsRemoved =
+ currentAppsSafetyLabelHistory.appSafetyLabelHistories.filter {
+ it.appInfo !in appInfosToRemove
+ }
+
+ write(file, AppsSafetyLabelHistory(historiesWithAppsRemoved))
+ }
+ }
+
+ /**
+ * Deletes stored safety labels so that there is at most one safety label for each app with
+ * [SafetyLabel.receivedAt] earlier that [startTime].
+ */
+ fun deleteSafetyLabelsOlderThan(startTime: Instant, file: File) {
+ synchronized(readWriteLock) {
+ val currentAppsSafetyLabelHistory =
+ read(file).appsSafetyLabelHistory ?: AppsSafetyLabelHistory(listOf())
+ val updatedAppHistories =
+ currentAppsSafetyLabelHistory.appSafetyLabelHistories.map { appHistory ->
+ val history = appHistory.safetyLabelHistory
+ // Retrieve the last safety label that was received prior to startTime.
+ val last =
+ history.indexOfLast { safetyLabels -> safetyLabels.receivedAt <= startTime }
+ if (last <= 0) {
+ // If there is only one or no safety labels received prior to startTime,
+ // then return the history as is.
+ appHistory
+ } else {
+ // Else, discard all safety labels other than the last safety label prior
+ // 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))
+ }
+ }
+
+ write(file, AppsSafetyLabelHistory(updatedAppHistories))
+ }
+ }
+
+ /**
+ * Serializes and writes the provided [AppsSafetyLabelHistory] with [CURRENT_VERSION] schema to
+ * the provided file.
+ */
+ fun write(file: File, appsSafetyLabelHistory: AppsSafetyLabelHistory) {
+ write(file, AppsSafetyLabelHistoryFileContent(appsSafetyLabelHistory, CURRENT_VERSION))
+ }
+
+ /**
+ * Serializes and writes the provided [AppsSafetyLabelHistoryFileContent] to the provided file.
+ */
+ fun write(file: File, fileContent: AppsSafetyLabelHistoryFileContent) {
+ val atomicFile = AtomicFile(file)
+ var outputStream: FileOutputStream? = null
+
+ try {
+ outputStream = atomicFile.startWrite()
+ val serializer = Xml.newSerializer()
+ serializer.setOutput(outputStream, StandardCharsets.UTF_8.name())
+ serializer.startDocument(null, true)
+ serializer.serializeAllAppSafetyLabelHistory(fileContent)
+ serializer.endDocument()
+ atomicFile.finishWrite(outputStream)
+ listeners.forEach { it.onSafetyLabelHistoryChanged() }
+ } catch (e: Exception) {
+ Log.i(
+ LOG_TAG, "Failed to write to $file. Previous version of file will be restored.", e)
+ atomicFile.failWrite(outputStream)
+ } finally {
+ try {
+ outputStream?.close()
+ } catch (e: Exception) {
+ Log.e(LOG_TAG, "Failed to close $file.", e)
+ }
+ }
+ }
+
+ /** Reads the provided history file and returns all safety label changes since [startTime]. */
+ fun getAppSafetyLabelDiffs(startTime: Instant, file: File): List<AppSafetyLabelDiff> {
+ val currentAppsSafetyLabelHistory =
+ read(file).appsSafetyLabelHistory ?: AppsSafetyLabelHistory(listOf())
+
+ 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))
+ null
+ else AppSafetyLabelDiff(before, after)
+ }
+ }
+
+ /** Clears the file. */
+ fun clear(file: File) {
+ AtomicFile(file).delete()
+ }
+
+ /** Returns the file persisting safety label history for installed apps. */
+ fun getSafetyLabelHistoryFile(context: Context): File =
+ File(context.filesDir, APPS_SAFETY_LABEL_HISTORY_PERSISTENCE_FILE_NAME)
+
+ private fun AppSafetyLabelHistory.getLastReceiptTime(): Instant? =
+ this.safetyLabelHistory.lastOrNull()?.receivedAt
+
+ private fun XmlPullParser.parseHistoryFile(): AppsSafetyLabelHistoryFileContent {
+ if (eventType != XmlPullParser.START_DOCUMENT) {
+ throw IllegalArgumentException()
+ }
+ nextTag()
+
+ val appsSafetyLabelHistory = parseAppsSafetyLabelHistory()
+
+ while (eventType == XmlPullParser.TEXT && isWhitespace) {
+ next()
+ }
+ if (eventType != XmlPullParser.END_DOCUMENT) {
+ throw IllegalArgumentException("Unexpected extra element")
+ }
+
+ return appsSafetyLabelHistory
+ }
+
+ private fun XmlPullParser.parseAppsSafetyLabelHistory(): AppsSafetyLabelHistoryFileContent {
+ checkTagStart(TAG_APPS_SAFETY_LABEL_HISTORY)
+ var version: Int? = null
+ for (i in 0 until attributeCount) {
+ when (getAttributeName(i)) {
+ ATTRIBUTE_VERSION -> version = getAttributeValue(i).toInt()
+ else ->
+ throw IllegalArgumentException(
+ "Unexpected attribute ${getAttributeName(i)} in tag" +
+ " $TAG_APPS_SAFETY_LABEL_HISTORY")
+ }
+ }
+ if (version == null) {
+ version = INITIAL_VERSION
+ Log.w(LOG_TAG, "Missing $ATTRIBUTE_VERSION in $TAG_APPS_SAFETY_LABEL_HISTORY")
+ }
+ nextTag()
+
+ val appSafetyLabelHistories = mutableListOf<AppSafetyLabelHistory>()
+ while (eventType == XmlPullParser.START_TAG && name == TAG_APP_SAFETY_LABEL_HISTORY) {
+ appSafetyLabelHistories.add(parseAppSafetyLabelHistory())
+ }
+
+ checkTagEnd(TAG_APPS_SAFETY_LABEL_HISTORY)
+ next()
+
+ return AppsSafetyLabelHistoryFileContent(
+ AppsSafetyLabelHistory(appSafetyLabelHistories), version)
+ }
+
+ private fun XmlPullParser.parseAppSafetyLabelHistory(): AppSafetyLabelHistory {
+ checkTagStart(TAG_APP_SAFETY_LABEL_HISTORY)
+ nextTag()
+
+ val appInfo = parseAppInfo()
+
+ val safetyLabels = mutableListOf<SafetyLabel>()
+ while (eventType == XmlPullParser.START_TAG && name == TAG_SAFETY_LABEL) {
+ safetyLabels.add(parseSafetyLabel(appInfo))
+ }
+
+ checkTagEnd(TAG_APP_SAFETY_LABEL_HISTORY)
+ nextTag()
+
+ return AppSafetyLabelHistory(appInfo, safetyLabels)
+ }
+
+ private fun XmlPullParser.parseSafetyLabel(appInfo: AppInfo): SafetyLabel {
+ checkTagStart(TAG_SAFETY_LABEL)
+
+ var receivedAt: Instant? = null
+ for (i in 0 until attributeCount) {
+ when (getAttributeName(i)) {
+ ATTRIBUTE_RECEIVED_AT -> receivedAt = parseInstant(getAttributeValue(i))
+ else ->
+ throw IllegalArgumentException(
+ "Unexpected attribute ${getAttributeName(i)} in tag $TAG_SAFETY_LABEL")
+ }
+ }
+ if (receivedAt == null) {
+ throw IllegalArgumentException("Missing $ATTRIBUTE_RECEIVED_AT in $TAG_SAFETY_LABEL")
+ }
+ nextTag()
+
+ val dataLabel = parseDataLabel()
+
+ checkTagEnd(TAG_SAFETY_LABEL)
+ nextTag()
+
+ return SafetyLabel(appInfo, receivedAt, dataLabel)
+ }
+
+ private fun XmlPullParser.parseDataLabel(): DataLabel {
+ checkTagStart(TAG_DATA_LABEL)
+ nextTag()
+
+ val dataSharing = parseDataShared()
+
+ checkTagEnd(TAG_DATA_LABEL)
+ nextTag()
+
+ return DataLabel(dataSharing)
+ }
+
+ private fun XmlPullParser.parseDataShared(): Map<String, DataCategory> {
+ checkTagStart(TAG_DATA_SHARED_MAP)
+ nextTag()
+
+ val sharedCategories = mutableListOf<Pair<String, DataCategory>>()
+ while (eventType == XmlPullParser.START_TAG && name == TAG_DATA_SHARED_ENTRY) {
+ sharedCategories.add(parseDataSharedEntry())
+ }
+
+ checkTagEnd(TAG_DATA_SHARED_MAP)
+ nextTag()
+
+ return sharedCategories.associate { it.first to it.second }
+ }
+
+ private fun XmlPullParser.parseDataSharedEntry(): Pair<String, DataCategory> {
+ checkTagStart(TAG_DATA_SHARED_ENTRY)
+ var category: String? = null
+ var hasAds: Boolean? = null
+ for (i in 0 until attributeCount) {
+ when (getAttributeName(i)) {
+ ATTRIBUTE_CATEGORY -> category = getAttributeValue(i)
+ ATTRIBUTE_CONTAINS_ADS -> hasAds = getAttributeValue(i).toBoolean()
+ else ->
+ throw IllegalArgumentException(
+ "Unexpected attribute ${getAttributeName(i)} in tag $TAG_DATA_SHARED_ENTRY")
+ }
+ }
+ if (category == null) {
+ throw IllegalArgumentException("Missing $ATTRIBUTE_CATEGORY in $TAG_DATA_SHARED_ENTRY")
+ }
+ if (hasAds == null) {
+ throw IllegalArgumentException(
+ "Missing $ATTRIBUTE_CONTAINS_ADS in $TAG_DATA_SHARED_ENTRY")
+ }
+ nextTag()
+
+ checkTagEnd(TAG_DATA_SHARED_ENTRY)
+ nextTag()
+
+ return category to DataCategory(hasAds)
+ }
+
+ private fun XmlPullParser.parseAppInfo(): AppInfo {
+ checkTagStart(TAG_APP_INFO)
+ var packageName: String? = null
+ for (i in 0 until attributeCount) {
+ when (getAttributeName(i)) {
+ ATTRIBUTE_PACKAGE_NAME -> packageName = getAttributeValue(i)
+ else ->
+ throw IllegalArgumentException(
+ "Unexpected attribute ${getAttributeName(i)} in tag $TAG_APP_INFO")
+ }
+ }
+ if (packageName == null) {
+ throw IllegalArgumentException("Missing $ATTRIBUTE_PACKAGE_NAME in $TAG_APP_INFO")
+ }
+
+ nextTag()
+ checkTagEnd(TAG_APP_INFO)
+ nextTag()
+ return AppInfo(packageName)
+ }
+
+ private fun XmlPullParser.checkTagStart(tag: String) {
+ check(eventType == XmlPullParser.START_TAG && tag == name)
+ }
+
+ private fun XmlPullParser.checkTagEnd(tag: String) {
+ check(eventType == XmlPullParser.END_TAG && tag == name)
+ }
+
+ private fun parseInstant(value: String): Instant {
+ return try {
+ Instant.ofEpochMilli(value.toLong())
+ } catch (e: Exception) {
+ throw IllegalArgumentException("Could not parse $value as Instant")
+ }
+ }
+
+ private fun XmlSerializer.serializeAllAppSafetyLabelHistory(
+ fileContent: AppsSafetyLabelHistoryFileContent
+ ) {
+ startTag(null, TAG_APPS_SAFETY_LABEL_HISTORY)
+ attribute(null, ATTRIBUTE_VERSION, fileContent.version.toString())
+ fileContent.appsSafetyLabelHistory?.appSafetyLabelHistories?.forEach {
+ serializeAppSafetyLabelHistory(it)
+ }
+ endTag(null, TAG_APPS_SAFETY_LABEL_HISTORY)
+ }
+
+ private fun XmlSerializer.serializeAppSafetyLabelHistory(
+ appSafetyLabelHistory: AppSafetyLabelHistory
+ ) {
+ startTag(null, TAG_APP_SAFETY_LABEL_HISTORY)
+ serializeAppInfo(appSafetyLabelHistory.appInfo)
+ appSafetyLabelHistory.safetyLabelHistory.forEach { serializeSafetyLabel(it) }
+ endTag(null, TAG_APP_SAFETY_LABEL_HISTORY)
+ }
+
+ private fun XmlSerializer.serializeAppInfo(appInfo: AppInfo) {
+ startTag(null, TAG_APP_INFO)
+ attribute(null, ATTRIBUTE_PACKAGE_NAME, appInfo.packageName)
+ endTag(null, TAG_APP_INFO)
+ }
+
+ private fun XmlSerializer.serializeSafetyLabel(safetyLabel: SafetyLabel) {
+ startTag(null, TAG_SAFETY_LABEL)
+ attribute(null, ATTRIBUTE_RECEIVED_AT, safetyLabel.receivedAt.toEpochMilli().toString())
+ serializeDataLabel(safetyLabel.dataLabel)
+ endTag(null, TAG_SAFETY_LABEL)
+ }
+
+ private fun XmlSerializer.serializeDataLabel(dataLabel: DataLabel) {
+ startTag(null, TAG_DATA_LABEL)
+ serializeDataSharedMap(dataLabel.dataShared)
+ endTag(null, TAG_DATA_LABEL)
+ }
+
+ private fun XmlSerializer.serializeDataSharedMap(dataShared: Map<String, DataCategory>) {
+ startTag(null, TAG_DATA_SHARED_MAP)
+ dataShared.entries.forEach { serializeDataSharedEntry(it) }
+ endTag(null, TAG_DATA_SHARED_MAP)
+ }
+
+ private fun XmlSerializer.serializeDataSharedEntry(
+ dataSharedEntry: Map.Entry<String, DataCategory>
+ ) {
+ startTag(null, TAG_DATA_SHARED_ENTRY)
+ attribute(null, ATTRIBUTE_CATEGORY, dataSharedEntry.key)
+ attribute(
+ null,
+ ATTRIBUTE_CONTAINS_ADS,
+ dataSharedEntry.value.containsAdvertisingPurpose.toString())
+ endTag(null, TAG_DATA_SHARED_ENTRY)
+ }
+
+ private fun AppSafetyLabelHistory.addSafetyLabelIfChanged(
+ safetyLabel: SafetyLabel
+ ): AppSafetyLabelHistory {
+ val latestSafetyLabel = safetyLabelHistory.lastOrNull()
+ return if (latestSafetyLabel?.dataLabel == safetyLabel.dataLabel) this
+ else this.withSafetyLabel(safetyLabel, getMaxSafetyLabelsToPersist())
+ }
+
+ private fun AppSafetyLabelHistory.addSafetyLabelsIfChanged(
+ safetyLabels: List<SafetyLabel>
+ ): AppSafetyLabelHistory {
+ var updatedAppHistory = this
+ val maxSafetyLabels = getMaxSafetyLabelsToPersist()
+ for (safetyLabel in safetyLabels) {
+ val latestSafetyLabel = updatedAppHistory.safetyLabelHistory.lastOrNull()
+ if (latestSafetyLabel?.dataLabel != safetyLabel.dataLabel) {
+ updatedAppHistory = updatedAppHistory.withSafetyLabel(safetyLabel, maxSafetyLabels)
+ }
+ }
+
+ return updatedAppHistory
+ }
+
+ private fun AppSafetyLabelHistory.getLatestSafetyLabel() = safetyLabelHistory.lastOrNull()
+
+ /**
+ * Return the safety label known to be the current safety label for the app at the provided
+ * time, if available in the history.
+ */
+ private fun AppSafetyLabelHistory.getSafetyLabelAt(startTime: Instant) =
+ safetyLabelHistory.lastOrNull {
+ // the last received safety label before or at startTime
+ it.receivedAt.isBefore(startTime) || it.receivedAt == startTime
+ }
+ ?: // the first safety label received after startTime, as a fallback
+ safetyLabelHistory.firstOrNull { it.receivedAt.isAfter(startTime) }
+
+ private const val PROPERTY_MAX_SAFETY_LABELS_PERSISTED_PER_APP =
+ "max_safety_labels_persisted_per_app"
+
+ /**
+ * Returns the maximum number of safety labels to persist per app.
+ *
+ * Note that this will be checked at the time of adding a new safety label to storage for an
+ * app; simply changing this Device Config property will not result in any storage being purged.
+ */
+ private fun getMaxSafetyLabelsToPersist() =
+ DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_MAX_SAFETY_LABELS_PERSISTED_PER_APP, 20)
+
+ /** An interface to listen to changes to persisted safety labels. */
+ interface ChangeListener {
+ /** Callback when the persisted safety labels are changed. */
+ fun onSafetyLabelHistoryChanged()
+ }
+
+ /** Data class to hold an [AppsSafetyLabelHistory] along with the file schema version. */
+ data class AppsSafetyLabelHistoryFileContent(
+ val appsSafetyLabelHistory: AppsSafetyLabelHistory?,
+ val version: Int,
+ )
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetylabel/SafetyLabelChangedBroadcastReceiver.kt b/PermissionController/src/com/android/permissioncontroller/safetylabel/SafetyLabelChangedBroadcastReceiver.kt
new file mode 100644
index 000000000..99f4adb02
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetylabel/SafetyLabelChangedBroadcastReceiver.kt
@@ -0,0 +1,230 @@
+/*
+ * 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.safetylabel
+
+import android.Manifest
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.Intent.ACTION_PACKAGE_ADDED
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Process
+import android.os.UserHandle
+import android.os.UserManager
+import android.util.Log
+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.v34.LightInstallSourceInfoLiveData
+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.Utils
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.SafetyLabel as SafetyLabelForPersistence
+import java.time.Instant
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
+
+/**
+ * Listens for package installs and updates, and updates the [AppsSafetyLabelHistoryPersistence] if
+ * the app safety label has changed.
+ */
+// TODO(b/264884476): Remove excess logging from this class once feature is stable.
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+class SafetyLabelChangedBroadcastReceiver : BroadcastReceiver() {
+
+ override fun onReceive(context: Context, intent: Intent) {
+ if (!KotlinUtils.isSafetyLabelChangeNotificationsEnabled(context)) {
+ return
+ }
+
+ val packageChangeEvent = getPackageChangeEvent(intent)
+ if (!(packageChangeEvent == PackageChangeEvent.NEW_INSTALL ||
+ packageChangeEvent == PackageChangeEvent.UPDATE)) {
+ return
+ }
+
+ val packageName = intent.data?.schemeSpecificPart
+ if (packageName == null) {
+ Log.w(TAG, "Received broadcast without package name")
+ return
+ }
+
+ val currentUser = Process.myUserHandle()
+ if (DEBUG) {
+ Log.i(
+ TAG,
+ "received broadcast packageName: $packageName, current user: $currentUser," +
+ " packageChangeEvent: $packageChangeEvent, intent user:" +
+ " ${intent.getParcelableExtra(Intent.EXTRA_USER, UserHandle::class.java)
+ ?: currentUser}")
+ }
+ val userManager = Utils.getSystemServiceSafe(context, UserManager::class.java)
+ if (userManager.isProfile) {
+ forwardBroadcastToParentUser(context, userManager, intent)
+ return
+ }
+
+ val user: UserHandle =
+ intent.getParcelableExtra(Intent.EXTRA_USER, UserHandle::class.java) ?: currentUser
+
+ val pendingResult: PendingResult = goAsync()
+
+ GlobalScope.launch(Dispatchers.Main) {
+ processPackageChange(context, packageName, user)
+ pendingResult.finish()
+ }
+ }
+
+ /** Processes the package change for the given package and user. */
+ private suspend fun processPackageChange(
+ context: Context,
+ packageName: String,
+ user: UserHandle,
+ ) {
+ val lightPackageInfo =
+ LightPackageInfoLiveData[Pair(packageName, user)].getInitializedValue() ?: return
+ if (!isAppRequestingLocationPermission(lightPackageInfo)) {
+ return
+ }
+
+ if (!isSafetyLabelSupported(Pair(packageName, user))) {
+ return
+ }
+ writeSafetyLabel(context, lightPackageInfo, user)
+ }
+
+ /**
+ * Retrieves and writes the safety label for a package to the safety labels store.
+ *
+ * As I/O operations are invoked, we run this method on the main thread.
+ */
+ @MainThread
+ private fun writeSafetyLabel(
+ context: Context,
+ lightPackageInfo: LightPackageInfo,
+ user: UserHandle,
+ ) {
+ val packageName = lightPackageInfo.packageName
+ if (DEBUG) {
+ Log.i(
+ TAG,
+ "writeSafetyLabel called for packageName: $packageName, currentUser:" +
+ " ${Process.myUserHandle()}")
+ }
+
+ // Get the context for the user in which the app is installed.
+ val userContext =
+ if (user == Process.myUserHandle()) {
+ context
+ } else {
+ context.createContextAsUser(user, 0)
+ }
+ val appMetadataBundle =
+ try {
+ userContext.packageManager.getAppMetadata(packageName)
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Package $packageName not found while retrieving app metadata")
+ return
+ }
+
+ if (DEBUG) {
+ Log.i(TAG, "appMetadataBundle $appMetadataBundle")
+ }
+ val safetyLabel: AppMetadataSafetyLabel =
+ AppMetadataSafetyLabel.getSafetyLabelFromMetadata(appMetadataBundle) ?: return
+
+ val receivedAtMs: Long = lightPackageInfo.lastUpdateTime
+
+ val safetyLabelForPersistence: SafetyLabelForPersistence =
+ AppsSafetyLabelHistory.SafetyLabel.extractLocationSharingSafetyLabel(
+ packageName, Instant.ofEpochMilli(receivedAtMs), safetyLabel)
+ val historyFile = AppsSafetyLabelHistoryPersistence.getSafetyLabelHistoryFile(context)
+
+ AppsSafetyLabelHistoryPersistence.recordSafetyLabel(safetyLabelForPersistence, historyFile)
+ }
+
+ private fun getPackageChangeEvent(intent: Intent): PackageChangeEvent {
+ val action = intent.action
+ val replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)
+
+ return if (isPackageAddedBroadcast(action) && replacing) {
+ PackageChangeEvent.UPDATE
+ } else if (isPackageAddedBroadcast(action)) {
+ PackageChangeEvent.NEW_INSTALL
+ } else {
+ PackageChangeEvent.INSIGNIFICANT
+ }
+ }
+
+ /** Companion object for [SafetyLabelChangedBroadcastReceiver]. */
+ companion object {
+ private val TAG = SafetyLabelChangedBroadcastReceiver::class.simpleName
+ private const val ACTION_PACKAGE_ADDED_PERMISSIONCONTROLLER_FORWARDED =
+ "com.android.permissioncontroller.action.PACKAGE_ADDED_PERMISSIONCONTROLLER_FORWARDED"
+ private const val DEBUG = true
+ private val LOCATION_PERMISSIONS =
+ PermissionMapping.getPlatformPermissionNamesOfGroup(Manifest.permission_group.LOCATION)
+
+ private fun isAppRequestingLocationPermission(lightPackageInfo: LightPackageInfo): Boolean {
+ return lightPackageInfo.requestedPermissions.any { LOCATION_PERMISSIONS.contains(it) }
+ }
+
+ private suspend fun isSafetyLabelSupported(packageUser: Pair<String, UserHandle>): Boolean {
+ val lightInstallSourceInfo =
+ LightInstallSourceInfoLiveData[packageUser].getInitializedValue()
+ return lightInstallSourceInfo.supportsSafetyLabel
+ }
+
+ private fun isPackageAddedBroadcast(intentAction: String?) =
+ intentAction == ACTION_PACKAGE_ADDED ||
+ intentAction == ACTION_PACKAGE_ADDED_PERMISSIONCONTROLLER_FORWARDED
+
+ private fun forwardBroadcastToParentUser(
+ context: Context,
+ userManager: UserManager,
+ intent: Intent
+ ) {
+ val currentUser = Process.myUserHandle()
+ val profileParent = userManager.getProfileParent(currentUser)
+ if (profileParent == null) {
+ Log.w(TAG, "Could not find profile parent for $currentUser")
+ return
+ }
+
+ Log.i(
+ TAG,
+ "Forwarding intent from current user: $currentUser to profile parent" +
+ " $profileParent")
+ context.sendBroadcastAsUser(
+ Intent(intent)
+ .setAction(ACTION_PACKAGE_ADDED_PERMISSIONCONTROLLER_FORWARDED)
+ .putExtra(Intent.EXTRA_USER, currentUser),
+ profileParent)
+ }
+
+ /** Types of package change events. */
+ enum class PackageChangeEvent {
+ INSIGNIFICANT,
+ NEW_INSTALL,
+ UPDATE,
+ }
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetylabel/TEST_MAPPING b/PermissionController/src/com/android/permissioncontroller/safetylabel/TEST_MAPPING
new file mode 100644
index 000000000..b6e659353
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/safetylabel/TEST_MAPPING
@@ -0,0 +1,27 @@
+{
+ "presubmit": [
+ {
+ "name": "PermissionControllerMockingTests",
+ "options": [
+ {
+ "include-filter": "com.android.permissioncontroller.tests.mocking.safetylabel"
+ }
+ ]
+ }
+ ],
+ "presubmit-large": [
+ {
+ "name": "CtsPermission3TestCases",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ }
+ ]
+ }
+ ],
+ "mainline-presubmit": [
+ {
+ "name": "CtsPermission3TestCases[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 0cc355daa..78c767f1d 100644
--- a/PermissionController/tests/inprocess/Android.bp
+++ b/PermissionController/tests/inprocess/Android.bp
@@ -33,7 +33,10 @@ android_test {
target_sdk_version: "30",
min_sdk_version: "30",
- srcs: ["src/**/*.kt"],
+ srcs: [
+ "src/**/*.kt",
+ "src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompatTest.java",
+ ],
libs: [
"android.test.base",
@@ -46,6 +49,7 @@ android_test {
"androidx.test.ext.junit",
"androidx.test.uiautomator_uiautomator",
"compatibility-device-util-axt",
+ "kotlin-test",
"permission-test-util-lib",
],
diff --git a/PermissionController/tests/inprocess/AndroidTest.xml b/PermissionController/tests/inprocess/AndroidTest.xml
index 403e320a3..8971a7270 100644
--- a/PermissionController/tests/inprocess/AndroidTest.xml
+++ b/PermissionController/tests/inprocess/AndroidTest.xml
@@ -23,7 +23,7 @@
<object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
<!-- Install test -->
- <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="test-file-name" value="PermissionControllerInProcessTests.apk" />
<option name="cleanup-apks" value="true" />
</target_preparer>
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 a1012cde6..1dd13be2a 100644
--- a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/GetPermissionGroupInfoTest.kt
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/GetPermissionGroupInfoTest.kt
@@ -20,7 +20,7 @@ import android.content.Context
import android.os.Build
import androidx.test.filters.SdkSuppress
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import java.util.concurrent.CountDownLatch
@@ -34,7 +34,7 @@ class GetPermissionGroupInfoTest {
@Test
fun assertAllPlatformPermGroupPermListsMatch() {
- val groups = Utils.getPlatformPermissionGroups()
+ val groups = PermissionMapping.getPlatformPermissionGroups()
var returnedPerms: List<String>? = null
for (group in groups) {
val latch = CountDownLatch(1)
@@ -44,15 +44,15 @@ class GetPermissionGroupInfoTest {
}
latch.await(timeoutMs, TimeUnit.MILLISECONDS)
assertThat(returnedPerms).isEqualTo(
- Utils.getPlatformPermissionNamesOfGroup(group))
+ PermissionMapping.getPlatformPermissionNamesOfGroup(group))
}
}
@Test
fun assertAllPlatformPermGroupsMatch() {
- val groups = Utils.getPlatformPermissionGroups()
+ val groups = PermissionMapping.getPlatformPermissionGroups()
for (group in groups) {
- val perms = Utils.getPlatformPermissionNamesOfGroup(group)
+ val perms = PermissionMapping.getPlatformPermissionNamesOfGroup(group)
for (permName in perms) {
var permGroup: String? = null
val latch = CountDownLatch(1)
@@ -61,7 +61,8 @@ class GetPermissionGroupInfoTest {
latch.countDown()
}
latch.await(timeoutMs, TimeUnit.MILLISECONDS)
- assertThat(permGroup).isEqualTo(Utils.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
new file mode 100644
index 000000000..b4b18dbbe
--- /dev/null
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompatTest.java
@@ -0,0 +1,258 @@
+/*
+ * 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/util/ArrayUtilsTest.kt b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/ArrayUtilsTest.kt
new file mode 100644
index 000000000..305dcdfb7
--- /dev/null
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/ArrayUtilsTest.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.permission.util
+
+import com.android.permissioncontroller.permission.utils.ArrayUtils
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class ArrayUtilsTest {
+ @Test
+ fun appendString_appendToNull_returnsArrayWithString() {
+ assertThat(ArrayUtils.appendString(null, TEST_STRING))
+ .isEqualTo(arrayOf(TEST_STRING))
+ }
+
+ @Test
+ fun appendString_appendToNull_returnsArrayWithNull() {
+ val result = ArrayUtils.appendString(null, null)
+ assertThat(result.size).isEqualTo(1)
+ assertThat(result[0]).isEqualTo(null)
+ }
+
+ @Test
+ fun appendString_duplicatedString_returnsArray() {
+ val cur = arrayOf("a", "b", TEST_STRING)
+ assertThat(ArrayUtils.appendString(cur, TEST_STRING)).isEqualTo(cur)
+ }
+
+ @Test
+ fun appendString_appendNull_returnsArray() {
+ val cur = arrayOf("a", "b", null)
+ assertThat(ArrayUtils.appendString(cur, null)).isEqualTo(cur)
+ }
+
+ @Test
+ fun appendString_appendToEmptyArray_returnsArrayWithNewString() {
+ val cur = arrayOf<String>()
+ val new = arrayOf(TEST_STRING)
+ assertThat(ArrayUtils.appendString(cur, TEST_STRING)).isEqualTo(new)
+ }
+
+ @Test
+ fun appendString_appendNullToEmptyArray_returnsArrayWithNewString() {
+ val cur = arrayOf<String>()
+ val result = ArrayUtils.appendString(cur, null)
+ assertThat(result.size).isEqualTo(1)
+ assertThat(result[0]).isNull()
+ }
+
+ @Test
+ fun appendString_appendNewString() {
+ val cur = arrayOf("old test")
+ val new = arrayOf("old test", TEST_STRING)
+ assertThat(ArrayUtils.appendString(cur, TEST_STRING)).isEqualTo(new)
+ }
+
+ companion object {
+ private const val TEST_STRING = "test"
+ }
+}
diff --git a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/CollectionUtilsTest.kt b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/CollectionUtilsTest.kt
new file mode 100644
index 000000000..3d4bd28ff
--- /dev/null
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/CollectionUtilsTest.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.util
+
+import com.android.permissioncontroller.permission.utils.CollectionUtils
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class CollectionUtilsTest {
+ @Test
+ fun testContains_true() {
+ val byteArrays = setOf(TEST_BYTE_ARRAY_1, TEST_BYTE_ARRAY_2, TEST_BYTE_ARRAY_3)
+
+ assertThat(CollectionUtils.contains(byteArrays, TEST_BYTE_ARRAY_1)).isTrue()
+ }
+
+ @Test
+ fun testContains_false() {
+ val byteArrays = setOf(TEST_BYTE_ARRAY_1, TEST_BYTE_ARRAY_2, TEST_BYTE_ARRAY_3)
+
+ assertThat(CollectionUtils.contains(byteArrays, TEST_BYTE_ARRAY_4)).isFalse()
+ }
+
+ @Test
+ fun testContainsSubset_true() {
+ val byteArrays = setOf(TEST_BYTE_ARRAY_1, TEST_BYTE_ARRAY_2, TEST_BYTE_ARRAY_3)
+ val otherByteArrays = setOf(TEST_BYTE_ARRAY_2, TEST_BYTE_ARRAY_3)
+
+ assertThat(CollectionUtils.containsSubset(byteArrays, otherByteArrays)).isTrue()
+ }
+
+ @Test
+ fun testContainsSubset_false() {
+ val byteArrays = setOf(TEST_BYTE_ARRAY_1, TEST_BYTE_ARRAY_2, TEST_BYTE_ARRAY_3)
+ val otherByteArrays = setOf(TEST_BYTE_ARRAY_3, TEST_BYTE_ARRAY_4)
+
+ assertThat(CollectionUtils.containsSubset(byteArrays, otherByteArrays)).isFalse()
+ }
+
+ companion object {
+ private val TEST_BYTE_ARRAY_1 = "I".toByteArray()
+ private val TEST_BYTE_ARRAY_2 = "love".toByteArray()
+ private val TEST_BYTE_ARRAY_3 = "Android".toByteArray()
+ private val TEST_BYTE_ARRAY_4 = "Hello".toByteArray()
+ }
+}
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
new file mode 100644
index 000000000..8f54da579
--- /dev/null
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/KotlinUtilsTest.kt
@@ -0,0 +1,165 @@
+/*
+ * 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.util
+
+import android.Manifest.permission.READ_MEDIA_IMAGES
+import android.Manifest.permission.READ_MEDIA_VIDEO
+import android.content.Context
+import android.content.Intent
+import android.content.Intent.ACTION_SHOW_APP_INFO
+import android.content.Intent.EXTRA_PACKAGE_NAME
+import android.content.pm.ActivityInfo
+import android.content.pm.PackageManager
+import android.content.pm.ResolveInfo
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.ColorFilter
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+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 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].
+ */
+@RunWith(AndroidJUnit4::class)
+class KotlinUtilsTest {
+ private val targetContext = InstrumentationRegistry.getInstrumentation().targetContext
+
+ @Test
+ fun convertToBitmap_argb888BitmapDrawable_returnsSameBitmap() {
+ val bitmap = Bitmap.createBitmap(/* width= */ 5, /* height= */ 10, Bitmap.Config.ARGB_8888)
+ val drawable = BitmapDrawable(targetContext.resources, bitmap)
+
+ assertThat(KotlinUtils.convertToBitmap(drawable).sameAs(bitmap)).isTrue()
+ }
+
+ @Test
+ fun convertToBitmap_noIntrinsicSize_throws() {
+ val drawable = FakeDrawable(intrinsicSize = 0)
+ assertFailsWith<IllegalArgumentException> { KotlinUtils.convertToBitmap(drawable) }
+ }
+
+ class FakeDrawable(private val intrinsicSize: Int) : Drawable() {
+ override fun getIntrinsicWidth() = intrinsicSize
+ override fun getIntrinsicHeight() = intrinsicSize
+
+ override fun draw(canvas: Canvas) = Unit // no-op
+ override fun getOpacity() = throw UnsupportedOperationException()
+ override fun setAlpha(alpha: Int) = throw UnsupportedOperationException()
+ override fun setColorFilter(colorFilter: ColorFilter?) =
+ throw UnsupportedOperationException()
+ }
+
+ @Test
+ fun getAppStoreIntent_returnsResolvedIntent() {
+ val installerPackage = "installer"
+ val installerActivity = "activity"
+ val appPackage = "app"
+ val mockContext = mock(Context::class.java)
+ val mockPackageManager = mock(PackageManager::class.java)
+ 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
+ }
+ })
+
+ val intent = KotlinUtils.getAppStoreIntent(mockContext, installerPackage, appPackage)
+
+ assertThat(intent).isNotNull()
+ with (intent!!) {
+ assertThat(action).isEqualTo(ACTION_SHOW_APP_INFO)
+ assertThat(component?.packageName).isEqualTo(installerPackage)
+ assertThat(component?.className).isEqualTo(installerActivity)
+ }
+ }
+
+ @Test
+ fun getAppStoreIntent_returnsAppPackageInExtras() {
+ val appPackage = "app"
+ 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 = ""
+ }
+ })
+
+ val intent = KotlinUtils.getAppStoreIntent(mockContext, "com.installer", appPackage)
+
+ assertThat(intent).isNotNull()
+ assertThat(intent?.extras?.getString(EXTRA_PACKAGE_NAME)).isEqualTo(appPackage)
+ }
+
+ @Test
+ fun getAppStoreIntent_returnsNullWhenInstallerNotResolved() {
+ val mockContext = mock(Context::class.java)
+ whenever(mockContext.packageManager).thenReturn(mock(PackageManager::class.java))
+ // Un-stubbed activity resolution will return null.
+
+ assertThat(KotlinUtils.getAppStoreIntent(mockContext, "com.installer", "com.app")).isNull()
+ }
+
+ @Test
+ fun getMimeTypeForPermissions_onlyReadMediaImages_returnsImage() {
+ assertThat(KotlinUtils.getMimeTypeForPermissions(listOf(READ_MEDIA_IMAGES, "read memes")))
+ .isEqualTo("image/*")
+ }
+
+ @Test
+ fun getMimeTypeForPermissions_onlyReadMediaVideo_returnsVideo() {
+ assertThat(KotlinUtils.getMimeTypeForPermissions(listOf("write memes", READ_MEDIA_VIDEO)))
+ .isEqualTo("video/*")
+ }
+
+ @Test
+ fun getMimeTypeForPermissions_bothReadMediaPermissions_returnsNull() {
+ assertThat(
+ KotlinUtils.getMimeTypeForPermissions(listOf(READ_MEDIA_IMAGES, READ_MEDIA_VIDEO)))
+ .isNull()
+ }
+
+ @Test
+ fun getMimeTypeForPermissions_noReadMediaPermissions_returnsNull() {
+ assertThat(KotlinUtils.getMimeTypeForPermissions(listOf("amazing permission"))).isNull()
+ }
+
+ @Test
+ fun getMimeTypeForPermissions_emptyList_returnsNull() {
+ assertThat(KotlinUtils.getMimeTypeForPermissions(emptyList())).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
new file mode 100644
index 000000000..64a13df60
--- /dev/null
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/PermissionMappingTest.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.permission.util
+
+import android.Manifest
+import android.app.AppOpsManager
+import android.health.connect.HealthPermissions
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.permissioncontroller.permission.utils.PermissionMapping
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class PermissionMappingTest {
+ @Test
+ fun testGetPlatformPermissionGroupForOp_healthPermissionGroup() {
+ 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)
+ }
+
+ @Test
+ fun testGetPlatformPermissionGroupForOp_camera() {
+ assertThat(
+ 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)
+ )
+ }
+}
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
new file mode 100644
index 000000000..15218024e
--- /dev/null
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/UtilsTest.kt
@@ -0,0 +1,274 @@
+/*
+ * 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.util
+
+import android.Manifest.permission.READ_CONTACTS
+import android.Manifest.permission_group.ACTIVITY_RECOGNITION
+import android.Manifest.permission_group.CALENDAR
+import android.Manifest.permission_group.CALL_LOG
+import android.Manifest.permission_group.CAMERA
+import android.Manifest.permission_group.CONTACTS
+import android.Manifest.permission_group.LOCATION
+import android.Manifest.permission_group.MICROPHONE
+import android.Manifest.permission_group.NEARBY_DEVICES
+import android.Manifest.permission_group.PHONE
+import android.Manifest.permission_group.READ_MEDIA_AURAL
+import android.Manifest.permission_group.READ_MEDIA_VISUAL
+import android.Manifest.permission_group.SENSORS
+import android.Manifest.permission_group.SMS
+import android.Manifest.permission_group.STORAGE
+import android.Manifest.permission_group.UNDEFINED
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.SharedPreferences
+import android.content.pm.PackageManager.NameNotFoundException
+import android.content.res.Resources
+import androidx.test.platform.app.InstrumentationRegistry
+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.utils.Utils
+import com.android.permissioncontroller.privacysources.WorkPolicyInfo
+import com.google.common.truth.Truth.assertThat
+import org.junit.Ignore
+import org.junit.Test
+import kotlin.test.assertFailsWith
+
+class UtilsTest {
+ private val context = InstrumentationRegistry.getInstrumentation().targetContext as Context
+
+ @Test
+ fun getAbsoluteTimeString_zero_returnsNull() {
+ assertThat(Utils.getAbsoluteTimeString(context, 0)).isNull()
+ }
+
+ @Test
+ fun getAbsoluteTimeString_currentTime_returnsTimeFormatString() {
+ val time = Utils.getAbsoluteTimeString(context, System.currentTimeMillis())
+ assertThat(time).isNotNull()
+ if (time != null) {
+ if (time.contains(":")) {
+ val times = time.split(":")
+ assertThat(times.size).isEqualTo(2)
+ val isTime = times[1].contains("am", true) || times[1].contains("pm", true)
+ assertThat(isTime).isTrue()
+ } else {
+ assertThat(time.contains(".")).isTrue()
+ val times = time.split(".")
+ assertThat(times.size).isEqualTo(3)
+ }
+ }
+ }
+
+ @Test
+ fun getAbsoluteTimeString_previousDateTime_returnsDateFormatString() {
+ val lastAccessTime = 1680739840723L
+ val time = Utils.getAbsoluteTimeString(context, lastAccessTime)
+ assertThat(time == "Apr 5, 2023" || time == "Apr 6, 2023").isTrue()
+ }
+
+ @Test
+ fun getBlockedIcon_invalidGroupName_returnsMinusOne() {
+ assertThat(Utils.getBlockedIcon(INVALID_GROUP_NAME)).isEqualTo(-1)
+ }
+
+ @Test
+ fun getBlockedIcon_validGroupName() {
+ assertThat(Utils.getBlockedIcon(CAMERA)).isEqualTo(R.drawable.ic_camera_blocked)
+ }
+
+ @Test
+ fun getBlockedTitle_invalidGroupName_returnsMinusOne() {
+ assertThat(Utils.getBlockedTitle(INVALID_GROUP_NAME)).isEqualTo(-1)
+ }
+ @Test
+ fun getBlockedTitle_validGroupName() {
+ assertThat(Utils.getBlockedTitle(CAMERA)).isEqualTo(R.string.blocked_camera_title)
+ }
+
+ @Test
+ fun getDeviceProtectedSharedPreferences() {
+ assertThat(Utils.getDeviceProtectedSharedPreferences(context))
+ .isInstanceOf(SharedPreferences::class.java)
+ }
+
+ @Test
+ @Ignore("b/277782895")
+ fun getEnterpriseString() {
+ assertThat(Utils.getEnterpriseString(context, WorkPolicyInfo.WORK_POLICY_TITLE,
+ R.string.work_policy_title)).isInstanceOf(String::class.java)
+ }
+
+ @Test
+ fun getOneTimePermissionsTimeout_returnsNonNegativeTimeout() {
+ assertThat(Utils.getOneTimePermissionsTimeout()).isGreaterThan(0L)
+ }
+
+ @Test
+ fun getOneTimePermissionsKilledDelaySelfRevoked() {
+ assertThat(Utils.getOneTimePermissionsKilledDelay(true)).isEqualTo(0)
+ }
+
+ @Test
+ fun getOneTimePermissionsKilledDelayNonSelfRevoked() {
+ assertThat(Utils.getOneTimePermissionsKilledDelay(false)).isAtLeast(0L)
+ }
+
+ @Test
+ fun getPackageInfoForComponentName_NonExistComponent_throwsNameNotFoundException() {
+ val testComponent = ComponentName("com.test.package", "TestClass")
+ assertFailsWith<NameNotFoundException> {
+ Utils.getPackageInfoForComponentName(context, testComponent)
+ }
+ }
+
+ @Test
+ fun getPermissionGroupDescriptionString_undefinedPermissionGroup() {
+ val description = "test permission group description"
+ val resultString =
+ context.getString(R.string.permission_description_summary_generic, description)
+ assertThat(Utils.getPermissionGroupDescriptionString(context, UNDEFINED, description))
+ .isEqualTo(resultString)
+ }
+
+ @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)
+ for (permissionGroupName in permissionGroupNames) {
+ assertThat(Utils.getPermissionGroupDescriptionString(context, permissionGroupName, ""))
+ .isNotNull()
+ }
+ }
+
+ @Test
+ fun getPermissionLastAccessSummaryTimestamp_lastAccessSummaryTimestampIsNull() {
+ val result = Utils.getPermissionLastAccessSummaryTimestamp(null, context, LOCATION)
+ assertThat(result.first).isEqualTo("")
+ assertThat(result.second).isEqualTo(Utils.NOT_IN_LAST_7D)
+ assertThat(result.third).isEqualTo("")
+ }
+
+ @Test
+ fun getPermissionLastAccessSummaryTimestamp_sensorDataPermission_lastAccessSummaryTimestampIsToday() {
+ 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()
+ }
+
+ @Test
+ fun getPermissionLastAccessSummaryTimestamp_sensorDataPermission_lastAccessSummaryTimestampIsYesterday() {
+ 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()
+ }
+
+ @Test
+ fun getPermissionLastAccessSummaryTimestamp_sensorDataPermission_lastAccessSummaryTimestampIsLast7Days() {
+ 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()
+ }
+
+ @Test
+ fun getPermissionLastAccessSummaryTimestamp_nonSensorDataPermission_lastAccessSummaryTimestampIsLast24Hrs() {
+ 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()
+ }
+
+ @Test
+ fun getPermissionLastAccessSummaryTimestamp_nonSensorDataPermission_lastAccessSummaryTimestampIs7Days() {
+ 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()
+ }
+
+ @Test
+ fun getOrGenerateSessionId_validSessionId() {
+ val intent = Intent()
+ intent.putExtra(EXTRA_SESSION_ID, VALID_SESSION_ID)
+ val sessionId = Utils.getOrGenerateSessionId(intent)
+ assertThat(sessionId).isEqualTo(VALID_SESSION_ID)
+ }
+
+ @Test
+ fun getOrGenerateSessionId_invalidSessionId() {
+ val intent = Intent()
+ val sessionId = Utils.getOrGenerateSessionId(intent)
+ assertThat(sessionId).isNotEqualTo(INVALID_SESSION_ID)
+ }
+
+ @Test
+ fun getGroupPermissionInfos_validGroupName_returnsGroupPermissions() {
+ val permissionInfos = Utils.getGroupPermissionInfos(CONTACTS, context)
+ assertThat(permissionInfos).isNotNull()
+ val permissions = mutableListOf<String>()
+ for (permissionInfo in permissionInfos!!) {
+ permissions.add(permissionInfo.name)
+ }
+ assertThat(permissions.contains(READ_CONTACTS)).isTrue()
+ }
+
+ @Test
+ fun getGroupPermissionInfos_inValidGroup_returnsNull() {
+ assertThat(Utils.getGroupPermissionInfos(INVALID_GROUP_NAME, context)).isNull()
+ }
+
+ @Test
+ fun getGroupPermissionInfos_undefinedGroup_returnsAllSystemPermissions() {
+ val permissionInfos = Utils.getGroupPermissionInfos(UNDEFINED, context)
+ assertThat(permissionInfos).isNotNull()
+ }
+
+ @Test
+ fun getGroupPermissionInfo_permissionName_returnsSamePermission() {
+ val permissionInfos = Utils.getGroupPermissionInfos(READ_CONTACTS, context)
+ assertThat(permissionInfos).isNotNull()
+ assertThat(permissionInfos!!.size).isEqualTo(1)
+ assertThat(permissionInfos[0].name).isEqualTo(READ_CONTACTS)
+ }
+
+ @Test
+ fun getColorResId_validId_returnsNonZero() {
+ assertThat(Utils.getColorResId(context, android.R.attr.colorPrimary))
+ .isNotEqualTo(Resources.ID_NULL)
+ }
+
+ @Test
+ fun getColorResId_inValidId_returnsZero() {
+ assertThat(Utils.getColorResId(context, INVALID_ATTR_ID)).isEqualTo(Resources.ID_NULL)
+ }
+
+ companion object {
+ private const val INVALID_ATTR_ID = 1000
+ private const val VALID_SESSION_ID = 10000L
+ private const val INVALID_GROUP_NAME = "invalid group name"
+ }
+}
diff --git a/PermissionController/tests/mocking/Android.bp b/PermissionController/tests/mocking/Android.bp
index 9c0a43e2e..0c7c3e675 100644
--- a/PermissionController/tests/mocking/Android.bp
+++ b/PermissionController/tests/mocking/Android.bp
@@ -46,10 +46,11 @@ android_test {
libs: [
"android.test.base",
"android.test.runner",
+ "safety-center-annotations",
],
static_libs: [
- "iconloader",
+ "iconloader_sc_mainline_prod",
"com.google.android.material_material",
"androidx.transition_transition",
"androidx-constraintlayout_constraintlayout",
@@ -85,6 +86,8 @@ android_test {
"SettingsLibFooterPreference",
"SettingsLibSelectorWithWidgetPreference",
"SettingsLibTwoTargetPreference",
+ "SettingsLibActivityEmbedding",
+ "SettingsLibIllustrationPreference",
"androidx.annotation_annotation",
"permissioncontroller-statsd",
// The PermissionController build file includes android.car-stubs in its libs dependency
@@ -104,6 +107,12 @@ android_test {
"libprotobuf-java-lite",
"SettingsLibUtils",
"modules-utils-build_system",
+ "safety-center-internal-data",
+ "safety-center-pending-intents",
+ "safety-center-resources-lib",
+ "safety-label",
+ "role-controller",
+ "lottie",
"androidx.test.rules",
"androidx.test.ext.truth",
@@ -112,6 +121,11 @@ android_test {
"mockito-target-extended-minus-junit4",
],
+ proto: {
+ type: "lite",
+ include_dirs: ["packages/modules/Permission/PermissionController/src/com/android/permissioncontroller"],
+ },
+
jni_libs: [
"libdexmakerjvmtiagent",
"libstaticjvmtiagent",
diff --git a/PermissionController/tests/mocking/AndroidTest.xml b/PermissionController/tests/mocking/AndroidTest.xml
index 58147c1b7..26755923a 100644
--- a/PermissionController/tests/mocking/AndroidTest.xml
+++ b/PermissionController/tests/mocking/AndroidTest.xml
@@ -23,7 +23,7 @@
<object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
<!-- Install test -->
- <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="test-file-name" value="PermissionControllerMockingTests.apk" />
<option name="cleanup-apks" value="true" />
</target_preparer>
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 8853c5ec9..e4cc110f0 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
@@ -28,9 +28,10 @@ import androidx.test.filters.SdkSuppress
import androidx.test.platform.app.InstrumentationRegistry
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.permissioncontroller.Constants
-import com.android.permissioncontroller.hibernation.v31.HibernationController
import com.android.permissioncontroller.PermissionControllerApplication
+import com.android.permissioncontroller.hibernation.v31.HibernationController
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
+import java.io.File
import org.junit.After
import org.junit.Assert.assertTrue
import org.junit.Before
@@ -43,11 +44,10 @@ import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-import java.io.File
-import org.mockito.Mockito.`when` as whenever
/**
* Unit tests for [HibernationController].
@@ -159,6 +159,9 @@ class HibernationControllerTest {
false /* isInstantApp */,
true /* enabled */,
0 /* appFlags */,
- 0 /* firstInstallTime */)
+ 0 /* firstInstallTime */,
+ 0 /* lastUpdateTime */,
+ false /* areAttributionsUserVisible */,
+ emptyMap() /* attributionTagsToLabels */)
}
}
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
new file mode 100644
index 000000000..fadd35f82
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/hibernation/HibernationPolicyTest.kt
@@ -0,0 +1,167 @@
+/*
+ * 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.permissioncontroller.tests.mocking.hibernation
+
+import android.app.job.JobScheduler
+import android.content.Context
+import android.content.Intent
+import android.content.SharedPreferences
+import android.os.Build
+import android.os.SystemClock
+import android.os.UserManager
+import android.preference.PreferenceManager
+import android.provider.DeviceConfig
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.permissioncontroller.Constants
+import com.android.permissioncontroller.PermissionControllerApplication
+import com.android.permissioncontroller.hibernation.HibernationBroadcastReceiver
+import com.android.permissioncontroller.hibernation.ONE_DAY_MS
+import com.android.permissioncontroller.hibernation.PREF_KEY_BOOT_TIME_SNAPSHOT
+import com.android.permissioncontroller.hibernation.PREF_KEY_ELAPSED_REALTIME_SNAPSHOT
+import com.android.permissioncontroller.hibernation.PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING
+import com.android.permissioncontroller.hibernation.SNAPSHOT_UNINITIALIZED
+import com.android.permissioncontroller.hibernation.getStartTimeOfUnusedAppTracking
+import com.google.common.truth.Truth.assertThat
+import java.io.File
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+import org.mockito.MockitoSession
+import org.mockito.quality.Strictness
+
+/**
+ * Unit tests for [HibernationPolicy].
+ */
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S, codeName = "S")
+class HibernationPolicyTest {
+
+ companion object {
+ private val application = Mockito.mock(PermissionControllerApplication::class.java)
+ }
+
+ @Mock lateinit var jobScheduler: JobScheduler
+ @Mock lateinit var context: Context
+ @Mock lateinit var userManager: UserManager
+
+ private lateinit var realContext: Context
+ private lateinit var receiver: HibernationBroadcastReceiver
+ private lateinit var sharedPreferences: SharedPreferences
+ private lateinit var mockitoSession: MockitoSession
+ private lateinit var filesDir: File
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ mockitoSession = ExtendedMockito.mockitoSession()
+ .mockStatic(PermissionControllerApplication::class.java)
+ .mockStatic(DeviceConfig::class.java)
+ .strictness(Strictness.LENIENT).startMocking()
+ `when`(PermissionControllerApplication.get()).thenReturn(application)
+
+ realContext = ApplicationProvider.getApplicationContext()
+ sharedPreferences =
+ PreferenceManager.getDefaultSharedPreferences(realContext.applicationContext)
+
+ `when`(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPreferences)
+ `when`(context.getSystemService(UserManager::class.java)).thenReturn(userManager)
+
+ filesDir = realContext.cacheDir
+ `when`(application.filesDir).thenReturn(filesDir)
+ `when`(context.getSystemService(JobScheduler::class.java)).thenReturn(jobScheduler)
+ `when`(jobScheduler.schedule(Mockito.any())).thenReturn(JobScheduler.RESULT_SUCCESS)
+
+ receiver = HibernationBroadcastReceiver()
+ }
+
+ @After
+ fun cleanup() {
+ mockitoSession.finishMocking()
+ val logFile = File(filesDir, Constants.LOGS_TO_DUMP_FILE)
+ logFile.delete()
+ }
+
+ @Test
+ 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)
+ val systemTimeSnapshot =
+ 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)
+ assertThat(startTimeOfUnusedAppTracking).isNotEqualTo(currentTimeMillis)
+ assertThat(systemTimeSnapshot).isNotEqualTo(SNAPSHOT_UNINITIALIZED)
+ assertThat(realtimeSnapshot).isNotEqualTo(SNAPSHOT_UNINITIALIZED)
+ assertThat(systemTimeSnapshot).isLessThan(currentTimeMillis)
+ assertThat(realtimeSnapshot).isLessThan(currentRealTime)
+
+ receiver.onReceive(context, Intent(Intent.ACTION_TIME_CHANGED))
+ assertAdjustedTime(systemTimeSnapshot, realtimeSnapshot)
+
+ receiver.onReceive(context, Intent(Intent.ACTION_TIMEZONE_CHANGED))
+ assertAdjustedTime(systemTimeSnapshot, realtimeSnapshot)
+ }
+
+ @Test
+ fun getStartTimeOfUnusedAppTracking_shouldReturnExpectedValue() {
+ assertThat(getStartTimeOfUnusedAppTracking(sharedPreferences))
+ .isNotEqualTo(SNAPSHOT_UNINITIALIZED)
+ receiver.onReceive(context, Intent(Intent.ACTION_BOOT_COMPLETED))
+ val systemTimeSnapshot = sharedPreferences.getLong(PREF_KEY_BOOT_TIME_SNAPSHOT,
+ SNAPSHOT_UNINITIALIZED)
+ sharedPreferences
+ .edit()
+ .putLong(PREF_KEY_BOOT_TIME_SNAPSHOT, systemTimeSnapshot - ONE_DAY_MS)
+ .apply()
+ assertThat(getStartTimeOfUnusedAppTracking(sharedPreferences))
+ .isNotEqualTo(systemTimeSnapshot)
+ }
+
+ private fun assertAdjustedTime(
+ systemTimeSnapshot: Long,
+ realtimeSnapshot: Long
+ ) {
+ val newStartTimeOfUnusedAppTracking =
+ sharedPreferences.getLong(PREF_KEY_START_TIME_OF_UNUSED_APP_TRACKING,
+ SNAPSHOT_UNINITIALIZED)
+ val newSystemTimeSnapshot =
+ sharedPreferences.getLong(PREF_KEY_BOOT_TIME_SNAPSHOT, SNAPSHOT_UNINITIALIZED)
+ val newRealtimeSnapshot =
+ sharedPreferences.getLong(PREF_KEY_ELAPSED_REALTIME_SNAPSHOT,
+ SNAPSHOT_UNINITIALIZED)
+ assertThat(newStartTimeOfUnusedAppTracking).isNotEqualTo(SNAPSHOT_UNINITIALIZED)
+ assertThat(newSystemTimeSnapshot).isNotEqualTo(SNAPSHOT_UNINITIALIZED)
+ assertThat(newSystemTimeSnapshot).isGreaterThan(systemTimeSnapshot)
+ assertThat(newRealtimeSnapshot).isNotEqualTo(SNAPSHOT_UNINITIALIZED)
+ assertThat(newRealtimeSnapshot).isAtLeast(realtimeSnapshot)
+ }
+}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/data/v33/FakeEventStorage.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/data/FakeEventStorage.kt
index 4211eff2d..de43bd2d5 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/data/v33/FakeEventStorage.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/data/FakeEventStorage.kt
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.tests.mocking.permission.data.v33
+package com.android.permissioncontroller.tests.mocking.permission.data
-import com.android.permissioncontroller.permission.data.v33.PermissionEvent
-import com.android.permissioncontroller.permission.service.v33.PermissionEventStorage
+import com.android.permissioncontroller.permission.data.PermissionEvent
+import com.android.permissioncontroller.permission.service.PermissionEventStorage
/**
* Fake event storage class used for tests
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 74f67730c..43d599871 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
@@ -19,6 +19,7 @@ package com.android.permissioncontroller.tests.mocking.permission.data.v33
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.permissioncontroller.permission.data.v33.PermissionDecision
import com.android.permissioncontroller.permission.data.v33.RecentPermissionDecisionsLiveData
+import com.android.permissioncontroller.tests.mocking.permission.data.FakeEventStorage
import kotlinx.coroutines.Job
import kotlinx.coroutines.runBlocking
import org.junit.Before
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/BasePermissionEventStorageTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/BasePermissionEventStorageTest.kt
index b5d53d5ff..41a60101d 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/BasePermissionEventStorageTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/BasePermissionEventStorageTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.tests.mocking.permission.service.v33
+package com.android.permissioncontroller.tests.mocking.permission.service
import android.app.job.JobInfo
import android.app.job.JobScheduler
@@ -25,7 +25,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.permissioncontroller.Constants
import com.android.permissioncontroller.PermissionControllerApplication
-import com.android.permissioncontroller.permission.service.v33.BasePermissionEventStorage
+import com.android.permissioncontroller.permission.service.BasePermissionEventStorage
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.runBlocking
import org.junit.After
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
new file mode 100644
index 000000000..761fff18b
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionChangeStorageImplTest.kt
@@ -0,0 +1,165 @@
+/*
+ * 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.permissioncontroller.tests.mocking.permission.service
+
+import android.app.job.JobScheduler
+import android.content.Context
+import android.provider.DeviceConfig
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.permissioncontroller.Constants
+import com.android.permissioncontroller.PermissionControllerApplication
+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 kotlinx.coroutines.runBlocking
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.Mock
+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 {
+ companion object {
+ private val application = Mockito.mock(PermissionControllerApplication::class.java)
+
+ private const val MAP_PACKAGE_NAME = "package.test.map"
+ private const val FIVE_HOURS_MS = 5 * 60 * 60 * 1000
+ }
+
+ private val jan12020 = Date(2020, 0, 1).time
+
+ private val mapChange = PermissionChange(MAP_PACKAGE_NAME, jan12020)
+
+ @Mock
+ lateinit var jobScheduler: JobScheduler
+
+ private lateinit var context: Context
+ private lateinit var storage: PermissionChangeStorageImpl
+ private lateinit var mockitoSession: MockitoSession
+ private lateinit var filesDir: File
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ 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)
+
+ storage = PermissionChangeStorageImpl(context, jobScheduler)
+ }
+
+ @After
+ fun cleanup() = runBlocking {
+ mockitoSession.finishMocking()
+ val logFile = File(filesDir, Constants.LOGS_TO_DUMP_FILE)
+ logFile.delete()
+
+ storage.clearEvents()
+ }
+
+ @Test
+ fun serialize_dataCanBeParsed() {
+ val outStream = ByteArrayOutputStream()
+ storage.serialize(outStream, listOf(mapChange))
+
+ val inStream = ByteArrayInputStream(outStream.toByteArray())
+ assertThat(storage.parse(inStream)).containsExactly(mapChange)
+ }
+
+ @Test
+ fun serialize_roundsTimeDownToDate() {
+ val laterInTheDayGrant = mapChange.copy(
+ eventTime = (mapChange.eventTime + FIVE_HOURS_MS))
+ val outStream = ByteArrayOutputStream()
+ storage.serialize(outStream, listOf(laterInTheDayGrant))
+
+ val inStream = ByteArrayInputStream(outStream.toByteArray())
+ assertThat(storage.parse(inStream)).containsExactly(mapChange)
+ }
+
+ @Test
+ fun serialize_exactTimeDataCanBeParsed() {
+ Mockito.`when`(
+ DeviceConfig.getBoolean(ArgumentMatchers.eq(DeviceConfig.NAMESPACE_PERMISSIONS),
+ ArgumentMatchers.eq(Utils.PROPERTY_PERMISSION_CHANGES_STORE_EXACT_TIME),
+ ArgumentMatchers.anyBoolean()))
+ .thenReturn(true)
+
+ val outStream = ByteArrayOutputStream()
+ storage.serialize(outStream, listOf(mapChange))
+
+ val inStream = ByteArrayInputStream(outStream.toByteArray())
+ assertThat(storage.parse(inStream)).containsExactly(mapChange)
+ }
+
+ @Test
+ fun serialize_afterStoresExactTimeChangedToTrue_canBeParsed() {
+ val outStream = ByteArrayOutputStream()
+ 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()))
+ .thenReturn(true)
+
+ val inStream = ByteArrayInputStream(outStream.toByteArray())
+ assertThat(storage.parse(inStream)).containsExactly(mapChange)
+ }
+
+ @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()))
+ .thenReturn(true)
+
+ 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()))
+ .thenReturn(false)
+
+ val inStream = ByteArrayInputStream(outStream.toByteArray())
+ assertThat(storage.parse(inStream)).containsExactly(mapChange)
+ }
+}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/PermissionEventCleanupJobServiceTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionEventCleanupJobServiceTest.kt
index 4cd9766d3..b60fea123 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/PermissionEventCleanupJobServiceTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionEventCleanupJobServiceTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.tests.mocking.permission.service.v33
+package com.android.permissioncontroller.tests.mocking.permission.service
import android.app.job.JobInfo
import android.app.job.JobScheduler
@@ -25,8 +25,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.permissioncontroller.Constants
import com.android.permissioncontroller.PermissionControllerApplication
-import com.android.permissioncontroller.permission.service.v33.PermissionEventCleanupJobService
-import com.android.permissioncontroller.permission.service.v33.PermissionEventCleanupJobService.Companion.DEFAULT_CLEAR_OLD_EVENTS_CHECK_FREQUENCY
+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 org.junit.After
import org.junit.Before
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/PermissionStorageTimeChangeReceiverTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionStorageTimeChangeReceiverTest.kt
index e2d40e7d2..cf5d92fe3 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/PermissionStorageTimeChangeReceiverTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PermissionStorageTimeChangeReceiverTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.tests.mocking.permission.service.v33
+package com.android.permissioncontroller.tests.mocking.permission.service
import android.content.Context
import android.content.Intent
@@ -27,12 +27,12 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.permissioncontroller.Constants
import com.android.permissioncontroller.PermissionControllerApplication
-import com.android.permissioncontroller.permission.data.v33.PermissionEvent
-import com.android.permissioncontroller.permission.service.v33.PermissionEventStorage
-import com.android.permissioncontroller.permission.service.v33.PermissionStorageTimeChangeReceiver
-import com.android.permissioncontroller.permission.service.v33.PermissionStorageTimeChangeReceiver.Companion.PREF_KEY_ELAPSED_REALTIME_SNAPSHOT
-import com.android.permissioncontroller.permission.service.v33.PermissionStorageTimeChangeReceiver.Companion.PREF_KEY_SYSTEM_TIME_SNAPSHOT
-import com.android.permissioncontroller.permission.service.v33.PermissionStorageTimeChangeReceiver.Companion.SNAPSHOT_UNINITIALIZED
+import com.android.permissioncontroller.permission.data.PermissionEvent
+import com.android.permissioncontroller.permission.service.PermissionEventStorage
+import com.android.permissioncontroller.permission.service.PermissionStorageTimeChangeReceiver
+import com.android.permissioncontroller.permission.service.PermissionStorageTimeChangeReceiver.Companion.PREF_KEY_ELAPSED_REALTIME_SNAPSHOT
+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 org.junit.After
import org.junit.Before
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/PersistedStoragePackageUninstalledReceiverTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PersistedStoragePackageUninstalledReceiverTest.kt
index 9f25847dc..2cefaab67 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/PersistedStoragePackageUninstalledReceiverTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/PersistedStoragePackageUninstalledReceiverTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.tests.mocking.permission.service.v33
+package com.android.permissioncontroller.tests.mocking.permission.service
import android.app.job.JobScheduler
import android.content.Context
@@ -26,8 +26,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.permissioncontroller.Constants
import com.android.permissioncontroller.PermissionControllerApplication
-import com.android.permissioncontroller.permission.service.v33.PersistedStoragePackageUninstalledReceiver
-import com.android.permissioncontroller.tests.mocking.permission.data.v33.FakeEventStorage
+import com.android.permissioncontroller.permission.service.PersistedStoragePackageUninstalledReceiver
+import com.android.permissioncontroller.tests.mocking.permission.data.FakeEventStorage
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
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 6b0187ca0..d576f2924 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
@@ -21,7 +21,11 @@ import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.Manifest.permission.ACCESS_MEDIA_LOCATION
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.SEND_SMS
+import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
import android.app.ActivityManager
import android.app.AppOpsManager
import android.app.job.JobScheduler
@@ -32,21 +36,27 @@ import android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED
import android.content.pm.PackageManager
import android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT
import android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT
+import android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET
import android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
import android.content.pm.PackageManager.MATCH_FACTORY_ONLY
import android.content.pm.PermissionInfo
import android.location.LocationManager
+import android.os.Build
import android.os.Build.VERSION_CODES.R
import android.os.UserManager
import android.permission.PermissionManager
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
+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.PermissionControllerApplication
import com.android.permissioncontroller.permission.service.RuntimePermissionsUpgradeController
import com.android.permissioncontroller.tests.mocking.permission.data.dataRepositories
+import java.util.concurrent.CompletableFuture
import org.junit.After
+import org.junit.Assume
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -59,11 +69,10 @@ import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.timeout
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations.initMocks
import org.mockito.MockitoSession
import org.mockito.quality.Strictness.LENIENT
-import java.util.concurrent.CompletableFuture
-import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidJUnit4::class)
class RuntimePermissionsUpgradeControllerTest {
@@ -73,7 +82,7 @@ class RuntimePermissionsUpgradeControllerTest {
init {
whenever(application.applicationContext).thenReturn(application)
- whenever(application.createPackageContextAsUser(any(), anyInt(), any())).thenReturn(
+ whenever(application.createContextAsUser(any(), anyInt())).thenReturn(
application)
whenever(application.registerComponentCallbacks(any())).thenAnswer {
@@ -85,7 +94,11 @@ class RuntimePermissionsUpgradeControllerTest {
}
/** Latest permission database version known in this test */
- private val LATEST_VERSION = 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
@@ -116,11 +129,9 @@ class RuntimePermissionsUpgradeControllerTest {
* @param pkgs packages that should pretend to be installed
*/
private fun setPackages(vararg pkgs: Package) {
- whenever(packageManager.getInstalledPackagesAsUser(anyInt(), anyInt())).thenAnswer {
- val flags = it.arguments[0] as Int
-
+ val mockPackageInfo = { pkgs: List<Package>, flags: Long ->
pkgs.filter { pkg ->
- (flags and MATCH_FACTORY_ONLY) == 0 || pkg.isPreinstalled
+ (flags and MATCH_FACTORY_ONLY.toLong()) == 0L || pkg.isPreinstalled
}.map { pkg ->
PackageInfo().apply {
packageName = pkg.name
@@ -133,18 +144,37 @@ class RuntimePermissionsUpgradeControllerTest {
}
}.toIntArray()
applicationInfo = ApplicationInfo().apply {
- targetSdkVersion = R
+ targetSdkVersion = pkg.targetSdkVersion
}
}
}
}
+ whenever(packageManager.getInstalledPackagesAsUser(anyInt(), anyInt())).thenAnswer {
+ val flags = (it.arguments[0] as Int).toLong()
+
+ mockPackageInfo(pkgs.toList(), flags)
+ }
+
+ if (SdkLevel.isAtLeastT()) {
+ whenever(
+ packageManager.getInstalledPackagesAsUser(
+ any(PackageManager.PackageInfoFlags::class.java),
+ anyInt()
+ )
+ ).thenAnswer {
+ val flags = it.arguments[0] as PackageManager.PackageInfoFlags
+
+ 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 }
- ?: throw PackageManager.NameNotFoundException()
+ .find { it.packageName == packageName }
+ ?: throw PackageManager.NameNotFoundException()
}
whenever(packageManager.getPermissionFlags(any(), any(), any())).thenAnswer {
@@ -208,10 +238,12 @@ class RuntimePermissionsUpgradeControllerTest {
*/
private fun upgradeIfNeeded() {
val completionCallback = CompletableFuture<Unit>()
- RuntimePermissionsUpgradeController.upgradeIfNeeded(application, Runnable {
- completionCallback.complete(Unit)
- })
- completionCallback.join()
+ runWithShellPermissionIdentity {
+ RuntimePermissionsUpgradeController.upgradeIfNeeded(application, Runnable {
+ completionCallback.complete(Unit)
+ })
+ completionCallback.join()
+ }
}
private fun setInitialDatabaseVersion(initialVersion: Int) {
@@ -483,6 +515,38 @@ class RuntimePermissionsUpgradeControllerTest {
verifyNotGranted(TEST_PKG_NAME, ACCESS_MEDIA_LOCATION)
}
+ @SdkSuppress(
+ minSdkVersion = Build.VERSION_CODES.TIRAMISU,
+ maxSdkVersion = Build.VERSION_CODES.TIRAMISU,
+ codeName = "Tiramisu"
+ )
+ @Test
+ fun storagePermissionsMigrateToMediaPermissionsWhenVersionIs9() {
+ Assume.assumeTrue(SdkLevel.isAtLeastT() && !SdkLevel.isAtLeastU())
+ 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),
+ Permission(READ_MEDIA_AUDIO, isGranted = false),
+ Permission(READ_MEDIA_VIDEO, isGranted = false),
+ Permission(READ_MEDIA_IMAGES, isGranted = false),
+ targetSdkVersion = 33
+ )
+ )
+
+ upgradeIfNeeded()
+
+ verifyGranted(TEST_PKG_NAME, READ_MEDIA_AUDIO)
+ verifyGranted(TEST_PKG_NAME, READ_MEDIA_VIDEO)
+ verifyGranted(TEST_PKG_NAME, READ_MEDIA_IMAGES)
+ }
+
@After
fun resetSystem() {
// Send low memory notifications for all data repositories which will clear cached data
@@ -500,10 +564,15 @@ class RuntimePermissionsUpgradeControllerTest {
private open class Package(
val name: String,
val permissions: List<Permission> = emptyList(),
- val isPreinstalled: Boolean = false
+ val isPreinstalled: Boolean = false,
+ val targetSdkVersion: Int = R
) {
- constructor(name: String, vararg permission: Permission, isPreinstalled: Boolean = false) :
- this(name, permission.toList(), isPreinstalled)
+ constructor(
+ name: String,
+ vararg permission: Permission,
+ isPreinstalled: Boolean = false,
+ targetSdkVersion: Int = R
+ ) : this(name, permission.toList(), isPreinstalled, targetSdkVersion)
}
private class PreinstalledPackage(
@@ -513,4 +582,14 @@ class RuntimePermissionsUpgradeControllerTest {
constructor(name: String, vararg permission: Permission) :
this(name, permission.toList())
}
+
+ private fun <R> runWithShellPermissionIdentity(block: () -> R): R {
+ val uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ uiAutomation.adoptShellPermissionIdentity()
+ try {
+ return block()
+ } finally {
+ uiAutomation.dropShellPermissionIdentity()
+ }
+ }
}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/TestPermissionEvent.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/TestPermissionEvent.kt
index e935cc36e..1bb8997dc 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/v33/TestPermissionEvent.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/service/TestPermissionEvent.kt
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.tests.mocking.permission.service.v33
+package com.android.permissioncontroller.tests.mocking.permission.service
-import com.android.permissioncontroller.permission.data.v33.PermissionEvent
+import com.android.permissioncontroller.permission.data.PermissionEvent
/**
* Test permission event used for tests.
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 df6e92154..0f4216066 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
@@ -26,11 +26,11 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
import com.android.permissioncontroller.permission.model.livedatatypes.LightPermission
-import com.android.permissioncontroller.permission.ui.model.v33.ReviewPermissionsViewModel
-import com.android.permissioncontroller.permission.ui.model.v33.ReviewPermissionsViewModel.PermissionTarget.PERMISSION_BACKGROUND
-import com.android.permissioncontroller.permission.ui.model.v33.ReviewPermissionsViewModel.PermissionTarget.PERMISSION_BOTH
-import com.android.permissioncontroller.permission.ui.model.v33.ReviewPermissionsViewModel.PermissionTarget.PERMISSION_FOREGROUND
-import com.android.permissioncontroller.permission.ui.model.v33.ReviewPermissionsViewModel.SummaryMessage
+import com.android.permissioncontroller.permission.ui.model.ReviewPermissionsViewModel
+import com.android.permissioncontroller.permission.ui.model.ReviewPermissionsViewModel.PermissionTarget.PERMISSION_BACKGROUND
+import com.android.permissioncontroller.permission.ui.model.ReviewPermissionsViewModel.PermissionTarget.PERMISSION_BOTH
+import com.android.permissioncontroller.permission.ui.model.ReviewPermissionsViewModel.PermissionTarget.PERMISSION_FOREGROUND
+import com.android.permissioncontroller.permission.ui.model.ReviewPermissionsViewModel.SummaryMessage
import com.android.permissioncontroller.permission.utils.Utils
import com.android.settingslib.RestrictedLockUtils
import org.junit.After
@@ -42,10 +42,10 @@ import org.mockito.Mock
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
import org.mockito.Mockito.spy
+import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-import org.mockito.Mockito.`when` as whenever
/**
* Unit tests for [ReviewPermissionsViewModel]
@@ -247,4 +247,4 @@ class ReviewPermissionsViewModelTest {
requestedPermissionsFlags = listOf<Int>().toIntArray()
}
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/v34/LightInstallSourceInfoTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/v34/LightInstallSourceInfoTest.kt
new file mode 100644
index 000000000..12e416786
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/v34/LightInstallSourceInfoTest.kt
@@ -0,0 +1,218 @@
+/*
+ * 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.mocking.permission.ui.model.v34
+
+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 androidx.test.filters.SdkSuppress
+import com.android.permissioncontroller.permission.model.livedatatypes.v34.LightInstallSourceInfo
+import com.android.permissioncontroller.permission.model.livedatatypes.v34.LightInstallSourceInfo.Companion.INSTALL_SOURCE_UNAVAILABLE
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+/** Tests for [LightInstallSourceInfo]. */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+class LightInstallSourceInfoTest {
+ @Test
+ fun initiatingPackageName_withDefaultConstructor_returnsNull() {
+ val installSourceInfo = INSTALL_SOURCE_UNAVAILABLE
+
+ assertThat(installSourceInfo.initiatingPackageName).isEqualTo(null)
+ }
+
+ @Test
+ fun initiatingPackageName_whenSet_returnsInitiatingPackageName() {
+ val installSourceInfo = LightInstallSourceInfo(PACKAGE_SOURCE_STORE, INITIATING_PKG_NAME)
+
+ assertThat(installSourceInfo.initiatingPackageName).isEqualTo(INITIATING_PKG_NAME)
+ }
+
+ @Test
+ fun initiatingPackageName_whenNotSet_returnsNull() {
+ val installSourceInfo = LightInstallSourceInfo(PACKAGE_SOURCE_STORE, null)
+
+ assertThat(installSourceInfo.initiatingPackageName).isEqualTo(null)
+ }
+
+ @Test
+ fun supportsSafetyLabel_withSourceStore_andPackageName_returnsTrue() {
+ val installSourceInfo = LightInstallSourceInfo(PACKAGE_SOURCE_STORE, INITIATING_PKG_NAME)
+
+ assertThat(installSourceInfo.supportsSafetyLabel).isEqualTo(true)
+ }
+
+ @Test
+ fun supportsSafetyLabel_withSourceOther_andPackageName_returnsFalse() {
+ val installSourceInfo = LightInstallSourceInfo(PACKAGE_SOURCE_OTHER, INITIATING_PKG_NAME)
+
+ assertThat(installSourceInfo.supportsSafetyLabel).isEqualTo(false)
+ }
+
+ @Test
+ fun supportsSafetyLabel_withSourceUnspecified_andPackageName_returnsTrue() {
+ val installSourceInfo =
+ LightInstallSourceInfo(PACKAGE_SOURCE_UNSPECIFIED, INITIATING_PKG_NAME)
+
+ assertThat(installSourceInfo.supportsSafetyLabel).isEqualTo(true)
+ }
+
+ @Test
+ fun supportsSafetyLabel_withSourceLocalFile_andPackageName_returnsFalse() {
+ val installSourceInfo =
+ LightInstallSourceInfo(PACKAGE_SOURCE_LOCAL_FILE, INITIATING_PKG_NAME)
+
+ assertThat(installSourceInfo.supportsSafetyLabel).isEqualTo(false)
+ }
+
+ @Test
+ fun supportsSafetyLabel_withSourceDownloadedFile_andPackageName_returnsFalse() {
+ val installSourceInfo =
+ LightInstallSourceInfo(PACKAGE_SOURCE_DOWNLOADED_FILE, INITIATING_PKG_NAME)
+
+ assertThat(installSourceInfo.supportsSafetyLabel).isEqualTo(false)
+ }
+
+ @Test
+ fun supportsSafetyLabel_withSourceStore_noPackageName_returnsFalse() {
+ val installSourceInfo = LightInstallSourceInfo(PACKAGE_SOURCE_STORE, null)
+
+ assertThat(installSourceInfo.supportsSafetyLabel).isEqualTo(false)
+ }
+
+ @Test
+ fun supportsSafetyLabel_withSourceOther_noPackageName_returnsFalse() {
+ val installSourceInfo = LightInstallSourceInfo(PACKAGE_SOURCE_OTHER, null)
+
+ assertThat(installSourceInfo.supportsSafetyLabel).isEqualTo(false)
+ }
+
+ @Test
+ fun supportsSafetyLabel_withSourceUnspecified_noPackageName_returnsTrue() {
+ val installSourceInfo = LightInstallSourceInfo(PACKAGE_SOURCE_UNSPECIFIED, null)
+
+ assertThat(installSourceInfo.supportsSafetyLabel).isEqualTo(true)
+ }
+
+ @Test
+ fun supportsSafetyLabel_withSourceLocalFile_noPackageName_returnsFalse() {
+ val installSourceInfo = LightInstallSourceInfo(PACKAGE_SOURCE_LOCAL_FILE, null)
+
+ assertThat(installSourceInfo.supportsSafetyLabel).isEqualTo(false)
+ }
+
+ @Test
+ fun supportsSafetyLabel_withSourceDownloadedFile_noPackageName_returnsFalse() {
+ val installSourceInfo = LightInstallSourceInfo(PACKAGE_SOURCE_DOWNLOADED_FILE, null)
+
+ assertThat(installSourceInfo.supportsSafetyLabel).isEqualTo(false)
+ }
+
+ @Test
+ fun supportsSafetyLabel_withNoSource_noPackageName_returnsFalse() {
+ val installSourceInfo = INSTALL_SOURCE_UNAVAILABLE
+
+ assertThat(installSourceInfo.supportsSafetyLabel).isEqualTo(false)
+ }
+
+ @Test
+ fun isPreloadedApp_withSourceStore_andPackageName_returnsFalse() {
+ val installSourceInfo = LightInstallSourceInfo(PACKAGE_SOURCE_STORE, INITIATING_PKG_NAME)
+
+ assertThat(installSourceInfo.isPreloadedApp).isEqualTo(false)
+ }
+
+ @Test
+ fun isPreloadedApp_withSourceOther_andPackageName_returnsFalse() {
+ val installSourceInfo = LightInstallSourceInfo(PACKAGE_SOURCE_OTHER, INITIATING_PKG_NAME)
+
+ assertThat(installSourceInfo.isPreloadedApp).isEqualTo(false)
+ }
+
+ @Test
+ fun isPreloadedApp_withSourceUnspecified_andPackageName_returnsFalse() {
+ val installSourceInfo =
+ LightInstallSourceInfo(PACKAGE_SOURCE_UNSPECIFIED, INITIATING_PKG_NAME)
+
+ assertThat(installSourceInfo.isPreloadedApp).isEqualTo(false)
+ }
+
+ @Test
+ fun isPreloadedApp_withSourceLocalFile_andPackageName_returnsFalse() {
+ val installSourceInfo =
+ LightInstallSourceInfo(PACKAGE_SOURCE_LOCAL_FILE, INITIATING_PKG_NAME)
+
+ assertThat(installSourceInfo.isPreloadedApp).isEqualTo(false)
+ }
+
+ @Test
+ fun isPreloadedApp_withSourceDownloadedFile_andPackageName_returnsFalse() {
+ val installSourceInfo =
+ LightInstallSourceInfo(PACKAGE_SOURCE_DOWNLOADED_FILE, INITIATING_PKG_NAME)
+
+ assertThat(installSourceInfo.isPreloadedApp).isEqualTo(false)
+ }
+
+ @Test
+ fun isPreloadedApp_withSourceStore_noPackageName_returnsFalse() {
+ val installSourceInfo = LightInstallSourceInfo(PACKAGE_SOURCE_STORE, null)
+
+ assertThat(installSourceInfo.isPreloadedApp).isEqualTo(false)
+ }
+
+ @Test
+ fun isPreloadedApp_withSourceOther_noPackageName_returnsFalse() {
+ val installSourceInfo = LightInstallSourceInfo(PACKAGE_SOURCE_OTHER, null)
+
+ assertThat(installSourceInfo.isPreloadedApp).isEqualTo(false)
+ }
+
+ @Test
+ fun isPreloadedApp_withSourceUnspecified_noPackageName_returnsTrue() {
+ val installSourceInfo = LightInstallSourceInfo(PACKAGE_SOURCE_UNSPECIFIED, null)
+
+ assertThat(installSourceInfo.isPreloadedApp).isEqualTo(true)
+ }
+
+ @Test
+ fun isPreloadedApp_withSourceLocalFile_noPackageName_returnsFalse() {
+ val installSourceInfo = LightInstallSourceInfo(PACKAGE_SOURCE_LOCAL_FILE, null)
+
+ assertThat(installSourceInfo.isPreloadedApp).isEqualTo(false)
+ }
+
+ @Test
+ fun isPreloadedApp_withSourceDownloadedFile_noPackageName_returnsFalse() {
+ val installSourceInfo = LightInstallSourceInfo(PACKAGE_SOURCE_DOWNLOADED_FILE, null)
+
+ assertThat(installSourceInfo.isPreloadedApp).isEqualTo(false)
+ }
+
+ @Test
+ fun isPreloadedApp_withNoSource_noPackageName_returnsFalse() {
+ val installSourceInfo = INSTALL_SOURCE_UNAVAILABLE
+
+ assertThat(installSourceInfo.isPreloadedApp).isEqualTo(false)
+ }
+
+ companion object {
+ private const val INITIATING_PKG_NAME = "pkg_name"
+ }
+}
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 df4c4e80f..be6518b23 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
@@ -40,6 +40,7 @@ import android.content.pm.PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY
import android.os.Build
import android.os.UserHandle
import android.permission.PermissionManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
import com.android.permissioncontroller.permission.model.livedatatypes.LightPermGroupInfo
@@ -58,12 +59,10 @@ import org.mockito.ArgumentMatchers.anyString
import org.mockito.ArgumentMatchers.eq
import org.mockito.ArgumentMatchers.nullable
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.mockito.Mockito.`when`
private const val PERMISSION_CONTROLLER_CHANGED_FLAG_MASK = FLAG_PERMISSION_USER_SET or
FLAG_PERMISSION_USER_FIXED or
@@ -155,7 +154,7 @@ class GrantRevokeTests {
Build.VERSION_CODES.LOLLIPOP
} else {
Build.VERSION_CODES.R
- }, isInstantApp, isInstantApp, 0, 0L)
+ }, isInstantApp, isInstantApp, 0, 0L, 0L, false, emptyMap())
}
/**
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
new file mode 100644
index 000000000..2fcf4a24d
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/AccessibilitySourceServiceTest.kt
@@ -0,0 +1,235 @@
+/*
+ * 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.permissioncontroller.tests.mocking.privacysources
+
+import android.app.job.JobParameters
+import android.content.ComponentName
+import android.content.Context
+import android.content.SharedPreferences
+import android.os.Build
+import android.provider.DeviceConfig
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.permissioncontroller.privacysources.AccessibilityJobService
+import com.android.permissioncontroller.privacysources.AccessibilitySourceService
+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.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import org.mockito.MockitoSession
+import org.mockito.quality.Strictness
+
+/**
+ * Unit tests for internal [AccessibilitySourceService]
+ *
+ * <p> Does not test notification as there are conflicts with being able to mock NotificationManager
+ * and PendingIntent.getBroadcast requiring a valid context. Notifications are tested in the CTS
+ * integration tests
+ */
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+class AccessibilitySourceServiceTest {
+
+ @Mock
+ lateinit var jobService: AccessibilityJobService
+ private lateinit var context: Context
+ private lateinit var mockitoSession: MockitoSession
+ private lateinit var accessibilitySourceService: AccessibilitySourceService
+ private var shouldCancel = false
+ private lateinit var sharedPref: SharedPreferences
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ context = ApplicationProvider.getApplicationContext()
+
+ mockitoSession = ExtendedMockito.mockitoSession()
+ .mockStatic(DeviceConfig::class.java)
+ .strictness(Strictness.LENIENT).startMocking()
+
+ accessibilitySourceService = runWithShellPermissionIdentity {
+ AccessibilitySourceService(context)
+ }
+ sharedPref = accessibilitySourceService.getSharedPreference()
+ sharedPref.edit().clear().apply()
+ }
+
+ @After
+ fun cleanup() {
+ shouldCancel = false
+ mockitoSession.finishMocking()
+ sharedPref.edit().clear().apply()
+ }
+
+ @Test
+ fun processAccessibilityJobWithCancellation() {
+ shouldCancel = true
+ val jobParameters = mock(JobParameters::class.java)
+
+ runWithShellPermissionIdentity {
+ runBlocking {
+ accessibilitySourceService.processAccessibilityJob(
+ jobParameters,
+ jobService
+ ) { shouldCancel }
+ }
+ }
+ verify(jobService).jobFinished(jobParameters, true)
+ }
+
+ @Test
+ fun markServiceAsNotified() {
+ val a11yService = ComponentName("com.test.package", "AccessibilityService")
+ runBlocking {
+ accessibilitySourceService.markServiceAsNotified(a11yService)
+ }
+
+ val storedServices = getNotifiedServices()
+ assertThat(storedServices.size).isEqualTo(1)
+ assertThat(storedServices.iterator().next()).isEqualTo(a11yService.flattenToShortString())
+ }
+
+ @Test
+ fun markAsNotifiedWithSecondComponent() {
+ val testComponent = ComponentName("com.test.package", "TestClass")
+ val testComponent2 = ComponentName("com.test.package2", "TestClass2")
+
+ var notifiedServices = runBlocking {
+ accessibilitySourceService.markServiceAsNotified(testComponent)
+ getNotifiedServices()
+ }
+ assertThat(notifiedServices.size).isEqualTo(1)
+ assertThat(notifiedServices.iterator().next())
+ .isEqualTo(testComponent.flattenToShortString())
+
+ notifiedServices = runBlocking {
+ accessibilitySourceService.markServiceAsNotified(testComponent2)
+ getNotifiedServices()
+ }
+ assertThat(notifiedServices.size).isEqualTo(2)
+ val expectedServices = listOf(testComponent, testComponent2)
+ expectedServices.forEach {
+ assertThat(notifiedServices.contains(it.flattenToShortString())).isTrue()
+ }
+ }
+ @Test
+ fun removeNotifiedService() {
+ val a11yService = ComponentName("com.test.package", "AccessibilityService")
+ val a11yService2 = ComponentName("com.test.package", "AccessibilityService2")
+ val a11yService3 = ComponentName("com.test.package", "AccessibilityService3")
+ val allServices = listOf(a11yService, a11yService2, a11yService3)
+
+ val notifiedServices = runBlocking {
+ allServices.forEach {
+ accessibilitySourceService.markServiceAsNotified(it)
+ }
+ accessibilitySourceService.removeFromNotifiedServices(a11yService2)
+ getNotifiedServices()
+ }
+ val expectedServices = listOf(a11yService, a11yService3)
+ assertThat(notifiedServices.size).isEqualTo(2)
+ expectedServices.forEach {
+ assertThat(notifiedServices.contains(it.flattenToShortString())).isTrue()
+ }
+ }
+
+ @Test
+ fun removePackageState() {
+ val testComponent = ComponentName("com.test.package", "TestClass")
+ val testComponent2 = ComponentName("com.test.package", "TestClass2")
+ val testComponent3 = ComponentName("com.test.package2", "TestClass3")
+ val testComponents = listOf(testComponent, testComponent2, testComponent3)
+
+ val notifiedServices = runBlocking {
+ testComponents.forEach {
+ accessibilitySourceService.markServiceAsNotified(it)
+ }
+ accessibilitySourceService.removePackageState(testComponent.packageName)
+ getNotifiedServices()
+ }
+
+ assertThat(notifiedServices.size).isEqualTo(1)
+ assertThat(notifiedServices.contains(testComponent3.flattenToShortString())).isTrue()
+ }
+
+ @Test
+ fun removePackageStateWithMultipleServicePerPackage() {
+ val testComponent = ComponentName("com.test.package", "TestClass")
+ val testComponent2 = ComponentName("com.test.package", "TestClass2")
+ val testComponents = listOf(testComponent, testComponent2)
+
+ val notifiedServices = runBlocking {
+ testComponents.forEach {
+ accessibilitySourceService.markServiceAsNotified(it)
+ }
+ accessibilitySourceService.removePackageState(testComponent.packageName)
+ getNotifiedServices()
+ }
+
+ assertThat(notifiedServices).isEmpty()
+ }
+
+ @Test
+ fun removePackageState_noPreviouslyNotifiedPackage() {
+ val testComponent = ComponentName("com.test.package", "TestClass")
+
+ // Get the initial list of Components
+ val initialComponents = getNotifiedServices()
+
+ // Verify no components are present
+ assertThat(initialComponents).isEmpty()
+
+ // Forget about test package, and get the resulting list of Components
+ // Filter to the component that match the test component
+ val updatedComponents = runWithShellPermissionIdentity {
+ runBlocking {
+ // Verify this should not fail!
+ accessibilitySourceService.removePackageState(testComponent.packageName)
+ getNotifiedServices()
+ }
+ }
+
+ // Verify no components are present
+ assertThat(updatedComponents).isEmpty()
+ }
+
+ private fun getNotifiedServices(): MutableSet<String> {
+ return sharedPref.getStringSet(
+ AccessibilitySourceService.KEY_ALREADY_NOTIFIED_SERVICES,
+ mutableSetOf<String>()
+ )!!
+ }
+
+ private fun <R> runWithShellPermissionIdentity(block: () -> R): R {
+ val uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ uiAutomation.adoptShellPermissionIdentity()
+ try {
+ return block()
+ } finally {
+ uiAutomation.dropShellPermissionIdentity()
+ }
+ }
+}
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
new file mode 100644
index 000000000..b1b5694ff
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/AppDataSharingUpdatesPrivacySourceTest.kt
@@ -0,0 +1,197 @@
+/*
+ * 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.mocking.privacysources
+
+import android.app.PendingIntent
+import android.app.PendingIntent.FLAG_IMMUTABLE
+import android.app.PendingIntent.FLAG_UPDATE_CURRENT
+import android.content.Context
+import android.content.ContextWrapper
+import android.content.Intent
+import android.content.Intent.ACTION_BOOT_COMPLETED
+import android.content.Intent.ACTION_REVIEW_APP_DATA_SHARING_UPDATES
+import android.os.Build
+import android.provider.DeviceConfig
+import android.provider.DeviceConfig.NAMESPACE_PRIVACY
+import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetyCenterManager.ACTION_REFRESH_SAFETY_SOURCES
+import android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID
+import android.safetycenter.SafetyEvent
+import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED
+import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED
+import android.safetycenter.SafetySourceData
+import android.safetycenter.SafetySourceStatus
+import android.safetylabel.SafetyLabelConstants.SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.permissioncontroller.PermissionControllerApplication
+import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent.EVENT_DEVICE_REBOOTED
+import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent.EVENT_REFRESH_REQUESTED
+import com.android.permissioncontroller.privacysources.v34.AppDataSharingUpdatesPrivacySource
+import com.android.permissioncontroller.privacysources.v34.AppDataSharingUpdatesPrivacySource.Companion.APP_DATA_SHARING_UPDATES_SOURCE_ID
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+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
+
+/** Tests for [AppDataSharingUpdatesPrivacySource]. */
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+class AppDataSharingUpdatesPrivacySourceTest {
+
+ private lateinit var mockitoSession: MockitoSession
+ private lateinit var appDataSharingUpdatesPrivacySource: AppDataSharingUpdatesPrivacySource
+ @Mock lateinit var mockSafetyCenterManager: SafetyCenterManager
+
+ @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()
+ whenever(
+ Utils.getSystemServiceSafe(
+ any(ContextWrapper::class.java), eq(SafetyCenterManager::class.java)))
+ .thenReturn(mockSafetyCenterManager)
+
+ appDataSharingUpdatesPrivacySource = AppDataSharingUpdatesPrivacySource()
+
+ setSafetyLabelChangeNotificationsEnabled(true)
+ }
+
+ @After
+ fun cleanup() {
+ mockitoSession.finishMocking()
+ }
+
+ @Test
+ fun safetyCenterEnabledChanged_enabled_doesNothing() {
+ appDataSharingUpdatesPrivacySource.safetyCenterEnabledChanged(context, true)
+
+ verifyZeroInteractions(mockSafetyCenterManager)
+ }
+
+ @Test
+ fun safetyCenterEnabledChanged_disabled_doesNothing() {
+ appDataSharingUpdatesPrivacySource.safetyCenterEnabledChanged(context, false)
+
+ verifyZeroInteractions(mockSafetyCenterManager)
+ }
+
+ @Test
+ fun rescanAndPushSafetyCenterData_bothFeaturesEnabled_setsDataWithStatus() {
+ val refreshIntent =
+ Intent(ACTION_REFRESH_SAFETY_SOURCES)
+ .putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, REFRESH_ID)
+
+ appDataSharingUpdatesPrivacySource.rescanAndPushSafetyCenterData(
+ context, refreshIntent, EVENT_REFRESH_REQUESTED)
+
+ val expectedSafetySourceData: SafetySourceData =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder(
+ DATA_SHARING_UPDATES_TITLE,
+ DATA_SHARING_UPDATES_SUMMARY,
+ SafetySourceData.SEVERITY_LEVEL_INFORMATION)
+ .setPendingIntent(
+ PendingIntent.getActivity(
+ context,
+ /* requestCode= */ 0,
+ Intent(ACTION_REVIEW_APP_DATA_SHARING_UPDATES),
+ FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE))
+ .build())
+ .build()
+ val expectedSafetyEvent =
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
+ .setRefreshBroadcastId(REFRESH_ID)
+ .build()
+ verify(mockSafetyCenterManager)
+ .setSafetySourceData(
+ APP_DATA_SHARING_UPDATES_SOURCE_ID, expectedSafetySourceData, expectedSafetyEvent)
+ }
+
+ @Test
+ fun rescanAndPushSafetyCenterData_safetyLabelChangeNotificationsDisabled_setsNullData() {
+ setSafetyLabelChangeNotificationsEnabled(false)
+ val bootCompleteIntent = Intent(ACTION_BOOT_COMPLETED)
+
+ appDataSharingUpdatesPrivacySource.rescanAndPushSafetyCenterData(
+ context, bootCompleteIntent, EVENT_DEVICE_REBOOTED)
+
+ val expectedSafetyEvent = SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build()
+ verify(mockSafetyCenterManager)
+ .setSafetySourceData(APP_DATA_SHARING_UPDATES_SOURCE_ID, null, expectedSafetyEvent)
+ }
+
+ @Test
+ fun rescanAndPushSafetyCenterData_bothFeaturesDisabled_setsNullData() {
+ setSafetyLabelChangeNotificationsEnabled(false)
+ val refreshIntent =
+ Intent(ACTION_REFRESH_SAFETY_SOURCES)
+ .putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, REFRESH_ID)
+
+ appDataSharingUpdatesPrivacySource.rescanAndPushSafetyCenterData(
+ context, refreshIntent, EVENT_REFRESH_REQUESTED)
+
+ val expectedSafetyEvent =
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
+ .setRefreshBroadcastId(REFRESH_ID)
+ .build()
+ verify(mockSafetyCenterManager)
+ .setSafetySourceData(APP_DATA_SHARING_UPDATES_SOURCE_ID, null, expectedSafetyEvent)
+ }
+
+ /** Companion object for [AppDataSharingUpdatesPrivacySourceTest]. */
+ companion object {
+ // Real context, used in order to avoid mocking resources.
+ var context: Context = ApplicationProvider.getApplicationContext()
+ const val DATA_SHARING_UPDATES_TITLE: String = "Data sharing updates for location"
+ const val DATA_SHARING_UPDATES_SUMMARY: String =
+ "Review apps that changed the way they may share your location data"
+ const val REFRESH_ID: String = "refresh_id"
+
+ /**
+ * Sets the value for the Safety Label Change Notifications feature [DeviceConfig] property.
+ */
+ private fun setSafetyLabelChangeNotificationsEnabled(enabled: Boolean) {
+ whenever(
+ DeviceConfig.getBoolean(
+ eq(NAMESPACE_PRIVACY),
+ eq(SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED),
+ 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
new file mode 100644
index 000000000..6f1d2c5c9
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerCheckInternalTest.kt
@@ -0,0 +1,567 @@
+/*
+ * 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.permissioncontroller.tests.mocking.privacysources
+
+import android.app.PendingIntent
+import android.app.job.JobParameters
+import android.content.ComponentName
+import android.content.Context
+import android.content.ContextWrapper
+import android.content.Intent
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageInfo
+import android.os.Build
+import android.provider.Settings
+import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetyEvent
+import android.safetycenter.SafetySourceData
+import android.safetycenter.SafetySourceIssue
+import androidx.core.util.Preconditions
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.privacysources.DisableNotificationListenerComponentHandler
+import com.android.permissioncontroller.privacysources.NotificationListenerActionCardDismissalReceiver
+import com.android.permissioncontroller.privacysources.NotificationListenerCheckInternal
+import com.android.permissioncontroller.privacysources.NotificationListenerCheckInternal.Companion.NLS_PREFERENCE_FILE
+import com.android.permissioncontroller.privacysources.NotificationListenerCheckJobService
+import com.android.permissioncontroller.privacysources.SC_NLS_DISABLE_ACTION_ID
+import com.android.permissioncontroller.privacysources.SC_NLS_SOURCE_ID
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.runBlocking
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import org.mockito.MockitoSession
+import org.mockito.quality.Strictness
+
+/**
+ * Unit tests for [NotificationListenerCheckInternal]
+ *
+ * <p> Does not test notification as there are conflicts with being able to mock NotificationManager
+ * and PendintIntent.getBroadcast requiring a valid context. Notifications are tested in the CTS
+ * integration tests
+ */
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+class NotificationListenerCheckInternalTest {
+
+ @Mock lateinit var mockNotificationListenerCheckJobService: NotificationListenerCheckJobService
+ @Mock lateinit var mockSafetyCenterManager: SafetyCenterManager
+
+ private lateinit var context: Context
+ private lateinit var mockitoSession: MockitoSession
+ private lateinit var notificationListenerCheck: NotificationListenerCheckInternal
+
+ private var shouldCancel = false
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ context = ApplicationProvider.getApplicationContext()
+
+ mockitoSession =
+ ExtendedMockito.mockitoSession()
+ .spyStatic(Utils::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
+
+ // Setup Safety Center
+ doReturn(mockSafetyCenterManager).`when` {
+ Utils.getSystemServiceSafe(
+ any(ContextWrapper::class.java), eq(SafetyCenterManager::class.java))
+ }
+
+ notificationListenerCheck = runWithShellPermissionIdentity {
+ NotificationListenerCheckInternal(context) { shouldCancel }
+ }
+
+ // ensure tests start with clean sharedPrefs
+ clearSharedPrefState()
+ }
+
+ @After
+ fun cleanup() {
+ clearSharedPrefState()
+ shouldCancel = false
+ mockitoSession.finishMocking()
+ }
+
+ @Test
+ fun getEnabledNotificationListenersAndNotifyIfNeeded_shouldCancel_finishJob_reschedule() {
+ shouldCancel = true
+ val jobParameters = mock(JobParameters::class.java)
+
+ runWithShellPermissionIdentity {
+ runBlocking {
+ notificationListenerCheck.getEnabledNotificationListenersAndNotifyIfNeeded(
+ jobParameters, mockNotificationListenerCheckJobService)
+ }
+ }
+
+ verify(mockNotificationListenerCheckJobService).jobFinished(jobParameters, true)
+ }
+
+ @Test
+ fun getEnabledNotificationListenersAndNotifyIfNeeded_finishJob() {
+ val jobParameters = mock(JobParameters::class.java)
+
+ runWithShellPermissionIdentity {
+ runBlocking {
+ notificationListenerCheck.getEnabledNotificationListenersAndNotifyIfNeeded(
+ jobParameters, mockNotificationListenerCheckJobService)
+ }
+ }
+
+ verify(mockNotificationListenerCheckJobService).jobFinished(jobParameters, false)
+ }
+
+ @Test
+ fun getEnabledNotificationListenersAndNotifyIfNeeded_sendsDataToSafetyCenter() {
+ val jobParameters = mock(JobParameters::class.java)
+
+ runWithShellPermissionIdentity {
+ runBlocking {
+ notificationListenerCheck.getEnabledNotificationListenersAndNotifyIfNeeded(
+ jobParameters, mockNotificationListenerCheckJobService)
+ }
+ }
+
+ verify(mockSafetyCenterManager)
+ .setSafetySourceData(
+ eq(SC_NLS_SOURCE_ID),
+ any(SafetySourceData::class.java),
+ any(SafetyEvent::class.java))
+ }
+
+ @Test
+ fun removeDisabledComponentsFromNotifiedComponents() {
+ val testComponent = ComponentName("com.test.package", "TestClass")
+ val testComponent2 = ComponentName("com.test.package2", "TestClass2")
+ val initialEnabledComponents = listOf(testComponent, testComponent2)
+ val updatedEnabledComponents = listOf(testComponent2)
+
+ // Mark all components as notified, and get the resulting list of ComponentNames
+ val initialNlsComponents = runBlocking {
+ initialEnabledComponents.forEach {
+ notificationListenerCheck.markComponentAsNotified(it)
+ }
+ getNotifiedComponents()
+ }
+
+ // Verify expected components are present
+ assertThat(initialNlsComponents).isNotNull()
+ assertThat(initialNlsComponents.size).isEqualTo(initialEnabledComponents.size)
+ initialEnabledComponents.forEach { assertThat(initialNlsComponents.contains(it)).isTrue() }
+
+ // Forget about test package, and get the resulting list of ComponentNames
+ // Filter to the component that match the test component
+ val updatedNlsComponents = runWithShellPermissionIdentity {
+ runBlocking {
+ notificationListenerCheck.removeDisabledComponentsFromNotifiedComponents(
+ updatedEnabledComponents)
+ getNotifiedComponents()
+ }
+ }
+
+ // Verify expected components are present
+ assertThat(updatedNlsComponents).isNotNull()
+ assertThat(updatedNlsComponents.size).isEqualTo(updatedEnabledComponents.size)
+ updatedEnabledComponents.forEach { assertThat(updatedNlsComponents.contains(it)).isTrue() }
+ }
+
+ @Test
+ fun markAsNotified() {
+ val testComponent = ComponentName("com.test.package", "TestClass")
+
+ // Mark as notified, and get the resulting list of ComponentName
+ // Filter to the component that match the test component
+ // Ensure size is equal to one (not empty)
+ runBlocking {
+ notificationListenerCheck.markComponentAsNotified(testComponent)
+ getNotifiedComponents()
+ }
+ .filter { it == testComponent }
+ .also { assertThat(it.size).isEqualTo(1) }
+ }
+
+ @Test
+ fun markAsNotified_notifySecondComponent() {
+ val testComponent = ComponentName("com.test.package", "TestClass")
+ val testComponent2 = ComponentName("com.test.package2", "TestClass2")
+
+ // Mark as notified, and get the resulting list of ComponentNames
+ var nlsComponents = runBlocking {
+ notificationListenerCheck.markComponentAsNotified(testComponent)
+ getNotifiedComponents()
+ }
+ // Expected # components is 1
+ assertThat(nlsComponents.size).isEqualTo(1)
+
+ // Filter to the component that match the test component
+ // Ensure size is equal to one (not empty)
+ nlsComponents.filter { it == testComponent }.also { assertThat(it.size).isEqualTo(1) }
+
+ // Mark second component as notified, and get the resulting list of ComponentNames
+ nlsComponents = runBlocking {
+ notificationListenerCheck.markComponentAsNotified(testComponent2)
+ getNotifiedComponents()
+ }
+ // Expected # components is 2
+ assertThat(nlsComponents.size).isEqualTo(2)
+
+ // Filter to the component that match the test component
+ // Ensure size is equal to one (not empty)
+ nlsComponents.filter { it == testComponent2 }.also { assertThat(it.size).isEqualTo(1) }
+ }
+
+ @Test
+ fun markAsNotified_notifySecondComponent_ensureFirstComponentNotModified() {
+ val testComponent = ComponentName("com.test.package", "TestClass")
+ val testComponent2 = ComponentName("com.test.package2", "TestClass2")
+
+ // Mark as notified, and get the resulting list of ComponentNames
+ var nlsComponents = runBlocking {
+ notificationListenerCheck.markComponentAsNotified(testComponent)
+ getNotifiedComponents()
+ }
+ // Expected # components is 1
+ assertThat(nlsComponents.size).isEqualTo(1)
+
+ // Filter to the component that match the test component
+ // Ensure size is equal to one (not empty)
+ // Get the component
+ val firstComponent =
+ nlsComponents
+ .filter { it == testComponent }
+ .also { assertThat(it.size).isEqualTo(1) }[0]
+
+ // Mark second component as notified, and get the resulting list of ComponentNames
+ nlsComponents = runBlocking {
+ notificationListenerCheck.markComponentAsNotified(testComponent2)
+ getNotifiedComponents()
+ }
+ // Expected # components is 2
+ assertThat(nlsComponents.size).isEqualTo(2)
+
+ // Verify first notified component still present
+ assertThat(nlsComponents.contains(firstComponent)).isTrue()
+ }
+
+ @Test
+ fun removeFromNotifiedComponents() {
+ val testComponent = ComponentName("com.test.package", "TestClass")
+ val testComponent2 = ComponentName("com.test.package2", "TestClass2")
+ val testComponents = listOf(testComponent, testComponent2)
+
+ // Mark all components as notified, and get the resulting list of ComponentNames
+ val initialNlsComponents = runBlocking {
+ testComponents.forEach { notificationListenerCheck.markComponentAsNotified(it) }
+ getNotifiedComponents()
+ }
+
+ // Verify expected components are present
+ assertThat(initialNlsComponents).isNotNull()
+ assertThat(initialNlsComponents.size).isEqualTo(testComponents.size)
+ testComponents.forEach { assertThat(initialNlsComponents.contains(it)).isTrue() }
+
+ // Forget about test package, and get the resulting list of ComponentNames
+ // Filter to the component that match the test component
+ val updatedNlsComponents = runWithShellPermissionIdentity {
+ runBlocking {
+ notificationListenerCheck.removeFromNotifiedComponents(testComponent.packageName)
+ getNotifiedComponents()
+ }
+ }
+
+ // Verify expected components are present
+ assertThat(updatedNlsComponents).isNotNull()
+ assertThat(updatedNlsComponents.size).isEqualTo(testComponents.size - 1)
+ assertThat(updatedNlsComponents.contains(testComponent)).isFalse()
+ assertThat(updatedNlsComponents.contains(testComponent2)).isTrue()
+ }
+
+ @Test
+ fun removeFromNotifiedComponents_multipleNlsPerPackage() {
+ val testComponent = ComponentName("com.test.package", "TestClass")
+ val testComponent2 = ComponentName("com.test.package", "TestClass2")
+ val testComponents = listOf(testComponent, testComponent2)
+
+ // Mark all components as notified, and get the resulting list of ComponentNames
+ val initialNlsComponents = runBlocking {
+ testComponents.forEach { notificationListenerCheck.markComponentAsNotified(it) }
+ getNotifiedComponents()
+ }
+
+ // Verify expected components are present
+ assertThat(initialNlsComponents).isNotNull()
+ assertThat(initialNlsComponents.size).isEqualTo(testComponents.size)
+ testComponents.forEach { assertThat(initialNlsComponents.contains(it)).isTrue() }
+
+ // Forget about test package, and get the resulting list of ComponentNames
+ // Filter to the component that match the test component
+ val updatedNlsComponents = runWithShellPermissionIdentity {
+ runBlocking {
+ notificationListenerCheck.removeFromNotifiedComponents(testComponent.packageName)
+ getNotifiedComponents()
+ }
+ }
+
+ // Ensure empty
+ assertThat(updatedNlsComponents).isEmpty()
+ }
+
+ @Test
+ fun removeFromNotifiedComponents_noPreviouslyNotifiedPackage() {
+ val testComponent = ComponentName("com.test.package", "TestClass")
+
+ // Forget about test package, and get the resulting list of ComponentNames
+ // Filter to the component that match the test component
+ val updatedNlsComponents = runWithShellPermissionIdentity {
+ runBlocking {
+ // Verify this should not fail!
+ notificationListenerCheck.removeFromNotifiedComponents(testComponent.packageName)
+ getNotifiedComponents()
+ }
+ }
+
+ // Verify no components are present
+ assertThat(updatedNlsComponents).isEmpty()
+ }
+
+ @Test
+ fun removeFromNotifiedComponents_componentName() {
+ val testComponent = ComponentName("com.test.package", "TestClass")
+ val testComponent2 = ComponentName("com.test.package2", "TestClass2")
+ val testComponents = listOf(testComponent, testComponent2)
+
+ // Mark all components as notified, and get the resulting list of ComponentNames
+ val initialNlsComponents = runBlocking {
+ testComponents.forEach { notificationListenerCheck.markComponentAsNotified(it) }
+ getNotifiedComponents()
+ }
+
+ // Verify expected components are present
+ assertThat(initialNlsComponents).isNotNull()
+ assertThat(initialNlsComponents.size).isEqualTo(testComponents.size)
+ testComponents.forEach { assertThat(initialNlsComponents.contains(it)).isTrue() }
+
+ // Forget about test component, and get the resulting list of ComponentNames
+ // Filter to the component that match the test component
+ val updatedNlsComponents = runWithShellPermissionIdentity {
+ runBlocking {
+ notificationListenerCheck.removeFromNotifiedComponents(testComponent)
+ getNotifiedComponents()
+ }
+ }
+
+ // Verify expected components are present
+ assertThat(updatedNlsComponents).isNotNull()
+ assertThat(updatedNlsComponents.size).isEqualTo(testComponents.size - 1)
+ assertThat(updatedNlsComponents.contains(testComponent)).isFalse()
+ assertThat(updatedNlsComponents.contains(testComponent2)).isTrue()
+ }
+
+ @Test
+ fun removeFromNotifiedComponents_componentName_multipleNlsPerPackage() {
+ val testComponent = ComponentName("com.test.package", "TestClass")
+ val testComponent2 = ComponentName("com.test.package", "TestClass2")
+ val testComponents = listOf(testComponent, testComponent2)
+
+ // Mark all components as notified, and get the resulting list of ComponentNames
+ val initialNlsComponents = runBlocking {
+ testComponents.forEach { notificationListenerCheck.markComponentAsNotified(it) }
+ getNotifiedComponents()
+ }
+
+ // Verify expected components are present
+ assertThat(initialNlsComponents).isNotNull()
+ assertThat(initialNlsComponents.size).isEqualTo(testComponents.size)
+ testComponents.forEach { assertThat(initialNlsComponents.contains(it)).isTrue() }
+
+ // Forget about test component, and get the resulting list of ComponentNames
+ // Filter to the component that match the test component
+ val updatedNlsComponents = runWithShellPermissionIdentity {
+ runBlocking {
+ notificationListenerCheck.removeFromNotifiedComponents(testComponent)
+ getNotifiedComponents()
+ }
+ }
+
+ // Verify expected components are present
+ assertThat(updatedNlsComponents).isNotNull()
+ assertThat(updatedNlsComponents.size).isEqualTo(testComponents.size - 1)
+ assertThat(updatedNlsComponents.contains(testComponent)).isFalse()
+ assertThat(updatedNlsComponents.contains(testComponent2)).isTrue()
+ }
+
+ @Test
+ fun removeFromNotifiedComponents_componentName_noPreviouslyNotifiedPackage() {
+ val testComponent = ComponentName("com.test.package", "TestClass")
+
+ // Forget about test component, and get the resulting list of ComponentNames
+ // Filter to the component that match the test component
+ val updatedNlsComponents = runWithShellPermissionIdentity {
+ runBlocking {
+ // Verify this should not fail!
+ notificationListenerCheck.removeFromNotifiedComponents(testComponent)
+ getNotifiedComponents()
+ }
+ }
+
+ // Verify no components are present
+ assertThat(updatedNlsComponents).isEmpty()
+ }
+
+ @Test
+ fun createSafetySourceIssue() {
+ val testComponent = ComponentName("com.test.package", "TestClass")
+ val testAppLabel = "TestApp Label"
+ doReturn(PackageInfo().apply { applicationInfo = ApplicationInfo() }).`when` {
+ Utils.getPackageInfoForComponentName(
+ any(Context::class.java), any(ComponentName::class.java))
+ }
+ doReturn(testAppLabel).`when` {
+ Utils.getApplicationLabel(any(Context::class.java), any(ApplicationInfo::class.java))
+ }
+
+ val safetySourceIssue =
+ Preconditions.checkNotNull(
+ notificationListenerCheck.createSafetySourceIssue(testComponent, 0))
+
+ val expectedId = "notification_listener_${testComponent.flattenToString()}"
+ val expectedTitle =
+ context.getString(R.string.notification_listener_reminder_notification_title)
+ val expectedSubtitle: String = testAppLabel.toString()
+ val expectedSummary = context.getString(R.string.notification_listener_warning_card_content)
+ val expectedSeverityLevel = SafetySourceData.SEVERITY_LEVEL_INFORMATION
+ val expectedIssueTypeId = NotificationListenerCheckInternal.SC_NLS_ISSUE_TYPE_ID
+ val expectedDismissIntent =
+ Intent(context, NotificationListenerActionCardDismissalReceiver::class.java).apply {
+ putExtra(Intent.EXTRA_COMPONENT_NAME, testComponent)
+ flags = Intent.FLAG_RECEIVER_FOREGROUND
+ identifier = testComponent.flattenToString()
+ }
+ val expectedDismissPendingIntent =
+ PendingIntent.getBroadcast(
+ 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))
+ .setWillResolve(true)
+ .setSuccessMessage(
+ 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))
+ .build()
+
+ assertThat(safetySourceIssue.id).isEqualTo(expectedId)
+ assertThat(safetySourceIssue.title).isEqualTo(expectedTitle)
+ assertThat(safetySourceIssue.subtitle).isEqualTo(expectedSubtitle)
+ assertThat(safetySourceIssue.summary).isEqualTo(expectedSummary)
+ assertThat(safetySourceIssue.severityLevel).isEqualTo(expectedSeverityLevel)
+ assertThat(safetySourceIssue.issueTypeId).isEqualTo(expectedIssueTypeId)
+ assertThat(safetySourceIssue.onDismissPendingIntent).isEqualTo(expectedDismissPendingIntent)
+ assertThat(safetySourceIssue.actions.size).isEqualTo(2)
+ assertThat(safetySourceIssue.actions).containsExactly(expectedAction2, expectedAction1)
+ }
+
+ @Test
+ fun exemptPackagesNotInitializedUntilUsed() {
+ assertThat(notificationListenerCheck.exemptPackagesDelegate.isInitialized()).isFalse()
+ runWithShellPermissionIdentity {
+ notificationListenerCheck.exemptPackages
+ }
+ assertThat(notificationListenerCheck.exemptPackagesDelegate.isInitialized()).isTrue()
+ }
+
+ private fun getNotifiedComponents(): Set<ComponentName> = runBlocking {
+ notificationListenerCheck
+ .getNotifiedComponents()
+ .mapNotNull { ComponentName.unflattenFromString(it) }
+ .toSet()
+ }
+
+ /** @return [PendingIntent] for remove access button on the warning card. */
+ private fun getDisableNlsPendingIntent(
+ context: Context,
+ safetySourceIssueId: String,
+ componentName: ComponentName
+ ): PendingIntent {
+ val intent =
+ Intent(context, DisableNotificationListenerComponentHandler::class.java).apply {
+ putExtra(SafetyCenterManager.EXTRA_SAFETY_SOURCE_ISSUE_ID, safetySourceIssueId)
+ putExtra(Intent.EXTRA_COMPONENT_NAME, componentName)
+ flags = Intent.FLAG_RECEIVER_FOREGROUND
+ identifier = componentName.flattenToString()
+ }
+
+ return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
+ }
+
+ /** @return [PendingIntent] to Notification Listener Settings page */
+ private fun getNotificationListenerSettingsPendingIntent(
+ context: Context,
+ componentName: ComponentName
+ ): PendingIntent {
+ val intent =
+ Intent(Settings.ACTION_NOTIFICATION_LISTENER_DETAIL_SETTINGS).apply {
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ identifier = componentName.flattenToString()
+ putExtra(
+ Settings.EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME,
+ componentName.flattenToString())
+ }
+ return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
+ }
+
+ private fun clearSharedPrefState() {
+ context
+ .getSharedPreferences(NLS_PREFERENCE_FILE, Context.MODE_PRIVATE)
+ .edit()
+ .clear()
+ .apply()
+ }
+
+ private fun <R> runWithShellPermissionIdentity(block: () -> R): R {
+ val uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ uiAutomation.adoptShellPermissionIdentity()
+ try {
+ return block()
+ } finally {
+ uiAutomation.dropShellPermissionIdentity()
+ }
+ }
+}
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
new file mode 100644
index 000000000..d8d4b3866
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerPregrantsTest.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.permissioncontroller.tests.mocking.privacysources
+
+import android.content.Context
+import android.os.Build
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.privacysources.NotificationListenerPregrants
+import org.junit.After
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+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 NotificationListenerPregrantsTest {
+ private lateinit var mockitoSession: MockitoSession
+ private lateinit var context: Context
+
+ private lateinit var notificationListenerPregrants: NotificationListenerPregrants
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ context = ApplicationProvider.getApplicationContext()
+
+ mockitoSession = ExtendedMockito.mockitoSession()
+ .mockStatic(Utils::class.java)
+ .strictness(Strictness.LENIENT).startMocking()
+
+ notificationListenerPregrants = NotificationListenerPregrants(context)
+ }
+
+ @After
+ fun cleanup() {
+ mockitoSession.finishMocking()
+ }
+
+ @Test
+ fun getPregrantedPackages() {
+ val pregrants: Set<String> = notificationListenerPregrants.pregrantedPackages
+ assertTrue(pregrants.isNotEmpty())
+ }
+
+ @Test
+ fun pregrantedPackagesNotInitializedUntilUsed() {
+ assertFalse(notificationListenerPregrants.pregrantedPackagesDelegate.isInitialized())
+ 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
new file mode 100644
index 000000000..9c1edb795
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/NotificationListenerPrivacySourceTest.kt
@@ -0,0 +1,316 @@
+/*
+ * 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.permissioncontroller.tests.mocking.privacysources
+
+import android.app.NotificationManager
+import android.app.role.RoleManager
+import android.content.ComponentName
+import android.content.Context
+import android.content.ContextWrapper
+import android.content.Intent
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageInfo
+import android.os.Build
+import android.os.UserHandle
+import android.os.UserManager
+import android.provider.DeviceConfig
+import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetyEvent
+import android.safetycenter.SafetySourceData
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+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.privacysources.NotificationListenerCheckInternal
+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
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+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
+
+@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
+
+ private lateinit var context: Context
+ private lateinit var notificationListenerCheck: NotificationListenerCheckInternal
+
+ private val privacySource: NotificationListenerPrivacySource =
+ NotificationListenerPrivacySource()
+
+ companion object {
+ private val testComponent1 = ComponentName("com.test.package", "TestClass1")
+ private val testComponent2 = ComponentName("com.test.package", "TestClass2")
+ private val enabledComponents = listOf(testComponent1, testComponent2)
+ }
+
+ @Before
+ fun setup() {
+ 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()
+
+ // Setup default flagging
+ setNotificationListenerCheckEnabled(true)
+
+ // Setup contexts
+ 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)))
+ .thenReturn(packageInfo1)
+ whenever(Utils.getPackageInfoForComponentName(
+ any(ContextWrapper::class.java),
+ eq(testComponent2)))
+ .thenReturn(packageInfo2)
+ whenever(Utils.getApplicationLabel(
+ any(ContextWrapper::class.java),
+ eq(packageInfo1.applicationInfo)))
+ .thenReturn(testComponent1.className)
+ 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)))
+ .thenReturn(mockUserManager)
+ whenever(mockUserManager.getProfileParent(any(UserHandle::class.java)))
+ .thenReturn(null)
+
+ // Setup Notification Manager
+ 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)))
+ .thenReturn(mockRoleManager)
+ whenever(mockRoleManager.getRoleHolders(anyString()))
+ .thenReturn(emptyList())
+
+ // Setup Safety Center
+ whenever(Utils.getSystemServiceSafe(
+ any(ContextWrapper::class.java),
+ eq(SafetyCenterManager::class.java)))
+ .thenReturn(mockSafetyCenterManager)
+
+ // Init NotificationListenerCheckInternal, used to quickly create expected SafetySourceData
+ notificationListenerCheck = runWithShellPermissionIdentity {
+ NotificationListenerCheckInternal(context, null)
+ }
+ }
+
+ @After
+ fun cleanup() {
+ mockitoSession.finishMocking()
+ }
+
+ @Test
+ fun safetyCenterEnabledChanged_removesNotifications() {
+ runWithShellPermissionIdentity {
+ privacySource.safetyCenterEnabledChanged(context, false)
+ }
+
+ verify(mockNotificationManager).cancel(NOTIFICATION_LISTENER_CHECK_NOTIFICATION_ID)
+ }
+
+ @Test
+ fun safetyCenterEnabledChanged_doesNotUpdateSafetyCenterData() {
+ runWithShellPermissionIdentity {
+ privacySource.safetyCenterEnabledChanged(context, false)
+ }
+
+ verify(mockSafetyCenterManager, never())
+ .setSafetySourceData(
+ eq(SC_NLS_SOURCE_ID),
+ any(SafetySourceData::class.java),
+ any(SafetyEvent::class.java))
+ }
+
+ @Test
+ fun safetyCenterEnabledChanged_notificationListenerCheckDisabled_noSafetyCenterInteractions() {
+ setNotificationListenerCheckEnabled(false)
+
+ privacySource.safetyCenterEnabledChanged(context, false)
+
+ verifyZeroInteractions(mockSafetyCenterManager)
+ }
+
+ @Test
+ fun rescanAndPushSafetyCenterData_eventDeviceRebooted_updateSafetyCenterData() {
+ privacySource.rescanAndPushSafetyCenterData(
+ context,
+ Intent(Intent.ACTION_BOOT_COMPLETED),
+ SafetyCenterReceiver.RefreshEvent.EVENT_DEVICE_REBOOTED
+ )
+
+ val expectedSafetySourceData: SafetySourceData = createExpectedSafetyCenterData()
+ val expectedSafetyEvent =
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build()
+
+ verify(mockSafetyCenterManager)
+ .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)
+ privacySource.rescanAndPushSafetyCenterData(
+ context,
+ intent,
+ SafetyCenterReceiver.RefreshEvent.EVENT_REFRESH_REQUESTED
+ )
+
+ val expectedSafetySourceData: SafetySourceData = createExpectedSafetyCenterData()
+
+ val refreshBroadcastId =
+ intent.getStringExtra(SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID)
+ val expectedSafetyEvent =
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
+ .setRefreshBroadcastId(refreshBroadcastId)
+ .build()
+
+ verify(mockSafetyCenterManager)
+ .setSafetySourceData(
+ SC_NLS_SOURCE_ID,
+ expectedSafetySourceData,
+ expectedSafetyEvent
+ )
+ }
+
+ @Test
+ fun rescanAndPushSafetyCenterData_updatesSafetyCenterEventUnknown() {
+ privacySource.rescanAndPushSafetyCenterData(
+ context,
+ Intent(Intent.ACTION_BOOT_COMPLETED),
+ SafetyCenterReceiver.RefreshEvent.UNKNOWN
+ )
+
+ val expectedSafetySourceData: SafetySourceData = createExpectedSafetyCenterData()
+ val expectedSafetyEvent =
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
+
+ verify(mockSafetyCenterManager)
+ .setSafetySourceData(
+ SC_NLS_SOURCE_ID,
+ expectedSafetySourceData,
+ expectedSafetyEvent
+ )
+ }
+
+ @Test
+ fun rescanAndPushSafetyCenterData_notificationListenerCheckDisabled_noSafetyCenterInteractions
+ () {
+ setNotificationListenerCheckEnabled(false)
+
+ privacySource.rescanAndPushSafetyCenterData(
+ context,
+ Intent(Intent.ACTION_BOOT_COMPLETED),
+ SafetyCenterReceiver.RefreshEvent.UNKNOWN
+ )
+
+ verifyZeroInteractions(mockSafetyCenterManager)
+ }
+
+ private fun setNotificationListenerCheckEnabled(enabled: Boolean) {
+ whenever(
+ DeviceConfig.getBoolean(
+ eq(DeviceConfig.NAMESPACE_PRIVACY),
+ eq(PROPERTY_NOTIFICATION_LISTENER_CHECK_ENABLED),
+ anyBoolean()
+ )
+ ).thenReturn(enabled)
+ }
+
+ private fun getPackageInfo(): PackageInfo {
+ return PackageInfo().apply {
+ applicationInfo = ApplicationInfo()
+ }
+ }
+
+ private fun createExpectedSafetyCenterData(): SafetySourceData {
+ val pendingIssues =
+ enabledComponents.mapNotNull {
+ notificationListenerCheck.createSafetySourceIssue(it, 0)
+ }
+ val dataBuilder = SafetySourceData.Builder()
+ pendingIssues.forEach { dataBuilder.addIssue(it) }
+ return dataBuilder.build()
+ }
+}
+
+private fun <R> runWithShellPermissionIdentity(block: () -> R): R {
+ val uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ uiAutomation.adoptShellPermissionIdentity()
+ try {
+ return block()
+ } finally {
+ uiAutomation.dropShellPermissionIdentity()
+ }
+}
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 bd6d500df..b4b1abd96 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
@@ -16,9 +16,14 @@
package com.android.permissioncontroller.tests.mocking.privacysources
+import android.content.Context
+import android.content.ContextWrapper
import android.content.Intent
import android.content.Intent.ACTION_BOOT_COMPLETED
+import android.content.pm.PackageManager
import android.os.Build
+import android.os.UserManager
+import android.provider.DeviceConfig
import android.safetycenter.SafetyCenterManager
import android.safetycenter.SafetyCenterManager.ACTION_REFRESH_SAFETY_SOURCES
import android.safetycenter.SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED
@@ -27,6 +32,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.permissioncontroller.PermissionControllerApplication
+import com.android.permissioncontroller.permission.service.v33.SafetyCenterQsTileService
+import com.android.permissioncontroller.permission.utils.Utils
import com.android.permissioncontroller.privacysources.PrivacySource
import com.android.permissioncontroller.privacysources.SafetyCenterReceiver
import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent.EVENT_DEVICE_REBOOTED
@@ -44,6 +51,9 @@ import org.junit.Before
import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+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
@@ -68,19 +78,23 @@ class SafetyCenterReceiverTest {
val application = Mockito.mock(PermissionControllerApplication::class.java)
}
- private val testCoroutineDispatcher: TestCoroutineDispatcher = TestCoroutineDispatcher()
+ 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
private lateinit var mockitoSession: MockitoSession
private lateinit var safetyCenterReceiver: SafetyCenterReceiver
- private fun privacySourceMap() = mapOf(
+ private fun privacySourceMap(context: Context) = mapOf(
TEST_PRIVACY_SOURCE_ID to mockPrivacySource,
TEST_PRIVACY_SOURCE_ID_2 to mockPrivacySource2
)
@@ -90,14 +104,26 @@ class SafetyCenterReceiverTest {
MockitoAnnotations.initMocks(this)
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.getSystemService(SafetyCenterManager::class.java))
- .thenReturn(mockSafetyCenterManager)
+ whenever(application.packageManager).thenReturn(mockPackageManager)
whenever(mockSafetyCenterManager.isSafetyCenterEnabled).thenReturn(true)
+ whenever(
+ Utils.getSystemServiceSafe(
+ any(ContextWrapper::class.java), eq(UserManager::class.java)
+ ))
+ .thenReturn(mockUserManager)
+ whenever(
+ Utils.getSystemServiceSafe(
+ any(ContextWrapper::class.java), eq(SafetyCenterManager::class.java)
+ ))
+ .thenReturn(mockSafetyCenterManager)
+ whenever(mockUserManager.isProfile).thenReturn(false)
safetyCenterReceiver = SafetyCenterReceiver(::privacySourceMap, testCoroutineDispatcher)
@@ -112,23 +138,35 @@ class SafetyCenterReceiverTest {
mockitoSession.finishMocking()
}
+ private fun mockQSTileSettingsFlag() {
+ whenever(
+ DeviceConfig.getInt(
+ eq(DeviceConfig.NAMESPACE_PRIVACY),
+ eq(SafetyCenterQsTileService.QS_TILE_COMPONENT_SETTING_FLAGS),
+ ArgumentMatchers.anyInt()
+ )
+ ).thenReturn(PackageManager.DONT_KILL_APP)
+ }
+
@Test
fun onReceive_actionSafetyCenterEnabledChanged() = runBlockingTest {
+ mockQSTileSettingsFlag()
safetyCenterReceiver.onReceive(application, Intent(ACTION_SAFETY_CENTER_ENABLED_CHANGED))
- verify(mockPrivacySource).safetyCenterEnabledChanged(true)
- verify(mockPrivacySource2).safetyCenterEnabledChanged(true)
+ verify(mockPrivacySource).safetyCenterEnabledChanged(application, true)
+ verify(mockPrivacySource2).safetyCenterEnabledChanged(application, true)
}
@Test
fun onReceive_actionSafetyCenterEnabledChanged_safetyCenterDisabled() = runBlockingTest {
+ mockQSTileSettingsFlag()
whenever(mockSafetyCenterManager.isSafetyCenterEnabled).thenReturn(false)
safetyCenterReceiver.onReceive(application, Intent(ACTION_SAFETY_CENTER_ENABLED_CHANGED))
advanceUntilIdle()
- verify(mockPrivacySource).safetyCenterEnabledChanged(false)
- verify(mockPrivacySource2).safetyCenterEnabledChanged(false)
+ verify(mockPrivacySource).safetyCenterEnabledChanged(application, false)
+ verify(mockPrivacySource2).safetyCenterEnabledChanged(application, false)
}
@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
new file mode 100644
index 000000000..15b9168ad
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/TextStorageRepositoryTest.kt
@@ -0,0 +1,146 @@
+/*
+ * 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.permissioncontroller.tests.mocking.privacysources
+
+import android.content.Context
+import android.os.Build
+import android.provider.DeviceConfig
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+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 org.junit.After
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Test
+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")
+class TextStorageRepositoryTest {
+
+ private lateinit var context: Context
+ private lateinit var mockitoSession: MockitoSession
+ private lateinit var dataFile: File
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ context = ApplicationProvider.getApplicationContext()
+
+ mockitoSession = ExtendedMockito.mockitoSession()
+ .mockStatic(DeviceConfig::class.java)
+ .strictness(Strictness.LENIENT).startMocking()
+
+ dataFile = context.getFileStreamPath("testFile")
+ }
+
+ @After
+ fun cleanup() {
+ context.deleteFile("testFile")
+ mockitoSession.finishMocking()
+ }
+
+ @Test
+ fun testEmptyFileReading() {
+ val storageRepository = TextStorageRepository(dataFile)
+ val dataList = storageRepository.readData(creator)
+ Assert.assertTrue(dataList.isEmpty())
+ }
+
+ @Test
+ fun testWrite() {
+ val storageRepository = TextStorageRepository(dataFile)
+ val component = TestPrivacySourceComponent("a", 100)
+ storageRepository.persistData(listOf(component))
+ val dataList = storageRepository.readData(creator)
+ Assert.assertEquals(1, dataList.size)
+ Assert.assertEquals(component.toStorageData(), dataList[0].toStorageData())
+ }
+
+ @Test
+ fun testWrite_MultipleEntries() {
+ val storageRepository = TextStorageRepository(dataFile)
+ 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)
+ }
+
+ @Test
+ fun testRead_Ignore_CorruptedEntries() {
+ val storageRepository = TextStorageRepository(dataFile)
+ 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")
+ appendCorruptedData(dataFile, "")
+ val dataList = storageRepository.readData(creator)
+ Assert.assertEquals(3, dataList.size)
+ }
+
+ @Test
+ fun testRead_Ignore_NumberFormatError() {
+ val storageRepository = TextStorageRepository(dataFile)
+ val components = listOf(TestPrivacySourceComponent("a", 100),
+ TestPrivacySourceComponent("b", 200)
+ )
+ storageRepository.persistData(components)
+ appendCorruptedData(dataFile, "com.example.TestService hundred")
+ appendCorruptedData(dataFile, "com.example.TestService1 abc")
+
+ val dataList: List<TestPrivacySourceComponent> = storageRepository.readData(creator)
+ Assert.assertEquals(2, dataList.size)
+ }
+
+ private fun appendCorruptedData(dataFile: File, data: String) {
+ BufferedWriter(FileWriter(dataFile, true)).use { writer ->
+ writer.write(data)
+ writer.newLine()
+ }
+ }
+
+ 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 {
+ 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
new file mode 100644
index 000000000..3e86d58b0
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/WorkPolicyInfoTest.kt
@@ -0,0 +1,307 @@
+/*
+ * 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.permissioncontroller.tests.mocking.privacysources
+
+import android.app.PendingIntent
+import android.content.Context
+import android.content.ContextWrapper
+import android.content.Intent
+import android.os.Build
+import android.os.UserManager
+import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetyEvent
+import android.safetycenter.SafetySourceData
+import android.safetycenter.SafetySourceStatus
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.permissioncontroller.PermissionControllerApplication
+import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.privacysources.SafetyCenterReceiver
+import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent
+import com.android.permissioncontroller.privacysources.WorkPolicyInfo
+import com.android.settingslib.utils.WorkPolicyUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito
+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] */
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+class WorkPolicyInfoTest {
+
+ private lateinit var mockitoSession: MockitoSession
+ private lateinit var workPolicyInfo: WorkPolicyInfo
+ @Mock lateinit var mockSafetyCenterManager: SafetyCenterManager
+ @Mock lateinit var mockWorkPolicyUtils: WorkPolicyUtils
+ @Mock lateinit var mockUserManager: UserManager
+
+ companion object {
+ // Real context is used in order to avoid mocking resources and other expected things
+ // eg: context.userId, context.getText etc
+ var context: Context = ApplicationProvider.getApplicationContext()
+ const val WORK_POLICY_TITLE: String = "workPolicyTitle"
+ const val WORK_POLICY_SUMMARY: String = "workPolicySummary"
+ }
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ mockitoSession =
+ ExtendedMockito.mockitoSession()
+ .mockStatic(PermissionControllerApplication::class.java)
+ .mockStatic(Utils::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
+
+ // Mock application is used to setup the services, eg.devicePolicyManager, userManager
+ val application = Mockito.mock(PermissionControllerApplication::class.java)
+ whenever(
+ Utils.getSystemServiceSafe(
+ any(ContextWrapper::class.java), eq(UserManager::class.java)))
+ .thenReturn(mockUserManager)
+ whenever(
+ Utils.getSystemServiceSafe(
+ 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()))
+ .thenReturn(WORK_POLICY_TITLE)
+ whenever(
+ Utils.getEnterpriseString(
+ any(ContextWrapper::class.java),
+ eq(WorkPolicyInfo.WORK_POLICY_SUMMARY),
+ anyInt()))
+ .thenReturn(WORK_POLICY_SUMMARY)
+
+ whenever(PermissionControllerApplication.get()).thenReturn(application)
+ whenever(application.applicationContext).thenReturn(application)
+ workPolicyInfo = WorkPolicyInfo(mockWorkPolicyUtils)
+ }
+
+ @After
+ fun cleanup() {
+ mockitoSession.finishMocking()
+ }
+
+ @Test
+ fun safetyCenterEnabledChanged_safetyCenterEnabled() {
+ val intent =
+ Intent(Intent.ACTION_BOOT_COMPLETED)
+ .putExtra(
+ 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.safetyCenterEnabledChanged(context, true)
+
+ val pendingIntent =
+ PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
+ val expectedSafetySourceStatus: SafetySourceStatus =
+ SafetySourceStatus.Builder(
+ WORK_POLICY_TITLE,
+ WORK_POLICY_SUMMARY,
+ SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED)
+ .setPendingIntent(pendingIntent)
+ .build()
+ val expectedSafetySourceData: SafetySourceData =
+ SafetySourceData.Builder().setStatus(expectedSafetySourceStatus).build()
+ val expectedSafetyEvent =
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
+
+ verify(mockSafetyCenterManager)
+ .setSafetySourceData(
+ WorkPolicyInfo.WORK_POLICY_INFO_SOURCE_ID,
+ expectedSafetySourceData,
+ expectedSafetyEvent)
+ }
+
+ @Test
+ fun safetyCenterEnabledChanged_safetyCenterDisabled() {
+ workPolicyInfo.safetyCenterEnabledChanged(context, false)
+
+ verifyZeroInteractions(mockSafetyCenterManager)
+ }
+
+ @Test
+ fun safetyCenterEnabledChanged_safetyCenterEnabled_hasWorkPolicyFalse() {
+ whenever(mockWorkPolicyUtils.hasWorkPolicy()).thenReturn(false)
+
+ workPolicyInfo.safetyCenterEnabledChanged(context, true)
+
+ val expectedSafetySourceData: SafetySourceData? = null
+ val expectedSafetyEvent =
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
+
+ verify(mockSafetyCenterManager)
+ .setSafetySourceData(
+ WorkPolicyInfo.WORK_POLICY_INFO_SOURCE_ID,
+ expectedSafetySourceData,
+ expectedSafetyEvent)
+ }
+
+ @Test
+ fun safetyCenterEnabledChanged_safetyCenterDisabled_hasWorkPolicyFalse() {
+ whenever(mockWorkPolicyUtils.hasWorkPolicy()).thenReturn(false)
+
+ workPolicyInfo.safetyCenterEnabledChanged(context, false)
+
+ verifyZeroInteractions(mockSafetyCenterManager)
+ }
+
+ @Test
+ fun rescanAndPushSafetyCenterData_eventRebooted_deviceOwner() {
+ val intent = Intent(Intent.ACTION_BOOT_COMPLETED)
+ whenever(mockWorkPolicyUtils.workPolicyInfoIntentDO).thenReturn(intent)
+ whenever(mockWorkPolicyUtils.workPolicyInfoIntentPO).thenReturn(null)
+
+ workPolicyInfo.rescanAndPushSafetyCenterData(
+ context, intent, RefreshEvent.EVENT_DEVICE_REBOOTED)
+
+ val pendingIntent =
+ PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
+ val expectedSafetySourceStatus: SafetySourceStatus =
+ SafetySourceStatus.Builder(
+ WORK_POLICY_TITLE,
+ WORK_POLICY_SUMMARY,
+ SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED)
+ .setPendingIntent(pendingIntent)
+ .build()
+
+ val expectedSafetySourceData: SafetySourceData =
+ SafetySourceData.Builder().setStatus(expectedSafetySourceStatus).build()
+ val expectedSafetyEvent =
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build()
+
+ verify(mockSafetyCenterManager)
+ .setSafetySourceData(
+ WorkPolicyInfo.WORK_POLICY_INFO_SOURCE_ID,
+ expectedSafetySourceData,
+ expectedSafetyEvent)
+ }
+
+ @Test
+ fun rescanAndPushSafetyCenterData_eventRefresh_deviceOwner() {
+ val intent =
+ Intent(Intent.ACTION_BOOT_COMPLETED)
+ .putExtra(
+ 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)
+
+ val pendingIntent =
+ PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
+ val expectedSafetySourceStatus: SafetySourceStatus =
+ SafetySourceStatus.Builder(
+ WORK_POLICY_TITLE,
+ WORK_POLICY_SUMMARY,
+ SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED)
+ .setPendingIntent(pendingIntent)
+ .build()
+
+ val expectedSafetySourceData: SafetySourceData =
+ SafetySourceData.Builder().setStatus(expectedSafetySourceStatus).build()
+
+ val refreshBroadcastId =
+ intent.getStringExtra(SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID)
+ val expectedSafetyEvent =
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
+ .setRefreshBroadcastId(refreshBroadcastId)
+ .build()
+
+ verify(mockSafetyCenterManager)
+ .setSafetySourceData(
+ WorkPolicyInfo.WORK_POLICY_INFO_SOURCE_ID,
+ expectedSafetySourceData,
+ expectedSafetyEvent)
+ }
+
+ @Test
+ fun rescanAndPushSafetyCenterData_eventUnknown_profileOwner() {
+ val intent = Intent(Intent.ACTION_BOOT_COMPLETED)
+
+ whenever(mockWorkPolicyUtils.workPolicyInfoIntentDO).thenReturn(null)
+ whenever(mockWorkPolicyUtils.workPolicyInfoIntentPO).thenReturn(intent)
+
+ val pendingIntent =
+ PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
+
+ workPolicyInfo.rescanAndPushSafetyCenterData(context, intent, RefreshEvent.UNKNOWN)
+
+ val expectedSafetySourceStatus: SafetySourceStatus =
+ SafetySourceStatus.Builder(
+ WORK_POLICY_TITLE,
+ WORK_POLICY_SUMMARY,
+ SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED)
+ .setPendingIntent(pendingIntent)
+ .build()
+
+ val expectedSafetySourceData: SafetySourceData =
+ SafetySourceData.Builder().setStatus(expectedSafetySourceStatus).build()
+ val expectedSafetyEvent =
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
+
+ verify(mockSafetyCenterManager)
+ .setSafetySourceData(
+ WorkPolicyInfo.WORK_POLICY_INFO_SOURCE_ID,
+ expectedSafetySourceData,
+ expectedSafetyEvent)
+ }
+
+ @Test
+ fun rescanAndPushSafetyCenterData_hasWorkPolicyFalse() {
+ whenever(mockWorkPolicyUtils.workPolicyInfoIntentPO).thenReturn(null)
+ whenever(mockWorkPolicyUtils.workPolicyInfoIntentDO).thenReturn(null)
+
+ val intent = Intent(Intent.ACTION_BOOT_COMPLETED)
+ workPolicyInfo.rescanAndPushSafetyCenterData(context, intent, RefreshEvent.UNKNOWN)
+
+ val expectedSafetySourceData: SafetySourceData? = null
+ val expectedSafetyEvent =
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
+
+ verify(mockSafetyCenterManager)
+ .setSafetySourceData(
+ WorkPolicyInfo.WORK_POLICY_INFO_SOURCE_ID,
+ expectedSafetySourceData,
+ expectedSafetyEvent)
+ }
+}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/role/model/RoleParserTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/role/model/RoleParserTest.kt
index b8bc2adf9..0989903d0 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/role/model/RoleParserTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/role/model/RoleParserTest.kt
@@ -18,16 +18,26 @@ package com.android.permissioncontroller.tests.mocking.role.model
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.permissioncontroller.role.model.RoleParser
+import com.android.permissioncontroller.role.model.RoleParserInitializer
+import com.android.role.controller.model.RoleParser
+import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class RoleParserTest {
+ companion object {
+ @BeforeClass
+ @JvmStatic
+ fun setupBeforeClass() {
+ RoleParserInitializer.initialize()
+ }
+ }
+
private val targetContext = InstrumentationRegistry.getInstrumentation().getTargetContext()
@Test
fun testParseRolesWithValidation() {
RoleParser(targetContext, true).parse()
}
-} \ No newline at end of file
+}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/OWNERS b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/OWNERS
new file mode 100644
index 000000000..5d8b8161b
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1026964
+
+include /SafetyCenter/OWNERS
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/SafetyStatusAnimationSequencerTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/SafetyStatusAnimationSequencerTest.kt
new file mode 100644
index 000000000..7c45b6fab
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/SafetyStatusAnimationSequencerTest.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.tests.mocking.safetycenter.ui
+
+import android.os.Build
+import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING
+import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import com.android.permissioncontroller.safetycenter.ui.SafetyStatusAnimationSequencer
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+class SafetyStatusAnimationSequencerTest {
+
+ private val sequencer: SafetyStatusAnimationSequencer = SafetyStatusAnimationSequencer()
+
+ @Test
+ fun getCurrentlyVisibleSeverityLevel_returnsUnknown() {
+ assertThat(sequencer.getCurrentlyVisibleSeverityLevel())
+ .isEqualTo(OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ }
+
+ @Test
+ fun getCurrentlyVisibleSeverityLevel_refreshingWithCriticalSeverity_returnsCritical() {
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ sequencer.onStartScanningAnimationStart()
+
+ assertThat(sequencer.getCurrentlyVisibleSeverityLevel())
+ .isEqualTo(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ }
+
+ @Test
+ fun getCurrentlyVisibleSeverityLevel_severityChangedToCriticalWhileRefreshing_returnsUnknown() {
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onStartScanningAnimationStart()
+
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+
+ assertThat(sequencer.getCurrentlyVisibleSeverityLevel())
+ .isEqualTo(OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ }
+
+ @Test
+ fun getCurrentlyVisibleSeverityLevel_refreshingStartedUnknownStoppedCritical_returnsUnknown() {
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onStartScanningAnimationStart()
+
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+
+ assertThat(sequencer.getCurrentlyVisibleSeverityLevel())
+ .isEqualTo(OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ }
+
+ @Test
+ fun getCurrentlyVisibleSeverityLevel_scanAnimationEndedAfterStoppedCritical_returnsCritical() {
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onStartScanningAnimationStart()
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+
+ sequencer.onFinishScanAnimationEnd(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+
+ assertThat(sequencer.getCurrentlyVisibleSeverityLevel())
+ .isEqualTo(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ }
+
+ @Test
+ fun getCurrentlyVisibleSeverityLevel_continueScanEndedRefreshingCritical_returnsCritical() {
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onStartScanningAnimationStart()
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+
+ sequencer.onContinueScanningAnimationEnd(
+ REFRESHING,
+ OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING
+ )
+
+ assertThat(sequencer.getCurrentlyVisibleSeverityLevel())
+ .isEqualTo(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ }
+
+ @Test
+ fun getCurrentlyVisibleSeverityLevel_continueScanEndedNotRefreshingCritical_returnsUnknown() {
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onStartScanningAnimationStart()
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+
+ sequencer.onContinueScanningAnimationEnd(
+ NOT_REFRESHING,
+ OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING
+ )
+
+ assertThat(sequencer.getCurrentlyVisibleSeverityLevel())
+ .isEqualTo(OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ }
+
+ @Test
+ fun getCurrentlyVisibleSeverityLevel_iconChangeAnimationQueuedCritical_returnsUnknown() {
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+
+ assertThat(sequencer.getCurrentlyVisibleSeverityLevel())
+ .isEqualTo(OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ }
+
+ @Test
+ fun getCurrentlyVisibleSeverityLevel_iconChangeAnimationEndedUnknown_returnsUnknown() {
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+
+ sequencer.onIconChangeAnimationEnd(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+
+ assertThat(sequencer.getCurrentlyVisibleSeverityLevel())
+ .isEqualTo(OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ }
+
+ @Test
+ fun getCurrentlyVisibleSeverityLevel_iconChangeAnimationEndedCritical_returnsCritical() {
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+
+ sequencer.onIconChangeAnimationEnd(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+
+ assertThat(sequencer.getCurrentlyVisibleSeverityLevel())
+ .isEqualTo(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ }
+
+ @Test
+ fun onContinueScanningAnimationEnd_whileRefreshing_returnsContinueScanning() {
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onStartScanningAnimationStart()
+ sequencer.onStartScanningAnimationEnd()
+
+ assertThat(
+ sequencer.onContinueScanningAnimationEnd(REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ )
+ .isEqualTo(SafetyStatusAnimationSequencer.Action.CONTINUE_SCANNING_ANIMATION)
+ }
+
+ @Test
+ fun onContinueScanningAnimationEnd_afterRefreshingStoppedUnknown_returnsNull() {
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onStartScanningAnimationStart()
+ sequencer.onStartScanningAnimationEnd()
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+
+ assertThat(
+ sequencer.onContinueScanningAnimationEnd(
+ NOT_REFRESHING,
+ OVERALL_SEVERITY_LEVEL_UNKNOWN
+ )
+ )
+ .isNull()
+ }
+
+ @Test
+ fun onContinueScanningAnimationEnd_afterRefreshingStoppedCritical_returnsResetScanning() {
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onStartScanningAnimationStart()
+ sequencer.onStartScanningAnimationEnd()
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+
+ assertThat(
+ sequencer.onContinueScanningAnimationEnd(
+ REFRESHING,
+ OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING
+ )
+ )
+ .isEqualTo(SafetyStatusAnimationSequencer.Action.RESET_SCANNING_ANIMATION)
+ }
+
+ @Test
+ fun onUpdateReceived_whileRefreshing_returnsStartScanning() {
+ assertThat(sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN))
+ .isEqualTo(SafetyStatusAnimationSequencer.Action.START_SCANNING_ANIMATION)
+ }
+
+ @Test
+ fun onUpdateReceived_notRefreshingCriticalSeverityLevel_returnsStartIconChangeAnimation() {
+ assertThat(
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ )
+ .isEqualTo(SafetyStatusAnimationSequencer.Action.START_ICON_CHANGE_ANIMATION)
+ }
+
+ @Test
+ fun onUpdateReceived_notRefreshingUnknownSeverityLevel_returnsChangeIcon() {
+ assertThat(sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN))
+ .isEqualTo(SafetyStatusAnimationSequencer.Action.CHANGE_ICON_WITHOUT_ANIMATION)
+ }
+
+ @Test
+ fun onUpdateReceived_refreshingWhileIconChangeAnimationRunning_returnsNull() {
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ sequencer.onIconChangeAnimationStart()
+
+ assertThat(sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING))
+ .isNull()
+ }
+
+ @Test
+ fun onUpdateReceived_UnknownSeverityWhileCriticalIconChangeAnimationRunning_returnsNull() {
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ sequencer.onIconChangeAnimationStart()
+
+ assertThat(sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN))
+ .isNull()
+ }
+
+ @Test
+ fun onUpdateReceived_whileRefreshingWithSameSeverity_returnsNull() {
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onStartScanningAnimationStart()
+
+ assertThat(sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)).isNull()
+ }
+
+ @Test
+ fun onUpdateReceived_refreshingStoppedWtihSameSeverity_returnsFinishScanningAnimation() {
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onStartScanningAnimationStart()
+
+ assertThat(sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN))
+ .isEqualTo(SafetyStatusAnimationSequencer.Action.FINISH_SCANNING_ANIMATION)
+ }
+
+ @Test
+ fun onUpdateReceived_whileRefreshingWithDifferentSeverity_returnsNull() {
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onStartScanningAnimationStart()
+
+ assertThat(sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING))
+ .isNull()
+ }
+
+ @Test
+ fun onUpdateReceived_refreshingStoppedWithDifferentSeverity_returnsFinishScanningAnimation() {
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onStartScanningAnimationStart()
+
+ assertThat(
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ )
+ .isEqualTo(SafetyStatusAnimationSequencer.Action.FINISH_SCANNING_ANIMATION)
+ }
+
+ @Test
+ fun onStartScanningAnimationEnd_returnsContinueScanningAnimation() {
+ assertThat(sequencer.onStartScanningAnimationEnd())
+ .isEqualTo(SafetyStatusAnimationSequencer.Action.CONTINUE_SCANNING_ANIMATION)
+ }
+
+ @Test
+ fun onFinishScanAnimationEnd_noIconChangeAnimationQueued_returnsChangeIcon() {
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onStartScanningAnimationStart()
+ sequencer.onStartScanningAnimationEnd()
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+
+ assertThat(
+ sequencer.onFinishScanAnimationEnd(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ )
+ .isEqualTo(SafetyStatusAnimationSequencer.Action.CHANGE_ICON_WITHOUT_ANIMATION)
+ }
+
+ @Test
+ fun onFinishScanAnimationEnd_iconChangeAnimationQueuedWithSameSeverity_returnsChangeIcon() {
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onStartScanningAnimationStart()
+ sequencer.onStartScanningAnimationEnd()
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+
+ assertThat(
+ sequencer.onFinishScanAnimationEnd(
+ NOT_REFRESHING,
+ OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING
+ )
+ )
+ .isEqualTo(SafetyStatusAnimationSequencer.Action.CHANGE_ICON_WITHOUT_ANIMATION)
+ }
+
+ @Test
+ fun onFinishScanAnimationEnd_iconChangeAnimationQueuedAfterRefreshing_returnsStartIconChange() {
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onStartScanningAnimationStart()
+ sequencer.onStartScanningAnimationEnd()
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+
+ assertThat(
+ sequencer.onFinishScanAnimationEnd(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ )
+ .isEqualTo(SafetyStatusAnimationSequencer.Action.START_ICON_CHANGE_ANIMATION)
+ }
+
+ @Test
+ fun onIconChangeAnimationEnd_noAnimationQueued_returnsChangeIcon() {
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ sequencer.onIconChangeAnimationStart()
+
+ assertThat(
+ sequencer.onIconChangeAnimationEnd(
+ NOT_REFRESHING,
+ OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING
+ )
+ )
+ .isEqualTo(SafetyStatusAnimationSequencer.Action.CHANGE_ICON_WITHOUT_ANIMATION)
+ }
+
+ @Test
+ fun onIconChangeAnimationEnd_updateReceivedWithDifferentSeverity_returnsStartIconChange() {
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ sequencer.onIconChangeAnimationStart()
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+
+ assertThat(
+ sequencer.onIconChangeAnimationEnd(
+ NOT_REFRESHING,
+ OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING
+ )
+ )
+ .isEqualTo(SafetyStatusAnimationSequencer.Action.START_ICON_CHANGE_ANIMATION)
+ }
+
+ @Test
+ fun onIconChangeAnimationEnd_updateReceivedWithSameSeverity_returnsChangeIcon() {
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ sequencer.onIconChangeAnimationStart()
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+
+ assertThat(
+ sequencer.onIconChangeAnimationEnd(
+ NOT_REFRESHING,
+ OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING
+ )
+ )
+ .isEqualTo(SafetyStatusAnimationSequencer.Action.CHANGE_ICON_WITHOUT_ANIMATION)
+ }
+
+ @Test
+ fun onIconChangeAnimationEnd_scanAnimationQueued_returnsStartScanningAnimation() {
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ sequencer.onIconChangeAnimationStart()
+ sequencer.onUpdateReceived(REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+
+ assertThat(
+ sequencer.onIconChangeAnimationEnd(
+ REFRESHING,
+ OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING
+ )
+ )
+ .isEqualTo(SafetyStatusAnimationSequencer.Action.START_SCANNING_ANIMATION)
+ }
+
+ @Test
+ fun onCouldNotStartIconChangeAnimation_noAnimationQueued_returnsChangeIcon() {
+ sequencer.onUpdateReceived(NOT_REFRESHING, OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ sequencer.onIconChangeAnimationStart()
+
+ assertThat(
+ sequencer.onCouldNotStartIconChangeAnimation(
+ NOT_REFRESHING,
+ OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING
+ )
+ )
+ .isEqualTo(SafetyStatusAnimationSequencer.Action.CHANGE_ICON_WITHOUT_ANIMATION)
+ }
+
+ private companion object {
+ const val REFRESHING = true
+ const val NOT_REFRESHING = false
+ }
+}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/SnakeCaseConverterTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/SnakeCaseConverterTest.kt
new file mode 100644
index 000000000..a8011f417
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/SnakeCaseConverterTest.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.tests.mocking.safetycenter.ui
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.permissioncontroller.safetycenter.ui.SnakeCaseConverter
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SnakeCaseConverterTest {
+
+ @Test
+ fun fromCamelCase_withCamelCaseInput_returnsSnakeCaseString() {
+ val input = "camelCase"
+
+ val result = SnakeCaseConverter.fromCamelCase(input)
+
+ assertThat(result).isEqualTo("camel_case")
+ }
+
+ @Test
+ fun fromCamelCase_withEmptyInput_returnsEmptyString() {
+ val input = ""
+
+ val result = SnakeCaseConverter.fromCamelCase(input)
+
+ assertThat(result).isEqualTo("")
+ }
+
+ @Test
+ fun fromCamelCase_withSnakeCaseInput_returnsSnakeCaseString() {
+ val input = "snake_case"
+
+ val result = SnakeCaseConverter.fromCamelCase(input)
+
+ assertThat(result).isEqualTo("snake_case")
+ }
+
+ @Test
+ fun fromCamelCase_withInputHavingUnderscores_preservesUnderscores() {
+ val input = "camelCase_withUnderscores"
+
+ val result = SnakeCaseConverter.fromCamelCase(input)
+
+ assertThat(result).isEqualTo("camel_case_with_underscores")
+ }
+
+ @Test
+ fun fromCamelCase_withPascalCaseInput_returnsSnakeCaseString() {
+ val input = "PascalCase"
+
+ val result = SnakeCaseConverter.fromCamelCase(input)
+
+ assertThat(result).isEqualTo("pascal_case")
+ }
+
+ @Test
+ fun fromCamelCase_withScreamingSnakeCaseInput_lowerCasesTheString() {
+ val input = "SCREAMING_SNAKE_CASE"
+
+ val result = SnakeCaseConverter.fromCamelCase(input)
+
+ assertThat(result).isEqualTo("screaming_snake_case")
+ }
+
+ @Test
+ fun fromCamelCase_withMixedCaseInput_returnsSnakeCaseString() {
+ val input = "PascalCase_snake_case_camelCase"
+
+ val result = SnakeCaseConverter.fromCamelCase(input)
+
+ assertThat(result).isEqualTo("pascal_case_snake_case_camel_case")
+ }
+}
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
new file mode 100644
index 000000000..34ea6fcf0
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/model/SafetyCenterUiDataTest.kt
@@ -0,0 +1,249 @@
+/*
+ * 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.mocking.safetycenter.ui.model
+
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import android.os.Bundle
+import android.safetycenter.SafetyCenterData
+import android.safetycenter.SafetyCenterEntryGroup
+import android.safetycenter.SafetyCenterEntryOrGroup
+import android.safetycenter.SafetyCenterIssue
+import android.safetycenter.SafetyCenterStatus
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterUiData
+import com.android.safetycenter.internaldata.SafetyCenterBundles.ISSUES_TO_GROUPS_BUNDLE_KEY
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+class SafetyCenterUiDataTest {
+
+ @Test
+ fun getMatchingGroup_validMatchingGroup_returnsExpectedEntryGroup() {
+ val matchingGroup = createSafetyCenterEntryGroup(MATCHING_GROUP_ID)
+ val nonMatchingGroup = createSafetyCenterEntryGroup(NON_MATCHING_GROUP_ID)
+ val safetyCenterData =
+ createSafetyCenterData(entryGroups = listOf(matchingGroup, nonMatchingGroup))
+
+ val result = SafetyCenterUiData(safetyCenterData).getMatchingGroup(MATCHING_GROUP_ID)
+
+ assertThat(result).isEqualTo(matchingGroup)
+ }
+
+ @Test
+ fun getMatchingGroup_noMatchingGroup_returnsNull() {
+ val nonMatchingGroup = createSafetyCenterEntryGroup(NON_MATCHING_GROUP_ID)
+ val safetyCenterData = createSafetyCenterData(entryGroups = listOf(nonMatchingGroup))
+
+ val result = SafetyCenterUiData(safetyCenterData).getMatchingGroup(MATCHING_GROUP_ID)
+
+ assertThat(result).isNull()
+ }
+
+ @Test
+ fun getMatchingIssues_defaultMatchingIssue_noExtras_returnsListOfIssues() {
+ val defaultMatchingIssue = createSafetyCenterIssue("id1", MATCHING_GROUP_ID)
+ val nonMatchingIssue = createSafetyCenterIssue("id2", NON_MATCHING_GROUP_ID)
+ val safetyCenterData =
+ createSafetyCenterData(issues = listOf(defaultMatchingIssue, nonMatchingIssue))
+
+ val result = SafetyCenterUiData(safetyCenterData).getMatchingIssues(MATCHING_GROUP_ID)
+
+ assertThat(result).containsExactly(defaultMatchingIssue)
+ }
+
+ @Test
+ fun getMatchingIssues_defaultMatchingIssue_unrelatedExtras_returnsListOfIssues() {
+ val defaultMatchingIssue = createSafetyCenterIssue("id1", MATCHING_GROUP_ID)
+ val nonMatchingIssue = createSafetyCenterIssue("id2", NON_MATCHING_GROUP_ID)
+ val safetyCenterData =
+ createSafetyCenterData(
+ issues = listOf(defaultMatchingIssue, nonMatchingIssue),
+ extras =
+ createSafetyCenterExtras(
+ Bundle().apply {
+ putStringArrayList(
+ nonMatchingIssue.id,
+ arrayListOf(NON_MATCHING_GROUP_ID)
+ )
+ }
+ )
+ )
+
+ val result = SafetyCenterUiData(safetyCenterData).getMatchingIssues(MATCHING_GROUP_ID)
+
+ assertThat(result).containsExactly(defaultMatchingIssue)
+ }
+
+ @Test
+ fun getMatchingIssues_mappingMatchingIssue_returnsListOfIssues() {
+ val mappingMatchingIssue = createSafetyCenterIssue("id1", NON_MATCHING_GROUP_ID)
+ val nonMatchingIssue = createSafetyCenterIssue("id2", NON_MATCHING_GROUP_ID)
+ val safetyCenterData =
+ createSafetyCenterData(
+ issues = listOf(mappingMatchingIssue, nonMatchingIssue),
+ extras =
+ createSafetyCenterExtras(
+ Bundle().apply {
+ putStringArrayList(
+ mappingMatchingIssue.id,
+ arrayListOf(MATCHING_GROUP_ID)
+ )
+ }
+ )
+ )
+
+ val result = SafetyCenterUiData(safetyCenterData).getMatchingIssues(MATCHING_GROUP_ID)
+
+ assertThat(result).containsExactly(mappingMatchingIssue)
+ }
+
+ @Test
+ fun getMatchingIssues_noDefaultMatchingIssue_returnsEmptyList() {
+ val nonMatchingIssue = createSafetyCenterIssue("id1", NON_MATCHING_GROUP_ID)
+ val dismissedIssue = createSafetyCenterIssue("id2", MATCHING_GROUP_ID)
+ val safetyCenterData =
+ createSafetyCenterData(
+ issues = listOf(nonMatchingIssue),
+ dismissedIssues = listOf(dismissedIssue)
+ )
+
+ val result = SafetyCenterUiData(safetyCenterData).getMatchingIssues(MATCHING_GROUP_ID)
+
+ assertThat(result).isEmpty()
+ }
+
+ @Test
+ fun getMatchingDismissedIssues_defaultMatchingDismissedIssue_returnsListOfDismissedIssues() {
+ val defaultMatchingDismissedIssue = createSafetyCenterIssue("id1", MATCHING_GROUP_ID)
+ val nonMatchingDismissedIssue = createSafetyCenterIssue("id2", NON_MATCHING_GROUP_ID)
+ val safetyCenterData =
+ createSafetyCenterData(
+ dismissedIssues = listOf(defaultMatchingDismissedIssue, nonMatchingDismissedIssue)
+ )
+
+ val result =
+ SafetyCenterUiData(safetyCenterData).getMatchingDismissedIssues(MATCHING_GROUP_ID)
+
+ assertThat(result).containsExactly(defaultMatchingDismissedIssue)
+ }
+
+ @Test
+ fun getMatchingDismissedIssues_defaultMatchingDismissedIssue2_returnsListOfDismissedIssues() {
+ val defaultMatchingDismissedIssue = createSafetyCenterIssue("id1", MATCHING_GROUP_ID)
+ val nonMatchingDismissedIssue = createSafetyCenterIssue("id2", NON_MATCHING_GROUP_ID)
+ val safetyCenterData =
+ createSafetyCenterData(
+ dismissedIssues = listOf(defaultMatchingDismissedIssue, nonMatchingDismissedIssue),
+ extras =
+ createSafetyCenterExtras(
+ Bundle().apply {
+ putStringArrayList(
+ nonMatchingDismissedIssue.id,
+ arrayListOf(NON_MATCHING_GROUP_ID)
+ )
+ }
+ )
+ )
+
+ val result =
+ SafetyCenterUiData(safetyCenterData).getMatchingDismissedIssues(MATCHING_GROUP_ID)
+
+ assertThat(result).containsExactly(defaultMatchingDismissedIssue)
+ }
+
+ @Test
+ fun getMatchingDismissedIssues_mappingMatchingDismissedIssue_returnsListOfDismissedIssues() {
+ val mappingMatchingDismissedIssue = createSafetyCenterIssue("id1", NON_MATCHING_GROUP_ID)
+ val nonMatchingDismissedIssue = createSafetyCenterIssue("id2", NON_MATCHING_GROUP_ID)
+ val safetyCenterData =
+ createSafetyCenterData(
+ dismissedIssues = listOf(mappingMatchingDismissedIssue, nonMatchingDismissedIssue),
+ extras =
+ createSafetyCenterExtras(
+ Bundle().apply {
+ putStringArrayList(
+ mappingMatchingDismissedIssue.id,
+ arrayListOf(MATCHING_GROUP_ID)
+ )
+ }
+ )
+ )
+
+ val result =
+ SafetyCenterUiData(safetyCenterData).getMatchingDismissedIssues(MATCHING_GROUP_ID)
+
+ assertThat(result).containsExactly(mappingMatchingDismissedIssue)
+ }
+
+ @Test
+ fun getMatchingDismissedIssues_noDefaultMatchingDismissedIssue_returnsEmptyList() {
+ val nonMatchingDismissedIssue = createSafetyCenterIssue("id1", NON_MATCHING_GROUP_ID)
+ val nonDismissedIssue = createSafetyCenterIssue("id2", MATCHING_GROUP_ID)
+ val safetyCenterData =
+ createSafetyCenterData(
+ issues = listOf(nonDismissedIssue),
+ dismissedIssues = listOf(nonMatchingDismissedIssue)
+ )
+
+ val result =
+ SafetyCenterUiData(safetyCenterData).getMatchingDismissedIssues(MATCHING_GROUP_ID)
+
+ assertThat(result).isEmpty()
+ }
+
+ private companion object {
+ const val MATCHING_GROUP_ID = "matching_group_id"
+ const val NON_MATCHING_GROUP_ID = "non_matching_group_id"
+
+ fun createSafetyCenterData(
+ issues: List<SafetyCenterIssue> = listOf(),
+ entryGroups: List<SafetyCenterEntryGroup> = listOf(),
+ dismissedIssues: List<SafetyCenterIssue> = listOf(),
+ extras: Bundle = Bundle()
+ ): SafetyCenterData {
+ val safetyCenterStatus =
+ SafetyCenterStatus.Builder("status title", "status summary").build()
+ val builder = SafetyCenterData.Builder(safetyCenterStatus)
+ for (issue in issues) {
+ builder.addIssue(issue)
+ }
+ for (group in entryGroups) {
+ builder.addEntryOrGroup(SafetyCenterEntryOrGroup(group))
+ }
+ for (dismissedIssue in dismissedIssues) {
+ builder.addDismissedIssue(dismissedIssue)
+ }
+ builder.setExtras(extras)
+ return builder.build()
+ }
+
+ fun createSafetyCenterEntryGroup(groupId: String) =
+ SafetyCenterEntryGroup.Builder(groupId, "group title").build()
+
+ fun createSafetyCenterIssue(issueId: String, groupId: String) =
+ SafetyCenterIssue.Builder(issueId, "issue title", "issue summary")
+ .setGroupId(groupId)
+ .build()
+
+ fun createSafetyCenterExtras(issuesToGroupsMapping: Bundle) =
+ Bundle().apply { putBundle(ISSUES_TO_GROUPS_BUNDLE_KEY, issuesToGroupsMapping) }
+ }
+}
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
new file mode 100644
index 000000000..d963fd535
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/model/StatusUiDataTest.kt
@@ -0,0 +1,267 @@
+/*
+ * 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.permissioncontroller.tests.mocking.safetycenter.ui.model
+
+import android.content.Context
+import android.os.Build
+import android.safetycenter.SafetyCenterData
+import android.safetycenter.SafetyCenterIssue
+import android.safetycenter.SafetyCenterStatus
+import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING
+import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK
+import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION
+import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN
+import android.safetycenter.SafetyCenterStatus.REFRESH_STATUS_DATA_FETCH_IN_PROGRESS
+import android.safetycenter.SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS
+import android.safetycenter.SafetyCenterStatus.REFRESH_STATUS_NONE
+import androidx.test.filters.SdkSuppress
+import com.android.permissioncontroller.R
+import com.android.permissioncontroller.safetycenter.ui.model.StatusUiData
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
+class StatusUiDataTest {
+
+ @Mock private lateinit var mockContext: Context
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ fun copyForPendingActions_setsCorrectPendingActionsValue() {
+ val copiedWithPendingActions =
+ StatusUiData(STATUS, hasPendingActions = false).copyForPendingActions(true)
+ val copiedWithoutPendingActions =
+ StatusUiData(STATUS, hasPendingActions = true).copyForPendingActions(false)
+
+ assertThat(copiedWithPendingActions.hasPendingActions).isTrue()
+ assertThat(copiedWithoutPendingActions.hasPendingActions).isFalse()
+ }
+
+ @Test
+ fun getTitle_returnsTitle() {
+ assertThat(StatusUiData(STATUS).title).isEqualTo(STATUS.title)
+ assertThat(StatusUiData(ANOTHER_STATUS).title).isEqualTo(ANOTHER_STATUS.title)
+ assertThat(StatusUiData(SafetyCenterData(STATUS, listOf(), listOf(), listOf())).title)
+ .isEqualTo(STATUS.title)
+ }
+
+ @Test
+ fun getOriginalSummary_returnsOriginalSummary() {
+ assertThat(StatusUiData(STATUS).originalSummary).isEqualTo(STATUS.summary)
+ assertThat(StatusUiData(ANOTHER_STATUS).originalSummary).isEqualTo(ANOTHER_STATUS.summary)
+ assertThat(
+ StatusUiData(SafetyCenterData(STATUS, listOf(), listOf(), listOf()))
+ .originalSummary)
+ .isEqualTo(STATUS.summary)
+ }
+
+ @Test
+ fun getSeverityLevel_returnsSeverityLevel() {
+ assertThat(StatusUiData(STATUS).severityLevel).isEqualTo(STATUS.severityLevel)
+ assertThat(StatusUiData(ANOTHER_STATUS).severityLevel)
+ .isEqualTo(ANOTHER_STATUS.severityLevel)
+ assertThat(
+ StatusUiData(SafetyCenterData(STATUS, listOf(), listOf(), listOf())).severityLevel)
+ .isEqualTo(STATUS.severityLevel)
+ }
+
+ @Test
+ fun getSummary_withoutPendingActions_returnsOriginalSummary() {
+ val dataWithoutPendingActions = StatusUiData(STATUS, hasPendingActions = false)
+
+ val actualSummary = dataWithoutPendingActions.getSummary(mockContext)
+
+ assertThat(actualSummary).isEqualTo(dataWithoutPendingActions.originalSummary)
+ }
+
+ @Test
+ fun getSummary_withPendingActions_returnsQsSummary() {
+ val expectedSummary = "a quick settings summary"
+ whenever(mockContext.getString(R.string.safety_center_qs_status_summary))
+ .thenReturn(expectedSummary)
+
+ val actualSummary = StatusUiData(STATUS, hasPendingActions = true).getSummary(mockContext)
+
+ assertThat(actualSummary).isEqualTo(expectedSummary)
+ }
+
+ @Test
+ fun getContentDescription_returnsContentDescription() {
+ val expectedContentDescription = "a content description"
+ whenever(
+ mockContext.getString(
+ R.string.safety_status_preference_title_and_summary_content_description,
+ STATUS.title,
+ STATUS.summary))
+ .thenReturn(expectedContentDescription)
+
+ val actualContentDescription = StatusUiData(STATUS).getContentDescription(mockContext)
+
+ assertThat(actualContentDescription).isEqualTo(expectedContentDescription)
+ }
+
+ @Test
+ fun fromSafetyCenterData_withIssues_hasIssuesIsTrue() {
+ assertThat(StatusUiData(DATA_WITH_ISSUES).hasIssues).isTrue()
+ }
+
+ @Test
+ fun fromSafetyCenterData_withoutIssues_hasIssuesIsFalse() {
+ assertThat(StatusUiData(DATA_WITHOUT_ISSUES).hasIssues).isFalse()
+ }
+
+ @Test
+ fun hasPendingActions_defaultsFalse() {
+ assertThat(StatusUiData(STATUS).hasPendingActions).isFalse()
+ assertThat(StatusUiData(DATA_WITH_ISSUES).hasPendingActions).isFalse()
+ }
+
+ @Test
+ fun getStatusImageResId_severityOk() {
+ assertThat(uiDataForSeverity(OVERALL_SEVERITY_LEVEL_OK).statusImageResId)
+ .isEqualTo(R.drawable.safety_status_info)
+ }
+
+ @Test
+ fun getStatusImageResId_severityUnknown() {
+ assertThat(uiDataForSeverity(OVERALL_SEVERITY_LEVEL_UNKNOWN).statusImageResId)
+ .isEqualTo(R.drawable.safety_status_info)
+ }
+ @Test
+ fun getStatusImageResId_severityRecommendation() {
+ assertThat(uiDataForSeverity(OVERALL_SEVERITY_LEVEL_RECOMMENDATION).statusImageResId)
+ .isEqualTo(R.drawable.safety_status_recommendation)
+ }
+ @Test
+ fun getStatusImageResId_severityWarning() {
+ assertThat(uiDataForSeverity(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING).statusImageResId)
+ .isEqualTo(R.drawable.safety_status_warn)
+ }
+
+ @Test
+ fun isRefreshInProgress_dataFetch_isTrue() {
+ assertThat(
+ uiDataForRefreshStatus(REFRESH_STATUS_DATA_FETCH_IN_PROGRESS).isRefreshInProgress)
+ .isTrue()
+ }
+
+ @Test
+ fun isRefreshInProgress_fullRescan_isTrue() {
+ assertThat(
+ uiDataForRefreshStatus(REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS).isRefreshInProgress)
+ .isTrue()
+ }
+
+ @Test
+ fun isRefreshInProgress_none_isFalse() {
+ assertThat(uiDataForRefreshStatus(REFRESH_STATUS_NONE).isRefreshInProgress).isFalse()
+ }
+
+ @Test
+ fun shouldShowRescanButton_severityOk_noIssues_noPendingActions_isTrue() {
+ assertThat(
+ StatusUiData(
+ statusForSeverity(OVERALL_SEVERITY_LEVEL_OK),
+ hasIssues = false,
+ hasPendingActions = false)
+ .shouldShowRescanButton())
+ .isTrue()
+ }
+
+ @Test
+ fun shouldShowRescanButton_severityUnknown_noIssues_noPendingActions_isTrue() {
+ assertThat(
+ StatusUiData(
+ statusForSeverity(OVERALL_SEVERITY_LEVEL_UNKNOWN),
+ hasIssues = false,
+ hasPendingActions = false)
+ .shouldShowRescanButton())
+ .isTrue()
+ }
+
+ @Test
+ fun shouldShowRescanButton_hasIssues_isFalse() {
+ assertThat(
+ StatusUiData(
+ statusForSeverity(OVERALL_SEVERITY_LEVEL_OK),
+ hasIssues = true,
+ hasPendingActions = false)
+ .shouldShowRescanButton())
+ .isFalse()
+ }
+
+ @Test
+ fun shouldShowRescanButton_hasPendingActions_isFalse() {
+ assertThat(
+ StatusUiData(
+ statusForSeverity(OVERALL_SEVERITY_LEVEL_OK),
+ hasIssues = false,
+ hasPendingActions = true)
+ .shouldShowRescanButton())
+ .isFalse()
+ }
+
+ @Test
+ fun shouldShowRescanButton_severityNotOkOrUnknown_isFalse() {
+ for (severity in
+ listOf(
+ OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING, OVERALL_SEVERITY_LEVEL_RECOMMENDATION)) {
+ assertThat(
+ StatusUiData(
+ statusForSeverity(severity),
+ hasIssues = false,
+ hasPendingActions = false)
+ .shouldShowRescanButton())
+ .isFalse()
+ }
+ }
+
+ private companion object {
+ val STATUS =
+ SafetyCenterStatus.Builder("a title", "a summary")
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK)
+ .setRefreshStatus(REFRESH_STATUS_NONE)
+ .build()
+
+ val ANOTHER_STATUS =
+ SafetyCenterStatus.Builder("another title", "another summary")
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_RECOMMENDATION)
+ .setRefreshStatus(REFRESH_STATUS_DATA_FETCH_IN_PROGRESS)
+ .build()
+
+ val ISSUE = SafetyCenterIssue.Builder("iSsUe_Id", "issue title", "issue summary").build()
+
+ val DATA_WITH_ISSUES = SafetyCenterData(STATUS, listOf(ISSUE), listOf(), listOf())
+ val DATA_WITHOUT_ISSUES = SafetyCenterData(STATUS, listOf(), listOf(), listOf())
+
+ fun statusForSeverity(severityLevel: Int) =
+ SafetyCenterStatus.Builder(STATUS).setSeverityLevel(severityLevel).build()
+
+ fun uiDataForSeverity(severityLevel: Int) = StatusUiData(statusForSeverity(severityLevel))
+
+ fun uiDataForRefreshStatus(refreshStatus: Int) =
+ StatusUiData(SafetyCenterStatus.Builder(STATUS).setRefreshStatus(refreshStatus).build())
+ }
+}
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
new file mode 100644
index 000000000..10221f6fa
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/AppsSafetyLabelHistoryPersistenceTest.kt
@@ -0,0 +1,538 @@
+/*
+ * 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.permissioncontroller.tests.mocking.safetylabel
+
+import android.content.Context
+import android.os.Build
+import android.provider.DeviceConfig
+import android.provider.DeviceConfig.NAMESPACE_PRIVACY
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.SdkSuppress
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.AppInfo
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.AppSafetyLabelDiff
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.AppSafetyLabelHistory
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistoryPersistence
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistoryPersistence.AppsSafetyLabelHistoryFileContent
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistoryPersistence.ChangeListener
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.DATE_2022_10_10
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.DATE_2022_10_12
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.DATE_2022_10_14
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.DATE_2022_12_10
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.DATE_2022_12_30
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.PACKAGE_NAME_1
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.PACKAGE_NAME_2
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.PACKAGE_NAME_3
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.SAFETY_LABEL_PKG_1_V1
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.SAFETY_LABEL_PKG_1_V2
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.SAFETY_LABEL_PKG_1_V3
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.SAFETY_LABEL_PKG_2_V1
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.SAFETY_LABEL_PKG_2_V2
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.SAFETY_LABEL_PKG_2_V3
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.SAFETY_LABEL_PKG_3_V1
+import com.google.common.truth.Truth.assertThat
+import java.io.File
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+import org.mockito.MockitoSession
+import org.mockito.quality.Strictness
+
+/** Tests for [AppsSafetyLabelHistoryPersistence]. */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+class AppsSafetyLabelHistoryPersistenceTest {
+ private lateinit var context: Context
+ private lateinit var dataFile: File
+ private lateinit var mockitoSession: MockitoSession
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ context = ApplicationProvider.getApplicationContext()
+ dataFile = context.getFileStreamPath(TEST_FILE_NAME)
+ mockitoSession =
+ ExtendedMockito.mockitoSession()
+ .mockStatic(DeviceConfig::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
+ setMaxSafetyLabelsToPersist(20)
+ }
+
+ @After
+ fun cleanup() {
+ context.deleteFile(TEST_FILE_NAME)
+ mockitoSession.finishMocking()
+ }
+
+ @Test
+ fun read_afterDeleted_returnsNull() {
+ val appsSafetyLabelHistory =
+ AppsSafetyLabelHistory(
+ listOf(),
+ )
+ AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
+ AppsSafetyLabelHistoryPersistence.clear(dataFile)
+
+ assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).appsSafetyLabelHistory)
+ .isEqualTo(null)
+ }
+
+ @Test
+ fun read_afterWrite_noHistory_returnsIdenticalAppsSafetyLabelHistory() {
+ val appsSafetyLabelHistory =
+ AppsSafetyLabelHistory(
+ listOf(),
+ )
+ AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
+
+ assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).appsSafetyLabelHistory)
+ .isEqualTo(appsSafetyLabelHistory)
+ }
+
+ @Test
+ fun read_afterWrite_noSharing_returnsIdenticalAppsSafetyLabelHistory() {
+ val appsSafetyLabelHistory =
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_2), listOf(SAFETY_LABEL_PKG_2_V2))))
+ AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
+
+ assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).appsSafetyLabelHistory)
+ .isEqualTo(appsSafetyLabelHistory)
+ }
+
+ @Test
+ fun read_afterWrite_returnsIdenticalAppsSafetyLabelHistory() {
+ val appsSafetyLabelHistory =
+ AppsSafetyLabelHistory(
+ listOf(
+ 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))))
+ AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
+
+ assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).appsSafetyLabelHistory)
+ .isEqualTo(appsSafetyLabelHistory)
+ }
+
+ @Test
+ fun read_noFile_returnsInitialVersion() {
+ assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).version).isEqualTo(0)
+ }
+
+ @Test
+ fun read_afterWrite_defaultVersion_returnsInitialVersion() {
+ val appsSafetyLabelHistory =
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_2), listOf(SAFETY_LABEL_PKG_2_V2))))
+ AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
+
+ assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).version).isEqualTo(0)
+ }
+
+ @Test
+ fun read_afterWrite_specifiedVersion_returnsSpecifiedVersion() {
+ val appsSafetyLabelHistory =
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_2), listOf(SAFETY_LABEL_PKG_2_V2))))
+ AppsSafetyLabelHistoryPersistence.write(
+ dataFile, AppsSafetyLabelHistoryFileContent(appsSafetyLabelHistory, 5))
+
+ assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).version).isEqualTo(5)
+ }
+
+ @Test
+ fun recordSafetyLabel_noAppsHistory_addsAppsHistory() {
+ AppsSafetyLabelHistoryPersistence.clear(dataFile)
+
+ AppsSafetyLabelHistoryPersistence.recordSafetyLabel(SAFETY_LABEL_PKG_1_V1, dataFile)
+
+ assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).appsSafetyLabelHistory)
+ .isEqualTo(
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1)))))
+ }
+
+ @Test
+ fun recordSafetyLabel_noAppHistory_addsAppHistory() {
+ val appsSafetyLabelHistory =
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1))))
+ AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
+
+ AppsSafetyLabelHistoryPersistence.recordSafetyLabel(SAFETY_LABEL_PKG_2_V1, dataFile)
+
+ assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).appsSafetyLabelHistory)
+ .isEqualTo(
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1)),
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_2), listOf(SAFETY_LABEL_PKG_2_V1)))))
+ }
+
+ @Test
+ fun recordSafetyLabel_existingAppHistory_addsToHistory() {
+ val appsSafetyLabelHistory =
+ AppsSafetyLabelHistory(
+ listOf(
+ 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))))
+ AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
+
+ AppsSafetyLabelHistoryPersistence.recordSafetyLabel(SAFETY_LABEL_PKG_2_V3, dataFile)
+
+ assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).appsSafetyLabelHistory)
+ .isEqualTo(
+ AppsSafetyLabelHistory(
+ listOf(
+ 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,
+ SAFETY_LABEL_PKG_2_V3)))))
+ }
+
+ @Test
+ fun recordSafetyLabel_whenMaximumSafetyLabelsAlreadyStoredForApp_dropsOldSafetyLabels() {
+ setMaxSafetyLabelsToPersist(2)
+ AppsSafetyLabelHistoryPersistence.recordSafetyLabel(SAFETY_LABEL_PKG_2_V1, dataFile)
+ AppsSafetyLabelHistoryPersistence.recordSafetyLabel(SAFETY_LABEL_PKG_2_V2, dataFile)
+
+ AppsSafetyLabelHistoryPersistence.recordSafetyLabel(SAFETY_LABEL_PKG_2_V3, dataFile)
+
+ assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).appsSafetyLabelHistory)
+ .isEqualTo(
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_2),
+ listOf(SAFETY_LABEL_PKG_2_V2, SAFETY_LABEL_PKG_2_V3)))))
+ }
+
+ @Test
+ fun recordSafetyLabel_noChangeToLastLabel_doesNothing() {
+ val appsSafetyLabelHistory =
+ AppsSafetyLabelHistory(
+ listOf(
+ 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))))
+ AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
+
+ AppsSafetyLabelHistoryPersistence.recordSafetyLabel(SAFETY_LABEL_PKG_1_V3, dataFile)
+
+ assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).appsSafetyLabelHistory)
+ .isEqualTo(appsSafetyLabelHistory)
+ }
+
+ @Test
+ fun recordSafetyLabels_addsToHistory() {
+ val appsSafetyLabelHistory =
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1)),
+ AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_2), listOf(SAFETY_LABEL_PKG_2_V1))))
+ AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
+
+ AppsSafetyLabelHistoryPersistence.recordSafetyLabels(
+ setOf(
+ SAFETY_LABEL_PKG_1_V2,
+ SAFETY_LABEL_PKG_2_V2,
+ SAFETY_LABEL_PKG_2_V3,
+ SAFETY_LABEL_PKG_3_V1),
+ dataFile)
+
+ assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).appsSafetyLabelHistory)
+ .isEqualTo(
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_1),
+ 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)),
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_3), listOf(SAFETY_LABEL_PKG_3_V1)),
+ )))
+ }
+
+ @Test
+ fun getAppSafetyLabelDiffs_whenNoHistory_returnsEmpty() {
+ AppsSafetyLabelHistoryPersistence.clear(dataFile)
+
+ val safetyLabelDiffs: List<AppSafetyLabelDiff> =
+ AppsSafetyLabelHistoryPersistence.getAppSafetyLabelDiffs(DATE_2022_12_10, dataFile)
+
+ assertThat(safetyLabelDiffs).isEqualTo(listOf<AppSafetyLabelDiff>())
+ }
+
+ @Test
+ fun getAppSafetyLabelDiffs_whenNoSafetyLabelChangesSinceStartTime_returnsEmpty() {
+ val appsSafetyLabelHistory =
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1))))
+ AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
+
+ val safetyLabelDiffs: List<AppSafetyLabelDiff> =
+ AppsSafetyLabelHistoryPersistence.getAppSafetyLabelDiffs(DATE_2022_10_14, dataFile)
+
+ assertThat(safetyLabelDiffs).isEqualTo(listOf<AppSafetyLabelDiff>())
+ }
+
+ @Test
+ fun getAppSafetyLabelDiffs_whenNoSafetyLabelsSinceStartTime_returnsEmpty() {
+ val appsSafetyLabelHistory =
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_1),
+ listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2))))
+ AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
+
+ val safetyLabelDiffs: List<AppSafetyLabelDiff> =
+ AppsSafetyLabelHistoryPersistence.getAppSafetyLabelDiffs(DATE_2022_12_10, dataFile)
+
+ assertThat(safetyLabelDiffs).isEqualTo(listOf<AppSafetyLabelDiff>())
+ }
+
+ @Test
+ fun getAppSafetyLabelDiffs_whenNoSafetyLabelsBeforeStartTime_returnsMoreRecentDiffs() {
+ val appsSafetyLabelHistory =
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_2),
+ listOf(SAFETY_LABEL_PKG_2_V2, SAFETY_LABEL_PKG_2_V3))))
+ AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
+
+ val safetyLabelDiffs: List<AppSafetyLabelDiff> =
+ AppsSafetyLabelHistoryPersistence.getAppSafetyLabelDiffs(DATE_2022_10_10, dataFile)
+
+ assertThat(safetyLabelDiffs)
+ .isEqualTo(listOf(AppSafetyLabelDiff(SAFETY_LABEL_PKG_2_V2, SAFETY_LABEL_PKG_2_V3)))
+ }
+
+ @Test
+ fun getAppSafetyLabelDiffs_returnsAvailableDiffs() {
+ val appsSafetyLabelHistory =
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_1),
+ 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))))
+ AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
+
+ val safetyLabelDiffs =
+ AppsSafetyLabelHistoryPersistence.getAppSafetyLabelDiffs(DATE_2022_10_12, dataFile)
+
+ assertThat(safetyLabelDiffs)
+ .isEqualTo(
+ listOf(
+ AppSafetyLabelDiff(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2),
+ AppSafetyLabelDiff(SAFETY_LABEL_PKG_2_V1, SAFETY_LABEL_PKG_2_V3)))
+ }
+
+ @Test
+ fun getSafetyLabelsLastUpdatedTimes_noAppsPersisted_returnsEmptyMap() {
+ val lastUpdatedTimes =
+ AppsSafetyLabelHistoryPersistence.getSafetyLabelsLastUpdatedTimes(dataFile)
+
+ assertThat(lastUpdatedTimes).isEmpty()
+ }
+
+ @Test
+ fun getSafetyLabelsLastUpdatedTimes_appsPersisted_returnsLastUpdatedTimes() {
+ val appsSafetyLabelHistory =
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_1),
+ 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))))
+ AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
+
+ val lastUpdatedTimes =
+ AppsSafetyLabelHistoryPersistence.getSafetyLabelsLastUpdatedTimes(dataFile)
+
+ assertThat(lastUpdatedTimes)
+ .isEqualTo(
+ mapOf(
+ AppInfo(PACKAGE_NAME_1) to DATE_2022_10_14,
+ AppInfo(PACKAGE_NAME_2) to DATE_2022_12_30))
+ }
+
+ @Test
+ fun deleteSafetyLabelsForApps_removesSafetyLabelsFromPersistence() {
+ val appsSafetyLabelHistory =
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_1),
+ 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))))
+ AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
+
+ AppsSafetyLabelHistoryPersistence.deleteSafetyLabelsForApps(
+ setOf(AppInfo(PACKAGE_NAME_2)), dataFile)
+
+ assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).appsSafetyLabelHistory)
+ .isEqualTo(
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_1),
+ listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_1_V2)))))
+ }
+
+ @Test
+ fun deleteSafetyLabelsOlderThan_laterTime_removesCorrectSafetyLabelsFromPersistence() {
+ val appsSafetyLabelHistory =
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_1),
+ 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))))
+ AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
+
+ AppsSafetyLabelHistoryPersistence.deleteSafetyLabelsOlderThan(DATE_2022_12_30, dataFile)
+
+ assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).appsSafetyLabelHistory)
+ .isEqualTo(
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V3)),
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_2), listOf(SAFETY_LABEL_PKG_2_V2)))))
+ }
+
+ @Test
+ fun deleteSafetyLabelsOlderThan_earlierTime_removesCorrectSafetyLabelsFromPersistence() {
+ val appsSafetyLabelHistory =
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_1),
+ 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))))
+ AppsSafetyLabelHistoryPersistence.write(dataFile, appsSafetyLabelHistory)
+
+ AppsSafetyLabelHistoryPersistence.deleteSafetyLabelsOlderThan(DATE_2022_10_14, dataFile)
+
+ assertThat(AppsSafetyLabelHistoryPersistence.read(dataFile).appsSafetyLabelHistory)
+ .isEqualTo(
+ AppsSafetyLabelHistory(
+ listOf(
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_1),
+ 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)))))
+ }
+
+ @Test
+ fun registerListener_receivesUpdates() {
+ var onChangedCount = 0
+ val testChangeListener: ChangeListener =
+ object : ChangeListener {
+ override fun onSafetyLabelHistoryChanged() {
+ onChangedCount++
+ }
+ }
+ AppsSafetyLabelHistoryPersistence.addListener(testChangeListener)
+
+ AppsSafetyLabelHistoryPersistence.recordSafetyLabel(SAFETY_LABEL_PKG_1_V1, dataFile)
+
+ assertThat(onChangedCount).isEqualTo(1)
+ }
+
+ @Test
+ fun unregisterListener_doesNotReceiveUpdates() {
+ var onChangedCount = 0
+ val testChangeListener: ChangeListener =
+ object : ChangeListener {
+ override fun onSafetyLabelHistoryChanged() {
+ onChangedCount++
+ }
+ }
+ AppsSafetyLabelHistoryPersistence.addListener(testChangeListener)
+ AppsSafetyLabelHistoryPersistence.recordSafetyLabel(SAFETY_LABEL_PKG_1_V1, dataFile)
+ assertThat(onChangedCount).isEqualTo(1)
+
+ AppsSafetyLabelHistoryPersistence.removeListener(testChangeListener)
+ AppsSafetyLabelHistoryPersistence.recordSafetyLabel(SAFETY_LABEL_PKG_1_V2, dataFile)
+
+ assertThat(onChangedCount).isEqualTo(1)
+ }
+
+ companion object {
+ private const val TEST_FILE_NAME = "test_safety_label_history_file"
+ private const val PROPERTY_MAX_SAFETY_LABELS_PERSISTED_PER_APP =
+ "max_safety_labels_persisted_per_app"
+
+ /** Sets the value for the Permission Rationale feature [DeviceConfig] property. */
+ private fun setMaxSafetyLabelsToPersist(max: Int) {
+ whenever(
+ DeviceConfig.getInt(
+ eq(NAMESPACE_PRIVACY),
+ eq(PROPERTY_MAX_SAFETY_LABELS_PERSISTED_PER_APP),
+ 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
new file mode 100644
index 000000000..dedb0b1cd
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/AppsSafetyLabelHistoryTest.kt
@@ -0,0 +1,295 @@
+/*
+ * 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.mocking.safetylabel
+
+import android.os.Build
+import android.os.PersistableBundle
+import androidx.test.filters.SdkSuppress
+import com.android.permission.safetylabel.SafetyLabel as AppMetadataSafetyLabel
+import com.android.permission.safetylabel.SafetyLabel.KEY_VERSION
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.AppInfo
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.AppSafetyLabelHistory
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.DataCategory
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.DataLabel
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.SafetyLabel
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.DATE_2022_09_01
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.DATE_2022_10_10
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.LOCATION_CATEGORY
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.PACKAGE_NAME_1
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.PACKAGE_NAME_2
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.SAFETY_LABEL_PKG_1_V1
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.SAFETY_LABEL_PKG_1_V2
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.SAFETY_LABEL_PKG_1_V3
+import com.android.permissioncontroller.tests.mocking.safetylabel.TestSafetyLabels.SAFETY_LABEL_PKG_2_V1
+import com.google.common.truth.Truth.assertThat
+import java.time.ZonedDateTime
+import org.junit.Assert
+import org.junit.Test
+
+/** Tests for [AppsSafetyLabelHistory]. */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+class AppsSafetyLabelHistoryTest {
+
+ @Test
+ fun createAppSafetyLabelHistory_requiresAllSafetyLabelsHaveSameApp() {
+ Assert.assertThrows(IllegalArgumentException::class.java) {
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V1, SAFETY_LABEL_PKG_2_V1))
+ }
+ }
+
+ @Test
+ fun createAppSafetyLabelHistory_requiresOrderedByReceivedAt() {
+ Assert.assertThrows(IllegalArgumentException::class.java) {
+ AppSafetyLabelHistory(
+ AppInfo(PACKAGE_NAME_1), listOf(SAFETY_LABEL_PKG_1_V2, SAFETY_LABEL_PKG_1_V1))
+ }
+ }
+
+ @Test
+ fun withSafetyLabel_forDifferentApp_throwsIllegalArgumentException() {
+ val appSafetyLabelHistory =
+ AppSafetyLabelHistory(
+ 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)
+ }
+ }
+
+ @Test
+ fun withSafetyLabel_returnsOrderdSafetyLabels() {
+ val appSafetyLabelHistory =
+ AppSafetyLabelHistory(
+ 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)))
+ }
+
+ @Test
+ fun withSafetyLabel_dropsOldLabelsWhenMaxPersisted() {
+ val appSafetyLabelHistory =
+ AppSafetyLabelHistory(
+ 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)))
+ }
+
+ @Test
+ fun extractLocationSharingSafetyLabel_noSharing_returnsSafetyLabelForPersistence() {
+ val metadataBundle = createMetadataWithDataShared(createDataSharedNoSharing())
+ val appMetadataSafetyLabel =
+ AppMetadataSafetyLabel.getSafetyLabelFromMetadata(metadataBundle)!!
+
+ val safetyLabelForPersistence =
+ SafetyLabel.extractLocationSharingSafetyLabel(
+ PACKAGE_NAME_1, DATE_2022_09_01, appMetadataSafetyLabel)
+
+ assertThat(safetyLabelForPersistence)
+ .isEqualTo(SafetyLabel(AppInfo(PACKAGE_NAME_1), DATE_2022_09_01, DataLabel(mapOf())))
+ }
+
+ @Test
+ fun extractLocationSharingSafetyLabel_locationSharingNoAds_returnsSafetyLabelForPersistence() {
+ val metadataBundle = createMetadataWithDataShared(createDataSharedWithLocationNoAds())
+ val appMetadataSafetyLabel =
+ AppMetadataSafetyLabel.getSafetyLabelFromMetadata(metadataBundle)!!
+
+ val safetyLabelForPersistence =
+ SafetyLabel.extractLocationSharingSafetyLabel(
+ 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)))))
+ }
+
+ @Test
+ fun extractLocationSharingSafetyLabel_locationSharingAds_returnsSafetyLabelForPersistence() {
+ val metadataBundle = createMetadataWithDataShared(createDataSharedWithLocationWithAds())
+ val appMetadataSafetyLabel =
+ AppMetadataSafetyLabel.getSafetyLabelFromMetadata(metadataBundle)!!
+
+ val safetyLabelForPersistence =
+ SafetyLabel.extractLocationSharingSafetyLabel(
+ 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)))))
+ }
+
+ @Test
+ fun extractLocationSharingSafetyLabel_financeCategory_returnsEmptySafetyLabel() {
+ val metadataBundle = createMetadataWithDataShared(createDataSharedWithFinanceWithAds())
+ val appMetadataSafetyLabel =
+ AppMetadataSafetyLabel.getSafetyLabelFromMetadata(metadataBundle)!!
+
+ val safetyLabelForPersistence =
+ SafetyLabel.extractLocationSharingSafetyLabel(
+ PACKAGE_NAME_2, DATE_2022_10_10, appMetadataSafetyLabel)
+
+ assertThat(safetyLabelForPersistence)
+ .isEqualTo(SafetyLabel(AppInfo(PACKAGE_NAME_2), DATE_2022_10_10, DataLabel(mapOf())))
+ }
+
+ @Test
+ fun extractLocationSharingSafetyLabel_locationFinance_returnsLocationSafetyLabel() {
+ val metadataBundle =
+ createMetadataWithDataShared(createDataSharedWithLocationAndFinanceWithAds())
+ val appMetadataSafetyLabel =
+ AppMetadataSafetyLabel.getSafetyLabelFromMetadata(metadataBundle)!!
+
+ val safetyLabelForPersistence =
+ SafetyLabel.extractLocationSharingSafetyLabel(
+ 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)))))
+ }
+
+ /** Companion object for [AppsSafetyLabelHistoryTest]. */
+ companion object {
+ private const val PACKAGE_NAME_1 = "package_name_1"
+ private const val PACKAGE_NAME_2 = "package_name_2"
+ private const val FINANCE_CATEGORY = "finance"
+ private const val FINANCIAL_PURCHASE_HISTORY = "purchase_history"
+ 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 SAFETY_LABEL_KEY = "safety_labels"
+ private const val DATA_SHARED_KEY = "data_shared"
+ private const val DATA_LABEL_KEY = "data_labels"
+ private const val PURPOSES_KEY = "purposes"
+ private const val TOP_LEVEL_VERSION = 1L
+ private const val SAFETY_LABELS_VERSION = 1L
+ private val DATE_2022_09_01 = ZonedDateTime.parse("2022-09-01T00:00:00.000Z").toInstant()
+ private val DATE_2022_10_10 = ZonedDateTime.parse("2022-10-10T00:00:00.000Z").toInstant()
+
+ fun createDataSharedNoSharing(): PersistableBundle {
+ return PersistableBundle()
+ }
+
+ fun createDataSharedWithLocationNoAds(): PersistableBundle {
+ val locationBundle =
+ PersistableBundle().apply {
+ putPersistableBundle(
+ APPROX_LOCATION,
+ PersistableBundle().apply {
+ putIntArray(
+ PURPOSES_KEY,
+ listOf(PURPOSE_FRAUD_PREVENTION_SECURITY).toIntArray())
+ })
+ }
+
+ return PersistableBundle().apply {
+ putPersistableBundle(LOCATION_CATEGORY, locationBundle)
+ }
+ }
+
+ fun createDataSharedWithLocationWithAds(): PersistableBundle {
+ val locationBundle =
+ PersistableBundle().apply {
+ putPersistableBundle(
+ APPROX_LOCATION,
+ PersistableBundle().apply {
+ putIntArray(PURPOSES_KEY, listOf(PURPOSE_ADVERTISING).toIntArray())
+ })
+ }
+
+ return PersistableBundle().apply {
+ putPersistableBundle(LOCATION_CATEGORY, locationBundle)
+ }
+ }
+
+ fun createDataSharedWithFinanceWithAds(): PersistableBundle {
+ val financeBundle =
+ PersistableBundle().apply {
+ putPersistableBundle(
+ FINANCIAL_PURCHASE_HISTORY,
+ PersistableBundle().apply {
+ putIntArray(PURPOSES_KEY, listOf(PURPOSE_ADVERTISING).toIntArray())
+ })
+ }
+
+ return PersistableBundle().apply {
+ putPersistableBundle(FINANCE_CATEGORY, financeBundle)
+ }
+ }
+
+ fun createDataSharedWithLocationAndFinanceWithAds(): PersistableBundle {
+ val locationBundle =
+ PersistableBundle().apply {
+ putPersistableBundle(
+ APPROX_LOCATION,
+ PersistableBundle().apply {
+ putIntArray(PURPOSES_KEY, listOf(PURPOSE_ADVERTISING).toIntArray())
+ })
+ }
+ val financeBundle =
+ PersistableBundle().apply {
+ putPersistableBundle(
+ FINANCIAL_PURCHASE_HISTORY,
+ PersistableBundle().apply {
+ putIntArray(PURPOSES_KEY, listOf(PURPOSE_ADVERTISING).toIntArray())
+ })
+ }
+
+ return PersistableBundle().apply {
+ putPersistableBundle(FINANCE_CATEGORY, financeBundle)
+ putPersistableBundle(LOCATION_CATEGORY, locationBundle)
+ }
+ }
+
+ fun createMetadataWithDataShared(dataSharedBundle: PersistableBundle): PersistableBundle {
+ val dataLabelBundle =
+ PersistableBundle().apply {
+ putPersistableBundle(DATA_SHARED_KEY, dataSharedBundle)
+ }
+
+ val safetyLabelBundle =
+ PersistableBundle().apply {
+ putLong(KEY_VERSION, SAFETY_LABELS_VERSION)
+ putPersistableBundle(DATA_LABEL_KEY, dataLabelBundle)
+ }
+
+ return PersistableBundle().apply {
+ putLong(KEY_VERSION, TOP_LEVEL_VERSION)
+ putPersistableBundle(SAFETY_LABEL_KEY, safetyLabelBundle)
+ }
+ }
+ }
+}
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
new file mode 100644
index 000000000..f6395f8ea
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/SafetyLabelChangesJobServiceTest.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.tests.mocking.safetylabel
+
+import android.app.NotificationManager
+import android.app.job.JobInfo
+import android.app.job.JobParameters
+import android.app.job.JobScheduler
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.UserManager
+import android.provider.DeviceConfig
+import android.safetylabel.SafetyLabelConstants
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.SdkSuppress
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.permissioncontroller.Constants
+import com.android.permissioncontroller.PermissionControllerApplication
+import com.android.permissioncontroller.permission.service.v34.SafetyLabelChangesJobService
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.doNothing
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.times
+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.Spy
+import org.mockito.quality.Strictness
+
+/** Tests for [SafetyLabelChangesJobService]. */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+class SafetyLabelChangesJobServiceTest {
+ @Spy private val service = SafetyLabelChangesJobService()
+ private val receiver = SafetyLabelChangesJobService.Receiver()
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
+ private lateinit var mockitoSession: MockitoSession
+
+ @Mock private lateinit var application: PermissionControllerApplication
+
+ @Mock private lateinit var mockJobScheduler: JobScheduler
+
+ @Mock private lateinit var mockUserManager: UserManager
+
+ @Mock private lateinit var mockNotificationManager: NotificationManager
+
+ @Mock private lateinit var mockPackageManager: PackageManager
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ mockitoSession =
+ ExtendedMockito.mockitoSession()
+ .mockStatic(DeviceConfig::class.java)
+ .mockStatic(PermissionControllerApplication::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
+
+ // Mock flags
+ setSafetyLabelChangeNotificationsEnabled(true)
+
+ // Mock application context
+ whenever(PermissionControllerApplication.get()).thenReturn(application)
+ whenever(application.resources).thenReturn(context.resources)
+ whenever(application.applicationInfo).thenReturn(context.applicationInfo)
+ whenever(application.applicationContext).thenReturn(application)
+ whenever(mockUserManager.isProfile).thenReturn(false)
+ whenever(application.packageManager).thenReturn(mockPackageManager)
+ whenever(mockPackageManager.hasSystemFeature(eq(PackageManager.FEATURE_AUTOMOTIVE)))
+ .thenReturn(false)
+ whenever(mockPackageManager.hasSystemFeature(eq(PackageManager.FEATURE_LEANBACK)))
+ .thenReturn(false)
+ whenever(mockPackageManager.hasSystemFeature(eq(PackageManager.FEATURE_WATCH)))
+ .thenReturn(false)
+
+ // Mock services
+ whenever(application.getSystemService(eq(NotificationManager::class.java)))
+ .thenReturn(mockNotificationManager)
+ whenever(application.getSystemService(eq(JobScheduler::class.java)))
+ .thenReturn(mockJobScheduler)
+ whenever(application.getSystemService(eq(UserManager::class.java)))
+ .thenReturn(mockUserManager)
+ doNothing().`when`(service).jobFinished(any(), anyBoolean())
+ }
+
+ @After
+ fun cleanup() {
+ mockitoSession.finishMocking()
+ }
+
+ @Test
+ fun flagsDisabled_onReceiveValidIntentAction_jobNotScheduled() {
+ setSafetyLabelChangeNotificationsEnabled(false)
+
+ receiver.onReceive(application, Intent(Intent.ACTION_BOOT_COMPLETED))
+
+ verifyZeroInteractions(mockJobScheduler)
+ }
+
+ @Test
+ fun onReceiveInvalidIntentAction_jobNotScheduled() {
+ receiver.onReceive(application, Intent(Intent.ACTION_DEFAULT))
+
+ verifyZeroInteractions(mockJobScheduler)
+ }
+
+ @Test
+ fun onReceiveValidIntentAction_jobsScheduled() {
+ receiver.onReceive(application, Intent(Intent.ACTION_BOOT_COMPLETED))
+
+ 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[1].id)
+ .isEqualTo(Constants.SAFETY_LABEL_CHANGES_PERIODIC_NOTIFICATION_JOB_ID)
+ }
+
+ private fun mockJobParamsForJobId(jobId: Int): JobParameters {
+ val jobParameters = mock(JobParameters::class.java)
+ whenever(jobParameters.jobId).thenReturn(jobId)
+ return jobParameters
+ }
+
+ private fun setSafetyLabelChangeNotificationsEnabled(flagValue: Boolean) {
+ whenever(
+ DeviceConfig.getBoolean(
+ eq(DeviceConfig.NAMESPACE_PRIVACY),
+ eq(SafetyLabelConstants.SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED),
+ anyBoolean()))
+ .thenReturn(flagValue)
+ }
+} \ No newline at end of file
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/TEST_MAPPING b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/TEST_MAPPING
new file mode 100644
index 000000000..42dd8fbce
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "PermissionControllerMockingTests",
+ "options": [
+ {
+ "include-filter": "com.android.permissioncontroller.tests.mocking.safetylabel"
+ }
+ ]
+ }
+ ]
+}
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
new file mode 100644
index 000000000..19c5adddd
--- /dev/null
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetylabel/TestSafetyLabels.kt
@@ -0,0 +1,88 @@
+/*
+ * 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.mocking.safetylabel
+
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.AppInfo
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.DataCategory
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.DataLabel
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.SafetyLabel
+import java.time.Instant
+import java.time.ZonedDateTime
+
+/** Safety labels to be used in tests. */
+object TestSafetyLabels {
+ const val PACKAGE_NAME_1 = "package_name_1"
+ const val PACKAGE_NAME_2 = "package_name_2"
+ const val PACKAGE_NAME_3 = "package_name_3"
+ const val LOCATION_CATEGORY = "location"
+ const val FINANCIAL_CATEGORY = "financial"
+ val DATE_2022_09_01: Instant = ZonedDateTime.parse("2022-09-01T00:00:00.000Z").toInstant()
+ val DATE_2022_10_10: Instant = ZonedDateTime.parse("2022-10-10T00:00:00.000Z").toInstant()
+ val DATE_2022_10_12: Instant = ZonedDateTime.parse("2022-10-12T00:00:00.000Z").toInstant()
+ val DATE_2022_10_14: Instant = ZonedDateTime.parse("2022-10-14T00:00:00.000Z").toInstant()
+ val DATE_2022_12_10: Instant = ZonedDateTime.parse("2022-12-10T00:00:00.000Z").toInstant()
+ val DATE_2022_12_30: Instant = ZonedDateTime.parse("2022-12-30T00:00:00.000Z").toInstant()
+
+ /** A Safety label for [PACKAGE_NAME_1]. */
+ val SAFETY_LABEL_PKG_1_V1: SafetyLabel =
+ SafetyLabel(
+ AppInfo(PACKAGE_NAME_1),
+ DATE_2022_09_01,
+ 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))))
+
+ /** 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))))
+
+ /** A Safety label for [PACKAGE_NAME_2]. */
+ val SAFETY_LABEL_PKG_2_V1: SafetyLabel =
+ SafetyLabel(
+ AppInfo(PACKAGE_NAME_2),
+ DATE_2022_10_10,
+ DataLabel(
+ mapOf(
+ LOCATION_CATEGORY to DataCategory(true),
+ FINANCIAL_CATEGORY to DataCategory(false))))
+
+ /** A Safety label for [PACKAGE_NAME_2]. */
+ val SAFETY_LABEL_PKG_2_V2: SafetyLabel =
+ SafetyLabel(AppInfo(PACKAGE_NAME_2), DATE_2022_12_10, DataLabel(mapOf()))
+
+ /** A Safety label for [PACKAGE_NAME_2]. */
+ val SAFETY_LABEL_PKG_2_V3: SafetyLabel =
+ SafetyLabel(
+ AppInfo(PACKAGE_NAME_2),
+ DATE_2022_12_30,
+ 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))))
+}
diff --git a/PermissionController/tests/outofprocess/Android.bp b/PermissionController/tests/outofprocess/Android.bp
index 806c8ecd7..e646def28 100644
--- a/PermissionController/tests/outofprocess/Android.bp
+++ b/PermissionController/tests/outofprocess/Android.bp
@@ -51,6 +51,7 @@ android_test {
proto: {
type: "lite",
+ include_dirs: ["packages/modules/Permission/PermissionController/src/com/android/permissioncontroller"],
},
test_suites: [
diff --git a/PermissionController/tests/outofprocess/AndroidTest.xml b/PermissionController/tests/outofprocess/AndroidTest.xml
index c47b78eab..37b8996ff 100644
--- a/PermissionController/tests/outofprocess/AndroidTest.xml
+++ b/PermissionController/tests/outofprocess/AndroidTest.xml
@@ -23,7 +23,7 @@
<object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
<!-- Install test -->
- <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="test-file-name" value="PermissionControllerOutOfProcessTests.apk" />
<option name="cleanup-apks" value="true" />
</target_preparer>
diff --git a/PermissionController/tests/permissionui/Android.bp b/PermissionController/tests/permissionui/Android.bp
index cc57ffa77..704307c1f 100644
--- a/PermissionController/tests/permissionui/Android.bp
+++ b/PermissionController/tests/permissionui/Android.bp
@@ -52,6 +52,7 @@ android_test {
test_suites: [
"device-tests",
+ "general-tests",
"mts-permission",
],
diff --git a/PermissionController/tests/permissionui/AndroidTest.xml b/PermissionController/tests/permissionui/AndroidTest.xml
index 34a56286e..62fc6ed3f 100644
--- a/PermissionController/tests/permissionui/AndroidTest.xml
+++ b/PermissionController/tests/permissionui/AndroidTest.xml
@@ -21,9 +21,10 @@
<option name="test-suite-tag" value="apct-instrumentation" />
<option name="test-tag" value="PermissionUiTestCases" />
<object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.permission.apex" />
<!-- Install test -->
- <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="test-file-name" value="PermissionUiTestCases.apk" />
<option name="cleanup-apks" value="true" />
</target_preparer>
@@ -55,6 +56,19 @@
<option name="teardown-command" value="pm uninstall android.permission.cts.appthatrequestpermission" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
+ <option name="run-command" value="wm dismiss-keyguard" />
+ </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" />
+ <option name="screen-always-on" value="on" />
+ </target_preparer>
+
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.permissioncontroller.tests.permissionui" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
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 5b9f42381..175b7a701 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/PermissionGroupPreferenceUtils.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/PermissionGroupPreferenceUtils.kt
@@ -16,9 +16,9 @@
package com.android.permissioncontroller.permissionui
-import android.support.test.uiautomator.By
+import androidx.test.uiautomator.By
import com.android.compatibility.common.util.SystemUtil.getEventually
-import com.android.compatibility.common.util.UiAutomatorUtils.waitFindObject
+import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject
private const val SUMMARY_TEXT = "apps 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 35cb11f94..25aa79632 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/UiUtils.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/UiUtils.kt
@@ -16,7 +16,7 @@
package com.android.permissioncontroller.permissionui
-import android.support.test.uiautomator.UiDevice
+import androidx.test.uiautomator.UiDevice
import androidx.test.platform.app.InstrumentationRegistry
/**
@@ -28,3 +28,11 @@ fun wakeUpScreen() {
uiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP")
uiDevice.executeShellCommand("wm dismiss-keyguard")
}
+
+/**
+ * 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 fd879a553..d5f574327 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,12 +19,12 @@ package com.android.permissioncontroller.permissionui.ui
import android.content.Intent
import android.permission.cts.PermissionUtils.install
import android.permission.cts.PermissionUtils.uninstallApp
-import android.support.test.uiautomator.By
+import androidx.test.uiautomator.By
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.compatibility.common.util.SystemUtil.eventually
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
-import com.android.compatibility.common.util.UiAutomatorUtils.waitFindObject
-import com.android.compatibility.common.util.UiAutomatorUtils.waitFindObjectOrNull
+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
@@ -60,6 +60,8 @@ class AllAppPermissionsFragmentTest : BasePermissionUiTest() {
private val PERM_LABEL = "Permission B"
private val SECOND_PERM_LABEL = "Permission C"
+ private val TIMEOUT_SHORT = 500L
+
@Before
fun assumeNotTelevision() = assumeFalse(isTelevision)
@@ -77,6 +79,7 @@ class AllAppPermissionsFragmentTest : BasePermissionUiTest() {
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)
})
}
@@ -109,7 +112,7 @@ class AllAppPermissionsFragmentTest : BasePermissionUiTest() {
install(PERMISSION_USER_APK)
eventually {
- assertNull(waitFindObjectOrNull(By.text(SECOND_PERM_LABEL)))
+ assertNull(waitFindObjectOrNull(By.text(SECOND_PERM_LABEL), TIMEOUT_SHORT))
}
}
@@ -117,7 +120,7 @@ class AllAppPermissionsFragmentTest : BasePermissionUiTest() {
fun activityIsClosedWhenUserIsUninstalled() {
uninstallApp(USER_PKG)
eventually {
- assertNull(waitFindObjectOrNull(By.text(ALL_PERMISSIONS)))
+ assertNull(waitFindObjectOrNull(By.text(ALL_PERMISSIONS), TIMEOUT_SHORT))
}
}
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 149500438..7b058d004 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,11 +21,11 @@ import android.os.UserHandle
import android.os.UserHandle.myUserId
import android.permission.cts.PermissionUtils.install
import android.permission.cts.PermissionUtils.uninstallApp
-import android.support.test.uiautomator.By
+import androidx.test.uiautomator.By
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.compatibility.common.util.SystemUtil.eventually
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
-import com.android.compatibility.common.util.UiAutomatorUtils.waitFindObjectOrNull
+import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObjectOrNull
import com.android.permissioncontroller.permissionui.wakeUpScreen
import org.junit.After
import org.junit.Assert.assertNull
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 5fe02b142..988cbca73 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,10 +17,10 @@
package com.android.permissioncontroller.permissionui.ui
import android.permission.cts.PermissionUtils.uninstallApp
-import android.support.test.uiautomator.By
+import androidx.test.uiautomator.By
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.compatibility.common.util.SystemUtil.eventually
-import com.android.compatibility.common.util.UiAutomatorUtils.waitFindObjectOrNull
+import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObjectOrNull
import org.junit.Assert.assertNull
import org.junit.Ignore
import org.junit.Test
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 1acf375e6..a5453d9e7 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,11 +19,11 @@ package com.android.permissioncontroller.permissionui.ui
import android.content.Intent
import android.permission.cts.PermissionUtils.install
import android.permission.cts.PermissionUtils.uninstallApp
-import android.support.test.uiautomator.By
+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.UiAutomatorUtils.waitFindObject
-import com.android.compatibility.common.util.UiAutomatorUtils.waitFindObjectOrNull
+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
@@ -83,7 +83,8 @@ abstract class PermissionAppsFragmentTest(
}
}
- @Test
+ // TODO(b/280652042) Slow tests aren't good
+ @Test(timeout = 120000)
fun appDisappearsWhenUninstalled() {
assertNull(waitFindObjectOrNull(By.text(userPkg)))
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 fcca9a086..c41dacc96 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,11 +21,11 @@ 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 android.support.test.uiautomator.By
+import androidx.test.uiautomator.By
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.compatibility.common.util.SystemUtil.eventually
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
-import com.android.compatibility.common.util.UiAutomatorUtils.waitFindObject
+import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject
import com.android.permissioncontroller.permissionui.getUsageCountsFromUi
import com.android.permissioncontroller.permissionui.wakeUpScreen
import com.google.common.truth.Truth.assertThat
@@ -61,14 +61,13 @@ class ManageCustomPermissionsFragmentTest : BaseHandheldPermissionUiTest() {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
})
}
-
- waitFindObject(By.textContains(ADDITIONAL_PERMISSIONS_LABEL)).click()
}
@Test
fun groupSummaryGetsUpdatedWhenPermissionGetsGranted() {
install(ONE_PERMISSION_DEFINER_APK)
install(PERMISSION_USER_APK)
+ waitFindObject(By.textContains(ADDITIONAL_PERMISSIONS_LABEL)).click()
waitFindObject(By.textContains(PERM_LABEL))
val original = getUsageCountsFromUi(PERM_LABEL)
@@ -83,6 +82,7 @@ class ManageCustomPermissionsFragmentTest : BaseHandheldPermissionUiTest() {
fun groupSummaryGetsUpdatedWhenPermissionGetsRevoked() {
install(ONE_PERMISSION_DEFINER_APK)
install(PERMISSION_USER_APK)
+ waitFindObject(By.textContains(ADDITIONAL_PERMISSIONS_LABEL)).click()
waitFindObject(By.textContains(PERM_LABEL))
val original = getUsageCountsFromUi(PERM_LABEL)
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 0b810691f..5d0fae9a1 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
@@ -22,12 +22,12 @@ 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 android.support.test.uiautomator.By
+import androidx.test.uiautomator.By
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.compatibility.common.util.SystemUtil.eventually
import com.android.compatibility.common.util.SystemUtil.getEventually
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
-import com.android.compatibility.common.util.UiAutomatorUtils.waitFindObject
+import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObjectOrNull
import com.android.permissioncontroller.permissionui.getUsageCountsFromUi
import com.android.permissioncontroller.permissionui.wakeUpScreen
import com.google.common.truth.Truth.assertThat
@@ -65,10 +65,12 @@ class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() {
* @return number of additional permissions
*/
private fun getAdditionalPermissionCount(): Int {
- waitFindObject(By.textContains(ADDITIONAL_PERMISSIONS_LABEL))
-
- val additionalPermissionsSummaryText = waitFindObject(By
- .textContains(ADDITIONAL_PERMISSIONS_SUMMARY)).getText()
+ 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 additionalPermissionsSummaryText = additionalPermissionsSummary.getText()
// Matches a single number out of the summary line, i.e. "...3..." -> "3"
return getEventually {
@@ -88,6 +90,8 @@ class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() {
})
}
+ reuninstallApp(LOCATION_USER_APK, LOCATION_USER_PKG)
+
// Sleep before each test for 1 second for getUsageCountsFromUi to get the correct counts
Thread.sleep(1000)
}
@@ -106,6 +110,7 @@ class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() {
@Test
fun groupSummaryGetsUpdatedWhenAppGetsUninstalled() {
+ reuninstallApp(LOCATION_USER_APK, LOCATION_USER_PKG)
val original = getUsageCountsFromUi(locationGroupLabel)
install(LOCATION_USER_APK)
@@ -114,6 +119,7 @@ class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() {
}
uninstallApp(LOCATION_USER_PKG)
+ reuninstallApp(LOCATION_USER_APK, LOCATION_USER_PKG)
eventually {
assertThat(getUsageCountsFromUi(locationGroupLabel)).isEqualTo(original)
}
@@ -202,6 +208,15 @@ class ManageStandardPermissionsFragmentTest : BaseHandheldPermissionUiTest() {
}
}
+ 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)
+ }
+
@After
fun tearDown() {
uninstallApp(LOCATION_USER_PKG)
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 9ad06515a..ec9971cb4 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
@@ -18,9 +18,9 @@ package com.android.permissioncontroller.permissionui.ui.handheld
import android.Manifest.permission.CAMERA
import android.content.Intent
-import android.support.test.uiautomator.By
+import androidx.test.uiautomator.By
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
-import com.android.compatibility.common.util.UiAutomatorUtils.waitFindObject
+import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject
import com.android.permissioncontroller.permissionui.PermissionHub2Test
import com.android.permissioncontroller.permissionui.ui.CAMERA_TEST_APP_LABEL
import com.android.permissioncontroller.permissionui.ui.grantTestAppPermission
diff --git a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/v31/PermissionUsageV2FragmentTest.kt b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/v31/PermissionUsageFragmentTest.kt
index a032c28d8..2869e1863 100644
--- a/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/v31/PermissionUsageV2FragmentTest.kt
+++ b/PermissionController/tests/permissionui/src/com/android/permissioncontroller/permissionui/ui/handheld/v31/PermissionUsageFragmentTest.kt
@@ -24,24 +24,22 @@ 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.wakeUpScreen
+import com.android.permissioncontroller.permissionui.pressHome
import org.junit.After
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.Before
-import android.support.test.uiautomator.By
-import com.android.compatibility.common.util.UiAutomatorUtils.waitFindObject
-import com.android.permissioncontroller.permissionui.PermissionHub2Test
-import com.android.permissioncontroller.permissionui.wakeUpScreen
-
-/**
- * Simple tests for {@link PermissionUsageV2Fragment}
- */
+/** Simple tests for {@link PermissionUsageFragment} */
@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
-class PermissionUsageV2FragmentTest : PermissionHub2Test() {
+class PermissionUsageFragmentTest : PermissionHub2Test() {
private val APK =
"/data/local/tmp/permissioncontroller/tests/permissionui" +
"/PermissionUiUseCameraPermissionApp.apk"
@@ -62,15 +60,15 @@ class PermissionUsageV2FragmentTest : PermissionHub2Test() {
accessCamera()
runWithShellPermissionIdentity {
- context.startActivity(Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE).apply {
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- })
+ context.startActivity(
+ Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ })
}
eventually {
try {
- waitFindObject(By.res("android:id/title")
- .textContains(CAMERA_PREF_LABEL)).click()
+ waitFindObject(By.res("android:id/title").textContains(CAMERA_PREF_LABEL)).click()
} catch (e: Exception) {
waitFindObject(By.textContains(REFRESH)).click()
throw e
@@ -83,5 +81,6 @@ class PermissionUsageV2FragmentTest : PermissionHub2Test() {
@After
fun uninstallTestApp() {
uninstallApp(APP)
+ pressHome()
}
}
diff --git a/SafetyCenter/Annotations/Android.bp b/SafetyCenter/Annotations/Android.bp
new file mode 100644
index 000000000..852d734b0
--- /dev/null
+++ b/SafetyCenter/Annotations/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.
+//
+
+// Library for internal data used by Safety Center system service and UI.
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+filegroup {
+ name: "safetycenter-annotations-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//packages/modules/Permission/SafetyCenter/ConfigLintChecker"],
+}
+
+java_library {
+ name: "safety-center-annotations",
+ srcs: [
+ ":safetycenter-annotations-sources",
+ ],
+ libs: [
+ "androidx.annotation_annotation",
+ "jsr305",
+ ],
+ apex_available: [
+ "com.android.permission",
+ "test_com.android.permission",
+ ],
+ installable: false,
+ min_sdk_version: "30",
+ sdk_version: "system_current",
+ visibility: [
+ "//packages/modules/Permission:__subpackages__",
+ ],
+}
diff --git a/SafetyCenter/Annotations/java/com/android/safetycenter/annotations/NonNullByDefault.java b/SafetyCenter/Annotations/java/com/android/safetycenter/annotations/NonNullByDefault.java
new file mode 100644
index 000000000..34b6ce798
--- /dev/null
+++ b/SafetyCenter/Annotations/java/com/android/safetycenter/annotations/NonNullByDefault.java
@@ -0,0 +1,42 @@
+/*
+ * 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.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.annotation.Nonnull;
+import javax.annotation.meta.TypeQualifierDefault;
+
+/**
+ * Specifies that all type uses are {@link Nonnull} within the annotated package, unless tagged with
+ * {@code @Nullable}. This helps IDEs flag all potential nullability issues without having to use
+ * {@code @NonNull} annotations.
+ *
+ * <p>This is similar to {@code @ParametersAreNonnullByDefault}, but is also applied more widely
+ * (e.g. to methods return types and fields).
+ */
+@Retention(CLASS)
+@Target(PACKAGE)
+@TypeQualifierDefault({PARAMETER, FIELD, METHOD})
+@Nonnull // Android variant cannot be applied as a type qualifier.
+public @interface NonNullByDefault {}
diff --git a/SafetyCenter/Config/Android.bp b/SafetyCenter/Config/Android.bp
index 2b20cea0f..895b242b0 100644
--- a/SafetyCenter/Config/Android.bp
+++ b/SafetyCenter/Config/Android.bp
@@ -28,7 +28,6 @@ java_library {
name: "safety-center-config",
sdk_version: "module_current",
min_sdk_version: "30",
- target_sdk_version: "32",
srcs: [
":safetycenter-config-parser-sources",
],
@@ -36,10 +35,18 @@ java_library {
"androidx.annotation_annotation",
"framework-annotations-lib",
"framework-permission-s",
+ "safety-center-annotations",
+ ],
+ static_libs: [
+ "modules-utils-build",
],
apex_available: [
"com.android.permission",
"test_com.android.permission",
],
installable: false,
+ visibility: [
+ "//packages/modules/Permission:__subpackages__",
+ "//vendor:__subpackages__",
+ ],
}
diff --git a/SafetyCenter/Config/TEST_MAPPING b/SafetyCenter/Config/TEST_MAPPING
index a39176e27..c35d3d777 100644
--- a/SafetyCenter/Config/TEST_MAPPING
+++ b/SafetyCenter/Config/TEST_MAPPING
@@ -3,5 +3,15 @@
{
"name": "SafetyCenterConfigTests"
}
+ ],
+ "mainline-presubmit": [
+ {
+ "name": "SafetyCenterConfigTests[com.google.android.permission.apex]",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ }
+ ]
+ }
]
}
diff --git a/SafetyCenter/Config/java/com/android/safetycenter/config/ParseException.java b/SafetyCenter/Config/java/com/android/safetycenter/config/ParseException.java
index e73f98484..91c7c6654 100644
--- a/SafetyCenter/Config/java/com/android/safetycenter/config/ParseException.java
+++ b/SafetyCenter/Config/java/com/android/safetycenter/config/ParseException.java
@@ -18,19 +18,17 @@ package com.android.safetycenter.config;
import static android.os.Build.VERSION_CODES.TIRAMISU;
-import android.annotation.NonNull;
-
import androidx.annotation.RequiresApi;
/** Exception thrown when there is an error parsing the Safety Center configuration. */
@RequiresApi(TIRAMISU)
public final class ParseException extends Exception {
- public ParseException(@NonNull String message) {
+ public ParseException(String message) {
super(message);
}
- public ParseException(@NonNull String message, @NonNull Throwable ex) {
+ public ParseException(String message, Throwable ex) {
super(message, ex);
}
}
diff --git a/SafetyCenter/Config/java/com/android/safetycenter/config/SafetyCenterConfigParser.java b/SafetyCenter/Config/java/com/android/safetycenter/config/SafetyCenterConfigParser.java
index 8081ae472..b6730f36f 100644
--- a/SafetyCenter/Config/java/com/android/safetycenter/config/SafetyCenterConfigParser.java
+++ b/SafetyCenter/Config/java/com/android/safetycenter/config/SafetyCenterConfigParser.java
@@ -28,7 +28,6 @@ import static org.xmlpull.v1.XmlPullParser.TEXT;
import static java.util.Locale.ROOT;
import static java.util.Objects.requireNonNull;
-import android.annotation.NonNull;
import android.annotation.StringRes;
import android.content.res.Resources;
import android.safetycenter.config.SafetyCenterConfig;
@@ -37,6 +36,8 @@ import android.safetycenter.config.SafetySourcesGroup;
import androidx.annotation.RequiresApi;
+import com.android.modules.utils.build.SdkLevel;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
@@ -58,6 +59,7 @@ public final class SafetyCenterConfigParser {
private static final String ATTR_SAFETY_SOURCES_GROUP_TITLE = "title";
private static final String ATTR_SAFETY_SOURCES_GROUP_SUMMARY = "summary";
private static final String ATTR_SAFETY_SOURCES_GROUP_STATELESS_ICON_TYPE = "statelessIconType";
+ private static final String ATTR_SAFETY_SOURCES_GROUP_TYPE = "type";
private static final String ATTR_SAFETY_SOURCE_ID = "id";
private static final String ATTR_SAFETY_SOURCE_PACKAGE_NAME = "packageName";
private static final String ATTR_SAFETY_SOURCE_TITLE = "title";
@@ -71,8 +73,14 @@ public final class SafetyCenterConfigParser {
private static final String ATTR_SAFETY_SOURCE_LOGGING_ALLOWED = "loggingAllowed";
private static final String ATTR_SAFETY_SOURCE_REFRESH_ON_PAGE_OPEN_ALLOWED =
"refreshOnPageOpenAllowed";
+ private static final String ATTR_SAFETY_SOURCE_NOTIFICATIONS_ALLOWED = "notificationsAllowed";
+ private static final String ATTR_SAFETY_SOURCE_DEDUPLICATION_GROUP = "deduplicationGroup";
+ private static final String ATTR_SAFETY_SOURCE_PACKAGE_CERT_HASHES = "packageCertificateHashes";
private static final String ENUM_STATELESS_ICON_TYPE_NONE = "none";
private static final String ENUM_STATELESS_ICON_TYPE_PRIVACY = "privacy";
+ private static final String ENUM_GROUP_TYPE_STATEFUL = "stateful";
+ private static final String ENUM_GROUP_TYPE_STATELESS = "stateless";
+ private static final String ENUM_GROUP_TYPE_HIDDEN = "hidden";
private static final String ENUM_PROFILE_PRIMARY = "primary_profile_only";
private static final String ENUM_PROFILE_ALL = "all_profiles";
private static final String ENUM_INITIAL_DISPLAY_STATE_ENABLED = "enabled";
@@ -91,9 +99,8 @@ public final class SafetyCenterConfigParser {
* @param resources the {@link Resources} retrieved from the package that contains the Safety
* Center configuration
*/
- @NonNull
- public static SafetyCenterConfig parseXmlResource(
- @NonNull InputStream in, @NonNull Resources resources) throws ParseException {
+ public static SafetyCenterConfig parseXmlResource(InputStream in, Resources resources)
+ throws ParseException {
requireNonNull(in);
requireNonNull(resources);
try {
@@ -118,9 +125,8 @@ public final class SafetyCenterConfigParser {
}
}
- @NonNull
private static SafetyCenterConfig parseSafetyCenterConfig(
- @NonNull XmlPullParser parser, @NonNull Resources resources)
+ XmlPullParser parser, Resources resources)
throws XmlPullParserException, IOException, ParseException {
validateElementHasNoAttribute(parser, TAG_SAFETY_CENTER_CONFIG);
parser.nextTag();
@@ -143,9 +149,8 @@ public final class SafetyCenterConfigParser {
}
}
- @NonNull
private static SafetySourcesGroup parseSafetySourcesGroup(
- @NonNull XmlPullParser parser, @NonNull Resources resources)
+ XmlPullParser parser, Resources resources)
throws XmlPullParserException, IOException, ParseException {
String name = TAG_SAFETY_SOURCES_GROUP;
SafetySourcesGroup.Builder builder = new SafetySourcesGroup.Builder();
@@ -183,6 +188,18 @@ public final class SafetyCenterConfigParser {
parser.getAttributeName(i),
resources));
break;
+ case ATTR_SAFETY_SOURCES_GROUP_TYPE:
+ if (SdkLevel.isAtLeastU()) {
+ builder.setType(
+ parseGroupType(
+ parser.getAttributeValue(i),
+ name,
+ parser.getAttributeName(i),
+ resources));
+ } else {
+ throw attributeUnexpected(name, parser.getAttributeName(i));
+ }
+ break;
default:
throw attributeUnexpected(name, parser.getAttributeName(i));
}
@@ -215,12 +232,8 @@ public final class SafetyCenterConfigParser {
}
}
- @NonNull
private static SafetySource parseSafetySource(
- @NonNull XmlPullParser parser,
- @NonNull Resources resources,
- int safetySourceType,
- @NonNull String name)
+ XmlPullParser parser, Resources resources, int safetySourceType, String name)
throws XmlPullParserException, IOException, ParseException {
SafetySource.Builder builder = new SafetySource.Builder(safetySourceType);
for (int i = 0; i < parser.getAttributeCount(); i++) {
@@ -321,6 +334,46 @@ public final class SafetyCenterConfigParser {
parser.getAttributeName(i),
resources));
break;
+ case ATTR_SAFETY_SOURCE_NOTIFICATIONS_ALLOWED:
+ if (SdkLevel.isAtLeastU()) {
+ builder.setNotificationsAllowed(
+ parseBoolean(
+ parser.getAttributeValue(i),
+ name,
+ parser.getAttributeName(i),
+ resources));
+ } else {
+ throw attributeUnexpected(name, parser.getAttributeName(i));
+ }
+ break;
+ case ATTR_SAFETY_SOURCE_DEDUPLICATION_GROUP:
+ if (SdkLevel.isAtLeastU()) {
+ builder.setDeduplicationGroup(
+ parseStringResourceValue(
+ parser.getAttributeValue(i),
+ name,
+ parser.getAttributeName(i),
+ resources));
+ } else {
+ throw attributeUnexpected(name, parser.getAttributeName(i));
+ }
+ break;
+ case ATTR_SAFETY_SOURCE_PACKAGE_CERT_HASHES:
+ if (SdkLevel.isAtLeastU()) {
+ String commaSeparatedHashes =
+ parseStringResourceValue(
+ parser.getAttributeValue(i),
+ name,
+ parser.getAttributeName(i),
+ resources);
+ String[] splits = commaSeparatedHashes.split(",");
+ for (int j = 0; j < splits.length; j++) {
+ builder.addPackageCertificateHash(splits[j]);
+ }
+ } else {
+ throw attributeUnexpected(name, parser.getAttributeName(i));
+ }
+ break;
default:
throw attributeUnexpected(name, parser.getAttributeName(i));
}
@@ -335,71 +388,62 @@ public final class SafetyCenterConfigParser {
}
}
- private static void validateElementStart(@NonNull XmlPullParser parser, @NonNull String name)
+ private static void validateElementStart(XmlPullParser parser, String name)
throws XmlPullParserException, ParseException {
if (parser.getEventType() != START_TAG || !parser.getName().equals(name)) {
throw elementMissing(name);
}
}
- private static void validateElementEnd(@NonNull XmlPullParser parser, @NonNull String name)
+ private static void validateElementEnd(XmlPullParser parser, String name)
throws XmlPullParserException, ParseException {
if (parser.getEventType() != END_TAG || !parser.getName().equals(name)) {
throw elementNotClosed(name);
}
}
- private static void validateElementHasNoAttribute(
- @NonNull XmlPullParser parser, @NonNull String name) throws ParseException {
+ private static void validateElementHasNoAttribute(XmlPullParser parser, String name)
+ throws ParseException {
if (parser.getAttributeCount() != 0) {
throw elementInvalid(name);
}
}
- private static ParseException elementMissing(@NonNull String name) {
+ private static ParseException elementMissing(String name) {
return new ParseException(String.format("Element %s missing", name));
}
- private static ParseException elementNotClosed(@NonNull String name) {
+ private static ParseException elementNotClosed(String name) {
return new ParseException(String.format("Element %s not closed", name));
}
- private static ParseException elementInvalid(@NonNull String name) {
+ private static ParseException elementInvalid(String name) {
return new ParseException(String.format("Element %s invalid", name));
}
- private static ParseException elementInvalid(@NonNull String name, @NonNull Throwable e) {
+ private static ParseException elementInvalid(String name, Throwable e) {
return new ParseException(String.format("Element %s invalid", name), e);
}
- private static ParseException attributeUnexpected(
- @NonNull String parent, @NonNull String name) {
+ private static ParseException attributeUnexpected(String parent, String name) {
return new ParseException(String.format("Unexpected attribute %s.%s", parent, name));
}
- private static String attributeInvalidString(
- @NonNull String valueString, @NonNull String parent, @NonNull String name) {
+ private static String attributeInvalidString(String valueString, String parent, String name) {
return String.format("Attribute value \"%s\" in %s.%s invalid", valueString, parent, name);
}
- private static ParseException attributeInvalid(
- @NonNull String valueString, @NonNull String parent, @NonNull String name) {
+ private static ParseException attributeInvalid(String valueString, String parent, String name) {
return new ParseException(attributeInvalidString(valueString, parent, name));
}
private static ParseException attributeInvalid(
- @NonNull String valueString,
- @NonNull String parent,
- @NonNull String name,
- @NonNull Throwable ex) {
+ String valueString, String parent, String name, Throwable ex) {
return new ParseException(attributeInvalidString(valueString, parent, name), ex);
}
private static int parseInteger(
- @NonNull String valueString,
- @NonNull String parent,
- @NonNull String name,
- @NonNull Resources resources)
+ String valueString, String parent, String name, Resources resources)
throws ParseException {
String valueToParse = getValueToParse(valueString, parent, name, resources);
try {
@@ -410,10 +454,7 @@ public final class SafetyCenterConfigParser {
}
private static boolean parseBoolean(
- @NonNull String valueString,
- @NonNull String parent,
- @NonNull String name,
- @NonNull Resources resources)
+ String valueString, String parent, String name, Resources resources)
throws ParseException {
String valueToParse =
getValueToParse(valueString, parent, name, resources).toLowerCase(ROOT);
@@ -427,10 +468,7 @@ public final class SafetyCenterConfigParser {
@StringRes
private static int parseStringResourceName(
- @NonNull String valueString,
- @NonNull String parent,
- @NonNull String name,
- @NonNull Resources resources)
+ String valueString, String parent, String name, Resources resources)
throws ParseException {
if (valueString.isEmpty()) {
throw new ParseException(
@@ -475,20 +513,13 @@ public final class SafetyCenterConfigParser {
return id;
}
- @NonNull
private static String parseStringResourceValue(
- @NonNull String valueString,
- @NonNull String parent,
- @NonNull String name,
- @NonNull Resources resources) {
+ String valueString, String parent, String name, Resources resources) {
return getValueToParse(valueString, parent, name, resources);
}
private static int parseStatelessIconType(
- @NonNull String valueString,
- @NonNull String parent,
- @NonNull String name,
- @NonNull Resources resources)
+ String valueString, String parent, String name, Resources resources)
throws ParseException {
String valueToParse = getValueToParse(valueString, parent, name, resources);
switch (valueToParse) {
@@ -501,11 +532,24 @@ public final class SafetyCenterConfigParser {
}
}
+ private static int parseGroupType(
+ String valueString, String parent, String name, Resources resources)
+ throws ParseException {
+ String valueToParse = getValueToParse(valueString, parent, name, resources);
+ switch (valueToParse) {
+ case ENUM_GROUP_TYPE_STATEFUL:
+ return SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATEFUL;
+ case ENUM_GROUP_TYPE_STATELESS:
+ return SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATELESS;
+ case ENUM_GROUP_TYPE_HIDDEN:
+ return SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_HIDDEN;
+ default:
+ throw attributeInvalid(valueToParse, parent, name);
+ }
+ }
+
private static int parseProfile(
- @NonNull String valueString,
- @NonNull String parent,
- @NonNull String name,
- @NonNull Resources resources)
+ String valueString, String parent, String name, Resources resources)
throws ParseException {
String valueToParse = getValueToParse(valueString, parent, name, resources);
switch (valueToParse) {
@@ -519,10 +563,7 @@ public final class SafetyCenterConfigParser {
}
private static int parseInitialDisplayState(
- @NonNull String valueString,
- @NonNull String parent,
- @NonNull String name,
- @NonNull Resources resources)
+ String valueString, String parent, String name, Resources resources)
throws ParseException {
String valueToParse = getValueToParse(valueString, parent, name, resources);
switch (valueToParse) {
@@ -537,12 +578,8 @@ public final class SafetyCenterConfigParser {
}
}
- @NonNull
private static String getValueToParse(
- @NonNull String valueString,
- @NonNull String parent,
- @NonNull String name,
- @NonNull Resources resources) {
+ String valueString, String parent, String name, Resources resources) {
try {
int id = parseStringResourceName(valueString, parent, name, resources);
return resources.getString(id);
diff --git a/SafetyCenter/Config/java/com/android/safetycenter/config/package-info.java b/SafetyCenter/Config/java/com/android/safetycenter/config/package-info.java
new file mode 100644
index 000000000..45ac9e485
--- /dev/null
+++ b/SafetyCenter/Config/java/com/android/safetycenter/config/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@NonNullByDefault
+package com.android.safetycenter.config;
+
+import com.android.safetycenter.annotations.NonNullByDefault;
diff --git a/SafetyCenter/Config/tests/Android.bp b/SafetyCenter/Config/tests/Android.bp
index 9d9975980..c58f2c922 100644
--- a/SafetyCenter/Config/tests/Android.bp
+++ b/SafetyCenter/Config/tests/Android.bp
@@ -21,7 +21,6 @@ android_test {
defaults: ["mts-target-sdk-version-current"],
sdk_version: "test_current",
min_sdk_version: "30",
- target_sdk_version: "32",
srcs: [
"java/**/*.kt",
],
@@ -31,8 +30,8 @@ android_test {
per_testcase_directory: true,
static_libs: [
"compatibility-device-util-axt",
- "kotlinx-coroutines-android",
"safety-center-config",
+ "safety-center-test-util-lib",
],
test_suites: [
"general-tests",
diff --git a/SafetyCenter/Config/tests/AndroidTest.xml b/SafetyCenter/Config/tests/AndroidTest.xml
index 4524ec665..5edc4c688 100644
--- a/SafetyCenter/Config/tests/AndroidTest.xml
+++ b/SafetyCenter/Config/tests/AndroidTest.xml
@@ -18,10 +18,12 @@
<configuration description="Runs unit tests for the Safety Center Config library.">
<option name="test-tag" value="SafetyCenterConfigTests" />
- <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk33ModuleController" />
+
+ <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
<!-- Install test -->
- <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="test-file-name" value="SafetyCenterConfigTests.apk" />
<option name="cleanup-apks" value="true" />
</target_preparer>
@@ -41,5 +43,6 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.safetycenter.config.tests" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="exclude-annotation" value="org.junit.Ignore"/>
</test>
</configuration>
diff --git a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/Coroutines.kt b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/Coroutines.kt
deleted file mode 100644
index 9b1d4c5f9..000000000
--- a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/Coroutines.kt
+++ /dev/null
@@ -1,77 +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.config
-
-import android.util.Log
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.withTimeout
-import java.time.Duration
-
-/**
- * A class that facilitates interacting with coroutines.
- * TODO(b/228823159) Consolidate with other Coroutines helper functions
- */
-object Coroutines {
-
- /** Behaves in the same way as [runBlocking], but with a timeout. */
- fun <T> runBlockingWithTimeout(timeout: Duration = TIMEOUT_LONG, block: suspend () -> T) =
- runBlocking {
- withTimeout(timeout.toMillis()) { block() }
- }
-
- /** Check a condition using coroutines with a timeout. */
- fun waitForWithTimeout(
- timeout: Duration = TIMEOUT_LONG,
- checkPeriod: Duration = CHECK_PERIOD,
- condition: () -> Boolean
- ) {
- runBlockingWithTimeout(timeout) { waitFor(checkPeriod, condition) }
- }
-
- /** Check a condition using coroutines. */
- suspend fun waitFor(checkPeriod: Duration = CHECK_PERIOD, condition: () -> Boolean) {
- val conditionMet = condition()
- if (conditionMet) {
- return
- }
- delay(checkPeriod.toMillis())
- return waitFor(checkPeriod, condition)
- }
-
- /** Retries a test until no assertions or exceptions are thrown or a timeout occurs. */
- fun waitForTestToPass(test: () -> Unit) {
- waitForWithTimeout {
- try {
- test()
- true
- } catch (ex: Throwable) {
- Log.w(TAG, "Encountered test failure, retrying until timeout: $ex")
- false
- }
- }
- }
-
- /** A medium period, to be used for conditions that are expected to change. */
- private val TAG = "Coroutines"
-
- /** A medium period, to be used for conditions that are expected to change. */
- private val CHECK_PERIOD = Duration.ofMillis(250)
-
- /** A long timeout, to be used for actions that are expected to complete. */
- private val TIMEOUT_LONG: Duration = Duration.ofSeconds(5)
-} \ No newline at end of file
diff --git a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParseExceptionTest.kt b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParseExceptionTest.kt
index ca4f914c4..f9dbc454a 100644
--- a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParseExceptionTest.kt
+++ b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParseExceptionTest.kt
@@ -16,16 +16,13 @@
package com.android.safetycenter.config
-import android.os.Build.VERSION_CODES.TIRAMISU
import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
/** CTS tests for [ParseException]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class ParseExceptionTest {
@Test
diff --git a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigInvalidTest.kt b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigInvalidTest.kt
index a06eaa9fb..64775d7fe 100644
--- a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigInvalidTest.kt
+++ b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigInvalidTest.kt
@@ -17,9 +17,8 @@
package com.android.safetycenter.config
import android.content.Context
-import android.os.Build.VERSION_CODES.TIRAMISU
import androidx.test.core.app.ApplicationProvider.getApplicationContext
-import androidx.test.filters.SdkSuppress
+import com.android.modules.utils.build.SdkLevel
import com.android.safetycenter.config.tests.R
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertThrows
@@ -28,7 +27,6 @@ import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class ParserConfigInvalidTest {
private val context: Context = getApplicationContext()
@@ -36,7 +34,8 @@ class ParserConfigInvalidTest {
private val testName: String,
val configResourceId: Int,
val errorMessage: String,
- val causeErrorMessage: String?
+ val causeErrorMessage: String?,
+ val includeCondition: Boolean = true
) {
override fun toString() = testName
}
@@ -63,292 +62,430 @@ class ParserConfigInvalidTest {
@Parameterized.Parameters(name = "{0}")
fun parameters() =
arrayOf(
- Params(
- "ConfigDynamicSafetySourceAllDisabledNoWork",
- R.raw.config_dynamic_safety_source_all_disabled_no_work,
- "Element dynamic-safety-source invalid",
- "Required attribute titleForWork missing"),
- Params(
- "ConfigDynamicSafetySourceAllHiddenWithSearchNoWork",
- R.raw.config_dynamic_safety_source_all_hidden_with_search_no_work,
- "Element dynamic-safety-source invalid",
- "Required attribute titleForWork missing"),
- Params(
- "ConfigDynamicSafetySourceAllNoWork",
- R.raw.config_dynamic_safety_source_all_no_work,
- "Element dynamic-safety-source invalid",
- "Required attribute titleForWork missing"),
- Params(
- "ConfigDynamicSafetySourceDisabledNoSummary",
- R.raw.config_dynamic_safety_source_disabled_no_summary,
- "Element dynamic-safety-source invalid",
- "Required attribute summary missing"),
- Params(
- "ConfigDynamicSafetySourceDisabledNoTitle",
- R.raw.config_dynamic_safety_source_disabled_no_title,
- "Element dynamic-safety-source invalid",
- "Required attribute title missing"),
- Params(
- "ConfigDynamicSafetySourceDuplicateKey",
- R.raw.config_dynamic_safety_source_duplicate_key,
- "Element safety-sources-config invalid",
- "Duplicate id id among safety sources"),
- Params(
- "ConfigDynamicSafetySourceHiddenWithSearchNoTitle",
- R.raw.config_dynamic_safety_source_hidden_with_search_no_title,
- "Element dynamic-safety-source invalid",
- "Required attribute title missing"),
- Params(
- "ConfigDynamicSafetySourceInvalidDisplay",
- R.raw.config_dynamic_safety_source_invalid_display,
- "Attribute value \"invalid\" in dynamic-safety-source.initialDisplayState " +
- "invalid",
- null),
- Params(
- "ConfigDynamicSafetySourceInvalidProfile",
- R.raw.config_dynamic_safety_source_invalid_profile,
- "Attribute value \"invalid\" in dynamic-safety-source.profile invalid",
- null),
- Params(
- "ConfigDynamicSafetySourceNoId",
- R.raw.config_dynamic_safety_source_no_id,
- "Element dynamic-safety-source invalid",
- "Required attribute id missing"),
- Params(
- "ConfigDynamicSafetySourceNoIntent",
- R.raw.config_dynamic_safety_source_no_intent,
- "Element dynamic-safety-source invalid",
- "Required attribute intentAction missing"),
- Params(
- "ConfigDynamicSafetySourceNoPackage",
- R.raw.config_dynamic_safety_source_no_package,
- "Element dynamic-safety-source invalid",
- "Required attribute packageName missing"),
- Params(
- "ConfigDynamicSafetySourceNoProfile",
- R.raw.config_dynamic_safety_source_no_profile,
- "Element dynamic-safety-source invalid",
- "Required attribute profile missing"),
- Params(
- "ConfigDynamicSafetySourceNoSummary",
- R.raw.config_dynamic_safety_source_no_summary,
- "Element dynamic-safety-source invalid",
- "Required attribute summary missing"),
- Params(
- "ConfigDynamicSafetySourceNoTitle",
- R.raw.config_dynamic_safety_source_no_title,
- "Element dynamic-safety-source invalid",
- "Required attribute title missing"),
- Params(
- "ConfigDynamicSafetySourcePrimaryHiddenWithWork",
- R.raw.config_dynamic_safety_source_primary_hidden_with_work,
- "Element dynamic-safety-source invalid",
- "Prohibited attribute titleForWork present"),
- Params(
- "ConfigDynamicSafetySourcePrimaryWithWork",
- R.raw.config_dynamic_safety_source_primary_with_work,
- "Element dynamic-safety-source invalid",
- "Prohibited attribute titleForWork present"),
- Params(
- "ConfigFileCorrupted",
- R.raw.config_file_corrupted,
- "Exception while parsing the XML resource",
- null),
- Params(
- "ConfigIssueOnlySafetySourceDuplicateKey",
- R.raw.config_issue_only_safety_source_duplicate_key,
- "Element safety-sources-config invalid",
- "Duplicate id id among safety sources"),
- Params(
- "ConfigIssueOnlySafetySourceInvalidProfile",
- R.raw.config_issue_only_safety_source_invalid_profile,
- "Attribute value \"invalid\" in issue-only-safety-source.profile invalid",
- null),
- Params(
- "ConfigIssueOnlySafetySourceNoId",
- R.raw.config_issue_only_safety_source_no_id,
- "Element issue-only-safety-source invalid",
- "Required attribute id missing"),
- Params(
- "ConfigIssueOnlySafetySourceNoPackage",
- R.raw.config_issue_only_safety_source_no_package,
- "Element issue-only-safety-source invalid",
- "Required attribute packageName missing"),
- Params(
- "ConfigIssueOnlySafetySourceNoProfile",
- R.raw.config_issue_only_safety_source_no_profile,
- "Element issue-only-safety-source invalid",
- "Required attribute profile missing"),
- Params(
- "ConfigIssueOnlySafetySourceWithDisplay",
- R.raw.config_issue_only_safety_source_with_display,
- "Element issue-only-safety-source invalid",
- "Prohibited attribute initialDisplayState present"),
- Params(
- "ConfigIssueOnlySafetySourceWithIntent",
- R.raw.config_issue_only_safety_source_with_intent,
- "Element issue-only-safety-source invalid",
- "Prohibited attribute intentAction present"),
- Params(
- "ConfigIssueOnlySafetySourceWithSearch",
- R.raw.config_issue_only_safety_source_with_search,
- "Element issue-only-safety-source invalid",
- "Prohibited attribute searchTerms present"),
- Params(
- "ConfigIssueOnlySafetySourceWithSummary",
- R.raw.config_issue_only_safety_source_with_summary,
- "Element issue-only-safety-source invalid",
- "Prohibited attribute summary present"),
- Params(
- "ConfigIssueOnlySafetySourceWithTitle",
- R.raw.config_issue_only_safety_source_with_title,
- "Element issue-only-safety-source invalid",
- "Prohibited attribute title present"),
- Params(
- "ConfigIssueOnlySafetySourceWithWork",
- R.raw.config_issue_only_safety_source_with_work,
- "Element issue-only-safety-source invalid",
- "Prohibited attribute titleForWork present"),
- Params(
- "ConfigMixedSafetySourceDuplicateKey",
- R.raw.config_mixed_safety_source_duplicate_key,
- "Element safety-sources-config invalid",
- "Duplicate id id among safety sources"),
- Params(
- "ConfigSafetyCenterConfigMissing",
- R.raw.config_safety_center_config_missing,
- "Element safety-center-config missing",
- null),
- Params(
- "ConfigSafetySourcesConfigEmpty",
- R.raw.config_safety_sources_config_empty,
- "Element safety-sources-config invalid",
- "No safety sources groups present"),
- Params(
- "ConfigSafetySourcesConfigMissing",
- R.raw.config_safety_sources_config_missing,
- "Element safety-sources-config missing",
- null),
- Params(
- "ConfigSafetySourcesGroupDuplicateId",
- R.raw.config_safety_sources_group_duplicate_id,
- "Element safety-sources-config invalid",
- "Duplicate id id among safety sources groups"),
- Params(
- "ConfigSafetySourcesGroupEmpty",
- R.raw.config_safety_sources_group_empty,
- "Element safety-sources-group invalid",
- "Safety sources group empty"),
- Params(
- "ConfigSafetySourcesGroupInvalidIcon",
- R.raw.config_safety_sources_group_invalid_icon,
- "Attribute value \"invalid\" in safety-sources-group.statelessIconType invalid",
- null),
- Params(
- "ConfigSafetySourcesGroupNoId",
- R.raw.config_safety_sources_group_no_id,
- "Element safety-sources-group invalid",
- "Required attribute id missing"),
- Params(
- "ConfigSafetySourcesGroupNoTitle",
- R.raw.config_safety_sources_group_no_title,
- "Element safety-sources-group invalid",
- "Required attribute title missing"),
- Params(
- "ConfigStaticSafetySourceDuplicateKey",
- R.raw.config_static_safety_source_duplicate_key,
- "Element safety-sources-config invalid",
- "Duplicate id id among safety sources"),
- Params(
- "ConfigStaticSafetySourceInvalidProfile",
- R.raw.config_static_safety_source_invalid_profile,
- "Attribute value \"invalid\" in static-safety-source.profile invalid",
- null),
- Params(
- "ConfigStaticSafetySourceNoId",
- R.raw.config_static_safety_source_no_id,
- "Element static-safety-source invalid",
- "Required attribute id missing"),
- Params(
- "ConfigStaticSafetySourceNoIntent",
- R.raw.config_static_safety_source_no_intent,
- "Element static-safety-source invalid",
- "Required attribute intentAction missing"),
- Params(
- "ConfigStaticSafetySourceNoProfile",
- R.raw.config_static_safety_source_no_profile,
- "Element static-safety-source invalid",
- "Required attribute profile missing"),
- Params(
- "ConfigStaticSafetySourceNoTitle",
- R.raw.config_static_safety_source_no_title,
- "Element static-safety-source invalid",
- "Required attribute title missing"),
- Params(
- "ConfigStaticSafetySourceWithDisplay",
- R.raw.config_static_safety_source_with_display,
- "Element static-safety-source invalid",
- "Prohibited attribute initialDisplayState present"),
- Params(
- "ConfigStaticSafetySourceWithLogging",
- R.raw.config_static_safety_source_with_logging,
- "Element static-safety-source invalid",
- "Prohibited attribute loggingAllowed present"),
- Params(
- "ConfigStaticSafetySourceWithPackage",
- R.raw.config_static_safety_source_with_package,
- "Element static-safety-source invalid",
- "Prohibited attribute packageName present"),
- Params(
- "ConfigStaticSafetySourceWithPrimaryAndWork",
- R.raw.config_static_safety_source_with_primary_and_work,
- "Element static-safety-source invalid",
- "Prohibited attribute titleForWork present"),
- Params(
- "ConfigStaticSafetySourceWithRefresh",
- R.raw.config_static_safety_source_with_refresh,
- "Element static-safety-source invalid",
- "Prohibited attribute refreshOnPageOpenAllowed present"),
- Params(
- "ConfigStaticSafetySourceWithSeverity",
- R.raw.config_static_safety_source_with_severity,
- "Element static-safety-source invalid",
- "Prohibited attribute maxSeverityLevel present"),
- Params(
- "ConfigStringResourceNameInvalidEmpty",
- R.raw.config_string_resource_name_empty,
- "Resource name in safety-sources-group.title cannot be empty",
- null),
- Params(
- "ConfigStringResourceNameInvalidNoAt",
- R.raw.config_string_resource_name_invalid_no_at,
- "Resource name \"com.android.safetycenter.config.tests:string/reference\" in " +
- "safety-sources-group.title does not start with @",
- null),
- Params(
- "ConfigStringResourceNameInvalidNoPackage",
- R.raw.config_string_resource_name_invalid_no_package,
- "Resource name \"@string/reference\" in safety-sources-group.title does not " +
- "specify a package",
- null),
- Params(
- "ConfigStringResourceNameInvalidNoType",
- R.raw.config_string_resource_name_invalid_no_type,
- "Resource name \"@com.android.safetycenter.config.tests:reference\" in " +
- "safety-sources-group.title does not specify a type",
- null),
- Params(
- "ConfigStringResourceNameInvalidWrongType",
- R.raw.config_string_resource_name_invalid_wrong_type,
- "Resource name \"@com.android.safetycenter.config.tests:raw/" +
- "config_string_resource_name_invalid_wrong_type\" in " +
- "safety-sources-group.title is not a string",
- null),
- Params(
- "ConfigStringResourceNameMissing",
- R.raw.config_string_resource_name_missing,
- "Resource name \"@com.android.safetycenter.config.tests:string/missing\" in " +
- "safety-sources-group.title missing or invalid",
- null))
+ Params(
+ "ConfigDynamicSafetySourceAllDisabledNoWork",
+ R.raw.config_dynamic_safety_source_all_disabled_no_work,
+ "Element dynamic-safety-source invalid",
+ "Required attribute titleForWork missing"
+ ),
+ Params(
+ "ConfigDynamicSafetySourceAllHiddenWithSearchNoWork",
+ R.raw.config_dynamic_safety_source_all_hidden_with_search_no_work,
+ "Element dynamic-safety-source invalid",
+ "Required attribute titleForWork missing"
+ ),
+ Params(
+ "ConfigDynamicSafetySourceAllNoWork",
+ R.raw.config_dynamic_safety_source_all_no_work,
+ "Element dynamic-safety-source invalid",
+ "Required attribute titleForWork missing"
+ ),
+ Params(
+ "ConfigDynamicSafetySourceDisabledNoSummary",
+ R.raw.config_dynamic_safety_source_disabled_no_summary,
+ "Element dynamic-safety-source invalid",
+ "Required attribute summary missing"
+ ),
+ Params(
+ "ConfigDynamicSafetySourceDisabledNoTitle",
+ R.raw.config_dynamic_safety_source_disabled_no_title,
+ "Element dynamic-safety-source invalid",
+ "Required attribute title missing"
+ ),
+ Params(
+ "ConfigDynamicSafetySourceDuplicateKey",
+ R.raw.config_dynamic_safety_source_duplicate_key,
+ "Element safety-sources-config invalid",
+ "Duplicate id id among safety sources"
+ ),
+ Params(
+ "ConfigDynamicSafetySourceHiddenWithSearchNoTitle",
+ R.raw.config_dynamic_safety_source_hidden_with_search_no_title,
+ "Element dynamic-safety-source invalid",
+ "Required attribute title missing"
+ ),
+ Params(
+ "ConfigDynamicSafetySourceInvalidDisplay",
+ R.raw.config_dynamic_safety_source_invalid_display,
+ "Attribute value \"invalid\" in " +
+ "dynamic-safety-source.initialDisplayState invalid",
+ null
+ ),
+ Params(
+ "ConfigDynamicSafetySourceInvalidId",
+ R.raw.config_dynamic_safety_source_invalid_id,
+ "Element dynamic-safety-source invalid",
+ "Attribute id invalid"
+ ),
+ Params(
+ "ConfigDynamicSafetySourceInvalidProfile",
+ R.raw.config_dynamic_safety_source_invalid_profile,
+ "Attribute value \"invalid\" in dynamic-safety-source.profile invalid",
+ null
+ ),
+ Params(
+ "ConfigDynamicSafetySourceNoId",
+ R.raw.config_dynamic_safety_source_no_id,
+ "Element dynamic-safety-source invalid",
+ "Required attribute id missing"
+ ),
+ Params(
+ "ConfigDynamicSafetySourceNoIntent",
+ R.raw.config_dynamic_safety_source_no_intent,
+ "Element dynamic-safety-source invalid",
+ "Required attribute intentAction missing"
+ ),
+ Params(
+ "ConfigDynamicSafetySourceNoPackage",
+ R.raw.config_dynamic_safety_source_no_package,
+ "Element dynamic-safety-source invalid",
+ "Required attribute packageName missing"
+ ),
+ Params(
+ "ConfigDynamicSafetySourceNoProfile",
+ R.raw.config_dynamic_safety_source_no_profile,
+ "Element dynamic-safety-source invalid",
+ "Required attribute profile missing"
+ ),
+ Params(
+ "ConfigDynamicSafetySourceNoSummary",
+ R.raw.config_dynamic_safety_source_no_summary,
+ "Element dynamic-safety-source invalid",
+ "Required attribute summary missing"
+ ),
+ Params(
+ "ConfigDynamicSafetySourceNoTitle",
+ R.raw.config_dynamic_safety_source_no_title,
+ "Element dynamic-safety-source invalid",
+ "Required attribute title missing"
+ ),
+ Params(
+ "ConfigDynamicSafetySourcePrimaryHiddenWithWork",
+ R.raw.config_dynamic_safety_source_primary_hidden_with_work,
+ "Element dynamic-safety-source invalid",
+ "Prohibited attribute titleForWork present"
+ ),
+ Params(
+ "ConfigDynamicSafetySourcePrimaryWithWork",
+ R.raw.config_dynamic_safety_source_primary_with_work,
+ "Element dynamic-safety-source invalid",
+ "Prohibited attribute titleForWork present"
+ ),
+ Params(
+ "ConfigFileCorrupted",
+ R.raw.config_file_corrupted,
+ "Exception while parsing the XML resource",
+ null
+ ),
+ Params(
+ "ConfigIssueOnlySafetySourceDuplicateKey",
+ R.raw.config_issue_only_safety_source_duplicate_key,
+ "Element safety-sources-config invalid",
+ "Duplicate id id among safety sources"
+ ),
+ Params(
+ "ConfigIssueOnlySafetySourceInvalidId",
+ R.raw.config_issue_only_safety_source_invalid_id,
+ "Element issue-only-safety-source invalid",
+ "Attribute id invalid"
+ ),
+ Params(
+ "ConfigIssueOnlySafetySourceInvalidProfile",
+ R.raw.config_issue_only_safety_source_invalid_profile,
+ "Attribute value \"invalid\" in issue-only-safety-source.profile invalid",
+ null
+ ),
+ Params(
+ "ConfigIssueOnlySafetySourceNoId",
+ R.raw.config_issue_only_safety_source_no_id,
+ "Element issue-only-safety-source invalid",
+ "Required attribute id missing"
+ ),
+ Params(
+ "ConfigIssueOnlySafetySourceNoPackage",
+ R.raw.config_issue_only_safety_source_no_package,
+ "Element issue-only-safety-source invalid",
+ "Required attribute packageName missing"
+ ),
+ Params(
+ "ConfigIssueOnlySafetySourceNoProfile",
+ R.raw.config_issue_only_safety_source_no_profile,
+ "Element issue-only-safety-source invalid",
+ "Required attribute profile missing"
+ ),
+ Params(
+ "ConfigIssueOnlySafetySourceWithDisplay",
+ R.raw.config_issue_only_safety_source_with_display,
+ "Element issue-only-safety-source invalid",
+ "Prohibited attribute initialDisplayState present"
+ ),
+ Params(
+ "ConfigIssueOnlySafetySourceWithIntent",
+ R.raw.config_issue_only_safety_source_with_intent,
+ "Element issue-only-safety-source invalid",
+ "Prohibited attribute intentAction present"
+ ),
+ Params(
+ "ConfigIssueOnlySafetySourceWithSearch",
+ R.raw.config_issue_only_safety_source_with_search,
+ "Element issue-only-safety-source invalid",
+ "Prohibited attribute searchTerms present"
+ ),
+ Params(
+ "ConfigIssueOnlySafetySourceWithSummary",
+ R.raw.config_issue_only_safety_source_with_summary,
+ "Element issue-only-safety-source invalid",
+ "Prohibited attribute summary present"
+ ),
+ Params(
+ "ConfigIssueOnlySafetySourceWithTitle",
+ R.raw.config_issue_only_safety_source_with_title,
+ "Element issue-only-safety-source invalid",
+ "Prohibited attribute title present"
+ ),
+ Params(
+ "ConfigIssueOnlySafetySourceWithWork",
+ R.raw.config_issue_only_safety_source_with_work,
+ "Element issue-only-safety-source invalid",
+ "Prohibited attribute titleForWork present"
+ ),
+ Params(
+ "ConfigMixedSafetySourceDuplicateKey",
+ R.raw.config_mixed_safety_source_duplicate_key,
+ "Element safety-sources-config invalid",
+ "Duplicate id id among safety sources"
+ ),
+ Params(
+ "ConfigSafetyCenterConfigMissing",
+ R.raw.config_safety_center_config_missing,
+ "Element safety-center-config missing",
+ null
+ ),
+ Params(
+ "ConfigSafetySourcesConfigEmpty",
+ R.raw.config_safety_sources_config_empty,
+ "Element safety-sources-config invalid",
+ "No safety sources groups present"
+ ),
+ Params(
+ "ConfigSafetySourcesConfigMissing",
+ R.raw.config_safety_sources_config_missing,
+ "Element safety-sources-config missing",
+ null
+ ),
+ Params(
+ "ConfigSafetySourcesGroupDuplicateId",
+ R.raw.config_safety_sources_group_duplicate_id,
+ "Element safety-sources-config invalid",
+ "Duplicate id id among safety sources groups"
+ ),
+ Params(
+ "ConfigSafetySourcesGroupEmpty",
+ R.raw.config_safety_sources_group_empty,
+ "Element safety-sources-group invalid",
+ "Safety sources group empty"
+ ),
+ Params(
+ "ConfigSafetySourcesGroupHiddenWithOnlyDynamic",
+ R.raw.config_safety_sources_group_hidden_with_only_dynamic,
+ "Element safety-sources-group invalid",
+ "Safety sources groups of type hidden can only contain sources of type " +
+ "issue-only",
+ SdkLevel.isAtLeastU()
+ ),
+ Params(
+ "ConfigSafetySourcesGroupHiddenWithOnlyStatic",
+ R.raw.config_safety_sources_group_hidden_with_only_static,
+ "Element safety-sources-group invalid",
+ "Safety sources groups of type hidden can only contain sources of type " +
+ "issue-only",
+ SdkLevel.isAtLeastU()
+ ),
+ Params(
+ "ConfigSafetySourcesGroupInvalidIcon",
+ R.raw.config_safety_sources_group_invalid_icon,
+ "Attribute value \"invalid\" in safety-sources-group.statelessIconType " +
+ "invalid",
+ null
+ ),
+ Params(
+ "ConfigSafetySourcesGroupInvalidId",
+ R.raw.config_safety_sources_group_invalid_id,
+ "Element safety-sources-group invalid",
+ "Attribute id invalid"
+ ),
+ Params(
+ "ConfigSafetySourcesGroupNoId",
+ R.raw.config_safety_sources_group_no_id,
+ "Element safety-sources-group invalid",
+ "Required attribute id missing"
+ ),
+ Params(
+ "ConfigSafetySourcesGroupNoTitle",
+ R.raw.config_safety_sources_group_no_title,
+ "Element safety-sources-group invalid",
+ "Required attribute title missing"
+ ),
+ Params(
+ "ConfigSafetySourcesGroupStatefulWithOnlyIssueOnly",
+ R.raw.config_safety_sources_group_stateful_with_only_issue_only,
+ "Element safety-sources-group invalid",
+ "Safety sources groups containing only sources of type issue-only must " +
+ "be of type hidden",
+ SdkLevel.isAtLeastU()
+ ),
+ Params(
+ "ConfigSafetySourcesGroupStatelessWithOnlyIssueOnly",
+ R.raw.config_safety_sources_group_stateless_with_only_issue_only,
+ "Element safety-sources-group invalid",
+ "Safety sources groups containing only sources of type issue-only must " +
+ "be of type hidden",
+ SdkLevel.isAtLeastU()
+ ),
+ Params(
+ "ConfigStaticSafetySourceDuplicateKey",
+ R.raw.config_static_safety_source_duplicate_key,
+ "Element safety-sources-config invalid",
+ "Duplicate id id among safety sources"
+ ),
+ Params(
+ "ConfigStaticSafetySourceInvalidId",
+ R.raw.config_static_safety_source_invalid_id,
+ "Element static-safety-source invalid",
+ "Attribute id invalid"
+ ),
+ Params(
+ "ConfigStaticSafetySourceInvalidProfile",
+ R.raw.config_static_safety_source_invalid_profile,
+ "Attribute value \"invalid\" in static-safety-source.profile invalid",
+ null
+ ),
+ Params(
+ "ConfigStaticSafetySourceNoId",
+ R.raw.config_static_safety_source_no_id,
+ "Element static-safety-source invalid",
+ "Required attribute id missing"
+ ),
+ Params(
+ "ConfigStaticSafetySourceNoIntent",
+ R.raw.config_static_safety_source_no_intent,
+ "Element static-safety-source invalid",
+ "Required attribute intentAction missing"
+ ),
+ Params(
+ "ConfigStaticSafetySourceNoProfile",
+ R.raw.config_static_safety_source_no_profile,
+ "Element static-safety-source invalid",
+ "Required attribute profile missing"
+ ),
+ Params(
+ "ConfigStaticSafetySourceNoTitle",
+ R.raw.config_static_safety_source_no_title,
+ "Element static-safety-source invalid",
+ "Required attribute title missing"
+ ),
+ Params(
+ "ConfigStaticSafetySourceWithDeduplicationGroups",
+ R.raw.config_static_safety_source_with_deduplication_groups,
+ "Element static-safety-source invalid",
+ "Prohibited attribute deduplicationGroup present",
+ SdkLevel.isAtLeastU()
+ ),
+ Params(
+ "ConfigStaticSafetySourceWithDisplay",
+ R.raw.config_static_safety_source_with_display,
+ "Element static-safety-source invalid",
+ "Prohibited attribute initialDisplayState present"
+ ),
+ Params(
+ "ConfigStaticSafetySourceWithLogging",
+ R.raw.config_static_safety_source_with_logging,
+ "Element static-safety-source invalid",
+ "Prohibited attribute loggingAllowed present"
+ ),
+ Params(
+ "ConfigStaticSafetySourceWithNotifications",
+ R.raw.config_static_safety_source_with_notifications,
+ "Element static-safety-source invalid",
+ "Prohibited attribute notificationsAllowed present",
+ SdkLevel.isAtLeastU()
+ ),
+ Params(
+ "ConfigStaticSafetySourceWithPackage",
+ R.raw.config_static_safety_source_with_package,
+ "Element static-safety-source invalid",
+ "Prohibited attribute packageName present",
+ !SdkLevel.isAtLeastU()
+ ),
+ Params(
+ "ConfigStaticSafetySourceWithPackageCertficates",
+ R.raw.config_static_safety_source_with_package_certs,
+ "Element static-safety-source invalid",
+ "Prohibited attribute packageCertificateHashes present",
+ SdkLevel.isAtLeastU()
+ ),
+ Params(
+ "ConfigStaticSafetySourceWithPrimaryAndWork",
+ R.raw.config_static_safety_source_with_primary_and_work,
+ "Element static-safety-source invalid",
+ "Prohibited attribute titleForWork present"
+ ),
+ Params(
+ "ConfigStaticSafetySourceWithRefresh",
+ R.raw.config_static_safety_source_with_refresh,
+ "Element static-safety-source invalid",
+ "Prohibited attribute refreshOnPageOpenAllowed present"
+ ),
+ Params(
+ "ConfigStaticSafetySourceWithSeverity",
+ R.raw.config_static_safety_source_with_severity,
+ "Element static-safety-source invalid",
+ "Prohibited attribute maxSeverityLevel present"
+ ),
+ Params(
+ "ConfigStringResourceNameInvalidEmpty",
+ R.raw.config_string_resource_name_empty,
+ "Resource name in safety-sources-group.title cannot be empty",
+ null
+ ),
+ Params(
+ "ConfigStringResourceNameInvalidNoAt",
+ R.raw.config_string_resource_name_invalid_no_at,
+ "Resource name " +
+ "\"com.android.safetycenter.config.tests:string/reference\" in " +
+ "safety-sources-group.title does not start with @",
+ null
+ ),
+ Params(
+ "ConfigStringResourceNameInvalidNoPackage",
+ R.raw.config_string_resource_name_invalid_no_package,
+ "Resource name \"@string/reference\" in safety-sources-group.title does " +
+ "not specify a package",
+ null
+ ),
+ Params(
+ "ConfigStringResourceNameInvalidNoType",
+ R.raw.config_string_resource_name_invalid_no_type,
+ "Resource name \"@com.android.safetycenter.config.tests:reference\" in " +
+ "safety-sources-group.title does not specify a type",
+ null
+ ),
+ Params(
+ "ConfigStringResourceNameInvalidWrongType",
+ R.raw.config_string_resource_name_invalid_wrong_type,
+ "Resource name \"@com.android.safetycenter.config.tests:raw/" +
+ "config_string_resource_name_invalid_wrong_type\" in " +
+ "safety-sources-group.title is not a string",
+ null
+ ),
+ Params(
+ "ConfigStringResourceNameMissing",
+ R.raw.config_string_resource_name_missing,
+ "Resource name \"@com.android.safetycenter.config.tests:string/missing\" " +
+ "in safety-sources-group.title missing or invalid",
+ null
+ )
+ )
+ .filter { it.includeCondition }
}
}
diff --git a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigOverlayTest.kt b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigOverlayTest.kt
index a78d8e502..ef9ad4e1e 100644
--- a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigOverlayTest.kt
+++ b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigOverlayTest.kt
@@ -17,14 +17,12 @@
package com.android.safetycenter.config
import android.content.Context
-import android.os.Build.VERSION_CODES.TIRAMISU
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.SystemUtil.runShellCommand
-import com.android.safetycenter.config.Coroutines.waitForTestToPass
-import com.android.safetycenter.config.Coroutines.waitForWithTimeout
import com.android.safetycenter.config.tests.R
+import com.android.safetycenter.testing.Coroutines.waitForSuccessWithTimeout
+import com.android.safetycenter.testing.Coroutines.waitForWithTimeout
import com.google.common.truth.Truth.assertThat
import org.junit.AfterClass
import org.junit.Assert.assertThrows
@@ -33,12 +31,11 @@ import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class ParserConfigOverlayTest {
private val context: Context = getApplicationContext()
@Test
- fun validNotOverlayableConfig_matchesExpected() = waitForTestToPass {
+ fun validNotOverlayableConfig_matchesExpected() = waitForSuccessWithTimeout {
val inputStream = context.resources.openRawResource(R.raw.config_valid_not_overlayable)
val safetyCenterConfig =
@@ -72,7 +69,7 @@ class ParserConfigOverlayTest {
}
@Test
- fun validOverlayableConfig_matchesExpected() = waitForTestToPass {
+ fun validOverlayableConfig_matchesExpected() = waitForSuccessWithTimeout {
val inputStream = context.resources.openRawResource(R.raw.config_valid_overlayable)
val safetyCenterConfig =
@@ -103,7 +100,7 @@ class ParserConfigOverlayTest {
}
@Test
- fun invalidOverlayableConfig_StringResourceNameInvalid_throws() = waitForTestToPass {
+ fun invalidOverlayableConfig_StringResourceNameInvalid_throws() = waitForSuccessWithTimeout {
val inputStream =
context.resources.openRawResource(R.raw.config_string_resource_name_invalid_overlayable)
@@ -116,7 +113,8 @@ class ParserConfigOverlayTest {
.hasMessageThat()
.isEqualTo(
"Resource name \"@com.android.safetycenter.config.tests:string/reference_overlay" +
- "\" in static-safety-source.summary missing or invalid")
+ "\" in static-safety-source.summary missing or invalid"
+ )
}
companion object {
@@ -127,7 +125,8 @@ class ParserConfigOverlayTest {
private const val STATE_ENABLED = "STATE_ENABLED"
private fun getStateForOverlay(overlayPackage: String): String? {
- val result: String = runShellCommand("cmd overlay dump --user 0 state $overlayPackage")
+ val result: String =
+ runShellCommand("cmd overlay dump --user 0 state $overlayPackage").lines().first()
if (!result.startsWith("STATE_")) {
return null
}
diff --git a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigValidTest.kt b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigValidTest.kt
index dcb6d9cd2..b63ccead7 100644
--- a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigValidTest.kt
+++ b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigValidTest.kt
@@ -17,20 +17,18 @@
package com.android.safetycenter.config
import android.content.Context
-import android.os.Build.VERSION_CODES.TIRAMISU
import android.safetycenter.config.SafetyCenterConfig
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 com.android.modules.utils.build.SdkLevel
import com.android.safetycenter.config.tests.R
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class ParserConfigValidTest {
private val context: Context = getApplicationContext()
@@ -72,6 +70,14 @@ class ParserConfigValidTest {
.setSearchTermsResId(R.string.reference)
.setLoggingAllowed(false)
.setRefreshOnPageOpenAllowed(true)
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup("group")
+ addPackageCertificateHash("feed1")
+ addPackageCertificateHash("feed2")
+ }
+ }
.build()
)
.addSafetySource(
@@ -88,6 +94,14 @@ class ParserConfigValidTest {
.setSearchTermsResId(R.string.reference)
.setLoggingAllowed(false)
.setRefreshOnPageOpenAllowed(true)
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup("group")
+ addPackageCertificateHash("feed1")
+ addPackageCertificateHash("feed2")
+ }
+ }
.build()
)
.addSafetySource(
@@ -138,6 +152,7 @@ class ParserConfigValidTest {
.addSafetySource(
SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_STATIC)
.setId("static_all_optional")
+ .apply { if (SdkLevel.isAtLeastU()) setPackageName("package") }
.setTitleResId(R.string.reference)
.setTitleForWorkResId(R.string.reference)
.setSummaryResId(R.string.reference)
@@ -166,6 +181,21 @@ class ParserConfigValidTest {
.setMaxSeverityLevel(300)
.setLoggingAllowed(false)
.setRefreshOnPageOpenAllowed(true)
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup("group")
+ addPackageCertificateHash("feed1")
+ addPackageCertificateHash("feed2")
+ }
+ }
+ .build()
+ )
+ .addSafetySource(
+ SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY)
+ .setId("id_test_abcxyz_ABCXYZ_012789")
+ .setPackageName("package")
+ .setProfile(SafetySource.PROFILE_PRIMARY)
.build()
)
.build()
@@ -201,6 +231,109 @@ class ParserConfigValidTest {
)
.build()
)
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ addSafetySourcesGroup(
+ SafetySourcesGroup.Builder()
+ .setType(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATEFUL)
+ .setId("stateful_barebone")
+ .setTitleResId(R.string.reference)
+ .addSafetySource(
+ SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_STATIC)
+ .setId("stateful_barebone_source")
+ .setTitleResId(R.string.reference)
+ .setIntentAction("intent")
+ .setProfile(SafetySource.PROFILE_PRIMARY)
+ .build()
+ )
+ .build()
+ )
+ addSafetySourcesGroup(
+ SafetySourcesGroup.Builder()
+ .setType(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATEFUL)
+ .setId("stateful_all_optional")
+ .setTitleResId(R.string.reference)
+ .setSummaryResId(R.string.reference)
+ .setStatelessIconType(
+ SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY
+ )
+ .addSafetySource(
+ SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_STATIC)
+ .setId("stateful_all_optional_source")
+ .setTitleResId(R.string.reference)
+ .setIntentAction("intent")
+ .setProfile(SafetySource.PROFILE_PRIMARY)
+ .build()
+ )
+ .build()
+ )
+ addSafetySourcesGroup(
+ SafetySourcesGroup.Builder()
+ .setType(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATELESS)
+ .setId("stateless_barebone")
+ .setTitleResId(R.string.reference)
+ .addSafetySource(
+ SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_STATIC)
+ .setId("stateless_barebone_source")
+ .setTitleResId(R.string.reference)
+ .setIntentAction("intent")
+ .setProfile(SafetySource.PROFILE_PRIMARY)
+ .build()
+ )
+ .build()
+ )
+ addSafetySourcesGroup(
+ SafetySourcesGroup.Builder()
+ .setType(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATELESS)
+ .setId("stateless_all_optional")
+ .setTitleResId(R.string.reference)
+ .setSummaryResId(R.string.reference)
+ .setStatelessIconType(
+ SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY
+ )
+ .addSafetySource(
+ SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_STATIC)
+ .setId("stateless_all_optional_source")
+ .setTitleResId(R.string.reference)
+ .setIntentAction("intent")
+ .setProfile(SafetySource.PROFILE_PRIMARY)
+ .build()
+ )
+ .build()
+ )
+ addSafetySourcesGroup(
+ SafetySourcesGroup.Builder()
+ .setType(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_HIDDEN)
+ .setId("hidden_barebone")
+ .addSafetySource(
+ SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY)
+ .setId("hidden_barebone_source")
+ .setPackageName("package")
+ .setProfile(SafetySource.PROFILE_PRIMARY)
+ .build()
+ )
+ .build()
+ )
+ addSafetySourcesGroup(
+ SafetySourcesGroup.Builder()
+ .setType(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_HIDDEN)
+ .setId("hidden_all_optional")
+ .setTitleResId(R.string.reference)
+ .setSummaryResId(R.string.reference)
+ .setStatelessIconType(
+ SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY
+ )
+ .addSafetySource(
+ SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY)
+ .setId("hidden_all_optional_source")
+ .setPackageName("package")
+ .setProfile(SafetySource.PROFILE_PRIMARY)
+ .build()
+ )
+ .build()
+ )
+ }
+ }
.build()
assertThat(actual).isEqualTo(expected)
}
diff --git a/SafetyCenter/Config/tests/overlay/Android.bp b/SafetyCenter/Config/tests/overlay/Android.bp
index 06bea5378..65eab02f1 100644
--- a/SafetyCenter/Config/tests/overlay/Android.bp
+++ b/SafetyCenter/Config/tests/overlay/Android.bp
@@ -20,7 +20,9 @@ package {
android_test_helper_app {
name: "SafetyCenterConfigTestsOverlay",
+ defaults: ["mts-target-sdk-version-current"],
sdk_version: "current",
+ min_sdk_version: "30",
test_suites: [
"general-tests",
"mts-permission",
diff --git a/SafetyCenter/Config/tests/res/raw-v34/config_safety_sources_group_hidden_with_only_dynamic.xml b/SafetyCenter/Config/tests/res/raw-v34/config_safety_sources_group_hidden_with_only_dynamic.xml
new file mode 100644
index 000000000..4be2c75ff
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw-v34/config_safety_sources_group_hidden_with_only_dynamic.xml
@@ -0,0 +1,15 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ type="hidden"
+ id="id">
+ <dynamic-safety-source
+ id="id"
+ packageName="package"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw-v34/config_safety_sources_group_hidden_with_only_static.xml b/SafetyCenter/Config/tests/res/raw-v34/config_safety_sources_group_hidden_with_only_static.xml
new file mode 100644
index 000000000..65f9f0ac9
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw-v34/config_safety_sources_group_hidden_with_only_static.xml
@@ -0,0 +1,14 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ type="hidden"
+ id="id">
+ <static-safety-source
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw-v34/config_safety_sources_group_stateful_with_only_issue_only.xml b/SafetyCenter/Config/tests/res/raw-v34/config_safety_sources_group_stateful_with_only_issue_only.xml
new file mode 100644
index 000000000..f801ca544
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw-v34/config_safety_sources_group_stateful_with_only_issue_only.xml
@@ -0,0 +1,13 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ type="stateful"
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference">
+ <issue-only-safety-source
+ id="id"
+ packageName="package"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw-v34/config_safety_sources_group_stateless_with_only_issue_only.xml b/SafetyCenter/Config/tests/res/raw-v34/config_safety_sources_group_stateless_with_only_issue_only.xml
new file mode 100644
index 000000000..9c05e59dd
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw-v34/config_safety_sources_group_stateless_with_only_issue_only.xml
@@ -0,0 +1,13 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ type="stateless"
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference">
+ <issue-only-safety-source
+ id="id"
+ packageName="package"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw-v34/config_static_safety_source_with_deduplication_groups.xml b/SafetyCenter/Config/tests/res/raw-v34/config_static_safety_source_with_deduplication_groups.xml
new file mode 100644
index 000000000..b75969ae1
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw-v34/config_static_safety_source_with_deduplication_groups.xml
@@ -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.
+ -->
+
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference">
+ <static-safety-source
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"
+ deduplicationGroup="group"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config> \ No newline at end of file
diff --git a/SafetyCenter/Config/tests/res/raw-v34/config_static_safety_source_with_notifications.xml b/SafetyCenter/Config/tests/res/raw-v34/config_static_safety_source_with_notifications.xml
new file mode 100644
index 000000000..920f5c44b
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw-v34/config_static_safety_source_with_notifications.xml
@@ -0,0 +1,16 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference">
+ <static-safety-source
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"
+ notificationsAllowed="true"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw-v34/config_static_safety_source_with_package_certs.xml b/SafetyCenter/Config/tests/res/raw-v34/config_static_safety_source_with_package_certs.xml
new file mode 100644
index 000000000..2a99d5617
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw-v34/config_static_safety_source_with_package_certs.xml
@@ -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.
+ -->
+
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference">
+ <static-safety-source
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"
+ packageCertificateHashes="feed1,feed2"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw-v34/config_valid.xml b/SafetyCenter/Config/tests/res/raw-v34/config_valid.xml
new file mode 100644
index 000000000..a473ea225
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw-v34/config_valid.xml
@@ -0,0 +1,193 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="dynamic"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ statelessIconType="privacy">
+ <dynamic-safety-source
+ id="dynamic_barebone"
+ packageName="package"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ <dynamic-safety-source
+ id="dynamic_all_optional"
+ packageName="package"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ titleForWork="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="all_profiles"
+ initialDisplayState="disabled"
+ maxSeverityLevel="300"
+ searchTerms="@com.android.safetycenter.config.tests:string/reference"
+ loggingAllowed="false"
+ refreshOnPageOpenAllowed="true"
+ notificationsAllowed="true"
+ deduplicationGroup="group"
+ packageCertificateHashes="feed1,feed2"/>
+ <dynamic-safety-source
+ id="@com.android.safetycenter.config.tests:string/dynamic_all_references_id"
+ packageName="@com.android.safetycenter.config.tests:string/dynamic_all_references_package_name"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ titleForWork="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="@com.android.safetycenter.config.tests:string/dynamic_all_references_intent_action"
+ profile="@com.android.safetycenter.config.tests:string/dynamic_all_references_profile"
+ initialDisplayState="@com.android.safetycenter.config.tests:string/dynamic_all_references_initial_display_state"
+ maxSeverityLevel="@com.android.safetycenter.config.tests:string/dynamic_all_references_max_severity_level"
+ searchTerms="@com.android.safetycenter.config.tests:string/reference"
+ loggingAllowed="@com.android.safetycenter.config.tests:string/dynamic_all_references_logging_allowed"
+ refreshOnPageOpenAllowed="@com.android.safetycenter.config.tests:string/dynamic_all_references_refresh_on_page_open_allowed"
+ notificationsAllowed="@com.android.safetycenter.config.tests:string/dynamic_all_references_notifications_allowed"
+ deduplicationGroup="@com.android.safetycenter.config.tests:string/dynamic_all_references_deduplication_group"
+ packageCertificateHashes="@com.android.safetycenter.config.tests:string/dynamic_all_references_package_cert_hashes"/>
+ <dynamic-safety-source
+ id="dynamic_disabled"
+ packageName="package"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ profile="primary_profile_only"
+ initialDisplayState="disabled"/>
+ <dynamic-safety-source
+ id="dynamic_hidden"
+ packageName="package"
+ profile="all_profiles"
+ initialDisplayState="hidden"/>
+ <dynamic-safety-source
+ id="dynamic_hidden_with_search"
+ packageName="package"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ titleForWork="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="all_profiles"
+ initialDisplayState="hidden"
+ searchTerms="@com.android.safetycenter.config.tests:string/reference"/>
+ </safety-sources-group>
+ <safety-sources-group
+ id="static"
+ title="@com.android.safetycenter.config.tests:string/reference">
+ <static-safety-source
+ id="static_barebone"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ <static-safety-source
+ id="static_all_optional"
+ packageName="package"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ titleForWork="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="all_profiles"
+ searchTerms="@com.android.safetycenter.config.tests:string/reference"/>
+ </safety-sources-group>
+ <safety-sources-group
+ id="issue_only">
+ <issue-only-safety-source
+ id="issue_only_barebone"
+ packageName="package"
+ profile="primary_profile_only"/>
+ <issue-only-safety-source
+ id="issue_only_all_optional"
+ packageName="package"
+ profile="all_profiles"
+ maxSeverityLevel="300"
+ loggingAllowed="false"
+ refreshOnPageOpenAllowed="true"
+ notificationsAllowed="true"
+ deduplicationGroup="group"
+ packageCertificateHashes="feed1,feed2"/>
+ <issue-only-safety-source
+ id="id_test_abcxyz_ABCXYZ_012789"
+ packageName="package"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ <safety-sources-group
+ id="mixed"
+ title="@com.android.safetycenter.config.tests:string/reference">
+ <dynamic-safety-source
+ id="mixed_dynamic_barebone"
+ packageName="package"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ <issue-only-safety-source
+ id="mixed_issue_only_barebone"
+ packageName="package"
+ profile="primary_profile_only"/>
+ <static-safety-source
+ id="mixed_static_barebone"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ <safety-sources-group
+ type="stateful"
+ id="stateful_barebone"
+ title="@com.android.safetycenter.config.tests:string/reference">
+ <static-safety-source
+ id="stateful_barebone_source"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ <safety-sources-group
+ type="stateful"
+ id="stateful_all_optional"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ statelessIconType="privacy">
+ <static-safety-source
+ id="stateful_all_optional_source"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ <safety-sources-group
+ type="stateless"
+ id="stateless_barebone"
+ title="@com.android.safetycenter.config.tests:string/reference">
+ <static-safety-source
+ id="stateless_barebone_source"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ <safety-sources-group
+ type="stateless"
+ id="stateless_all_optional"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ statelessIconType="privacy">
+ <static-safety-source
+ id="stateless_all_optional_source"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ <safety-sources-group
+ type="hidden"
+ id="hidden_barebone">
+ <issue-only-safety-source
+ id="hidden_barebone_source"
+ packageName="package"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ <safety-sources-group
+ type="hidden"
+ id="hidden_all_optional"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ statelessIconType="privacy">
+ <issue-only-safety-source
+ id="hidden_all_optional_source"
+ packageName="package"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw/config_dynamic_safety_source_invalid_id.xml b/SafetyCenter/Config/tests/res/raw/config_dynamic_safety_source_invalid_id.xml
new file mode 100644
index 000000000..9b7d2c734
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw/config_dynamic_safety_source_invalid_id.xml
@@ -0,0 +1,16 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference">
+ <dynamic-safety-source
+ id="package,id"
+ packageName="package"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw/config_issue_only_safety_source_invalid_id.xml b/SafetyCenter/Config/tests/res/raw/config_issue_only_safety_source_invalid_id.xml
new file mode 100644
index 000000000..52f0a28fb
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw/config_issue_only_safety_source_invalid_id.xml
@@ -0,0 +1,11 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="id">
+ <issue-only-safety-source
+ id="package.id"
+ packageName="package"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw/config_safety_sources_group_invalid_id.xml b/SafetyCenter/Config/tests/res/raw/config_safety_sources_group_invalid_id.xml
new file mode 100644
index 000000000..4be7533bd
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw/config_safety_sources_group_invalid_id.xml
@@ -0,0 +1,15 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="something:id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference">
+ <static-safety-source
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw/config_static_safety_source_invalid_id.xml b/SafetyCenter/Config/tests/res/raw/config_static_safety_source_invalid_id.xml
new file mode 100644
index 000000000..39296459d
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw/config_static_safety_source_invalid_id.xml
@@ -0,0 +1,15 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference">
+ <static-safety-source
+ id="something-id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw/config_valid.xml b/SafetyCenter/Config/tests/res/raw/config_valid.xml
index 8a3ee0917..50b9c995c 100644
--- a/SafetyCenter/Config/tests/res/raw/config_valid.xml
+++ b/SafetyCenter/Config/tests/res/raw/config_valid.xml
@@ -91,6 +91,10 @@
maxSeverityLevel="300"
loggingAllowed="false"
refreshOnPageOpenAllowed="true"/>
+ <issue-only-safety-source
+ id="id_test_abcxyz_ABCXYZ_012789"
+ packageName="package"
+ profile="primary_profile_only"/>
</safety-sources-group>
<safety-sources-group
id="mixed"
diff --git a/SafetyCenter/Config/tests/res/values/strings.xml b/SafetyCenter/Config/tests/res/values/strings.xml
index 195f56c2a..a625c5225 100644
--- a/SafetyCenter/Config/tests/res/values/strings.xml
+++ b/SafetyCenter/Config/tests/res/values/strings.xml
@@ -26,4 +26,7 @@
<string name="dynamic_all_references_max_severity_level" translatable="false">300</string>
<string name="dynamic_all_references_logging_allowed" translatable="false">false</string>
<string name="dynamic_all_references_refresh_on_page_open_allowed" translatable="false">true</string>
+ <string name="dynamic_all_references_notifications_allowed" translatable="false">true</string>
+ <string name="dynamic_all_references_deduplication_group" translatable="false">group</string>
+ <string name="dynamic_all_references_package_cert_hashes" translatable="false">feed1,feed2</string>
</resources>
diff --git a/SafetyCenter/ConfigLintChecker/Android.bp b/SafetyCenter/ConfigLintChecker/Android.bp
index f972fdb53..ff1e28009 100644
--- a/SafetyCenter/ConfigLintChecker/Android.bp
+++ b/SafetyCenter/ConfigLintChecker/Android.bp
@@ -21,6 +21,7 @@ java_library_host {
srcs: [
"java/**/*.java",
"java/**/*.kt",
+ ":safetycenter-annotations-sources",
":safetycenter-config-api-sources",
":safetycenter-config-parser-sources",
],
@@ -33,9 +34,13 @@ java_library_host {
"layoutlib_api-prebuilt", // For com.android.resources.ResourceFolderType
"lint_api",
],
- java_resources: [":safetycenter-config-schema"],
+ java_resources: [":safetycenter-config-schemas"],
jarjar_rules: "jarjar-rules.txt",
kotlincflags: ["-Xjvm-default=all"],
+ visibility: [
+ "//packages/modules/Permission:__subpackages__",
+ "//vendor:__subpackages__",
+ ],
}
java_test_host {
diff --git a/SafetyCenter/ConfigLintChecker/java/android/annotation/SuppressLint.java b/SafetyCenter/ConfigLintChecker/java/android/annotation/SuppressLint.java
new file mode 100644
index 000000000..c6d6dc757
--- /dev/null
+++ b/SafetyCenter/ConfigLintChecker/java/android/annotation/SuppressLint.java
@@ -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 android.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Indicates that Lint should ignore the specified warnings for the annotated element. */
+@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
+@Retention(RetentionPolicy.CLASS)
+public @interface SuppressLint {
+ /**
+ * The set of warnings (identified by the lint issue id) that should be ignored by lint. It is
+ * not an error to specify an unrecognized name.
+ */
+ String[] value();
+}
diff --git a/SafetyCenter/ConfigLintChecker/java/android/os/Build.java b/SafetyCenter/ConfigLintChecker/java/android/os/Build.java
index abe5d49d3..531b6e481 100644
--- a/SafetyCenter/ConfigLintChecker/java/android/os/Build.java
+++ b/SafetyCenter/ConfigLintChecker/java/android/os/Build.java
@@ -20,9 +20,11 @@ package android.os;
public final class Build {
private Build() {}
- /** Stub class to used in the Safety Center config files. */
+ /** Stub class used in the Safety Center config code. */
public static final class VERSION_CODES {
- /** Constant used in the Safety Center config files. */
- public static final int TIRAMISU = 10000;
+ /** 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;
}
}
diff --git a/SafetyCenter/ConfigLintChecker/java/android/os/Parcel.java b/SafetyCenter/ConfigLintChecker/java/android/os/Parcel.java
index e1300de32..81bedc860 100644
--- a/SafetyCenter/ConfigLintChecker/java/android/os/Parcel.java
+++ b/SafetyCenter/ConfigLintChecker/java/android/os/Parcel.java
@@ -29,6 +29,8 @@ public interface Parcel {
int readInt();
/** Method used in the Safety Center config data structures. */
String readString();
+ /** Method used in the Safety Center config data structures. */
+ ArrayList<String> createStringArrayList();
/** Method used in the Safety Center config data structures. */
void writeBoolean(boolean value);
@@ -37,5 +39,7 @@ public interface Parcel {
/** Method used in the Safety Center config data structures. */
void writeString(String value);
/** Method used in the Safety Center config data structures. */
+ void writeStringList(List<String> value);
+ /** Method used in the Safety Center config data structures. */
<T extends Parcelable> void writeTypedList(List<T> value);
}
diff --git a/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ConfigLintCheckerIssueRegistry.kt b/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ConfigLintCheckerIssueRegistry.kt
index 8b9148dfb..205809957 100644
--- a/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ConfigLintCheckerIssueRegistry.kt
+++ b/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ConfigLintCheckerIssueRegistry.kt
@@ -24,10 +24,7 @@ import com.google.auto.service.AutoService
@AutoService(IssueRegistry::class)
@Suppress("UnstableApiUsage")
class ConfigLintCheckerIssueRegistry : IssueRegistry() {
- override val issues = listOf(
- ConfigSchemaDetector.ISSUE,
- ParserExceptionDetector.ISSUE
- )
+ override val issues = listOf(ConfigSchemaDetector.ISSUE, ParserExceptionDetector.ISSUE)
override val api: Int
get() = CURRENT_API
@@ -35,9 +32,10 @@ class ConfigLintCheckerIssueRegistry : IssueRegistry() {
override val minApi: Int
get() = 11
- override val vendor = Vendor(
- vendorName = "Android",
- feedbackUrl = "http://b/issues/new?component=1026964",
- contact = "fiscella@google.com"
- )
+ override val vendor =
+ Vendor(
+ vendorName = "Android",
+ feedbackUrl = "http://b/issues/new?component=1026964",
+ contact = "fiscella@google.com"
+ )
}
diff --git a/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ConfigSchemaDetector.kt b/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ConfigSchemaDetector.kt
index ed58e5341..456ef1171 100644
--- a/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ConfigSchemaDetector.kt
+++ b/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ConfigSchemaDetector.kt
@@ -16,6 +16,7 @@
package android.safetycenter.lint
+import android.os.Build.VERSION_CODES.TIRAMISU
import com.android.resources.ResourceFolderType
import com.android.tools.lint.detector.api.Category
import com.android.tools.lint.detector.api.Context
@@ -36,20 +37,20 @@ import org.xml.sax.SAXException
class ConfigSchemaDetector : Detector(), OtherFileScanner {
companion object {
- val ISSUE = Issue.create(
- id = "InvalidSafetyCenterConfigSchema",
- briefDescription = "The Safety Center config does not meet the schema requirements",
- explanation = """The Safety Center config must follow all constraints defined in \
+ val ISSUE =
+ Issue.create(
+ id = "InvalidSafetyCenterConfigSchema",
+ briefDescription = "The Safety Center config does not meet the schema requirements",
+ explanation =
+ """The Safety Center config must follow all constraints defined in \
safety_center_config.xsd. Either the config is invalid or the schema is not up to
date.""",
- category = Category.CORRECTNESS,
- severity = Severity.ERROR,
- implementation = Implementation(
- ConfigSchemaDetector::class.java,
- Scope.OTHER_SCOPE
- ),
- androidSpecific = true
- )
+ category = Category.CORRECTNESS,
+ severity = Severity.ERROR,
+ implementation =
+ Implementation(ConfigSchemaDetector::class.java, Scope.OTHER_SCOPE),
+ androidSpecific = true
+ )
}
override fun appliesTo(folderType: ResourceFolderType): Boolean {
@@ -60,9 +61,32 @@ class ConfigSchemaDetector : Detector(), OtherFileScanner {
if (context.file.name != "safety_center_config.xml") {
return
}
- val xsd = StreamSource(
- ConfigSchemaDetector::class.java.getResourceAsStream("/safety_center_config.xsd")
- )
+ val fileSdk = FileSdk.getSdkQualifier(context.file)
+ // A config must comply with the schema at the highest SDK level that is lower or equal to
+ // the SDK level of the config itself.
+ var found = false
+ for (sdk in fileSdk downTo TIRAMISU) {
+ if (testSchema(sdk, context)) {
+ found = true
+ break
+ }
+ }
+ if (!found) {
+ context.report(
+ ISSUE,
+ Location.create(context.file),
+ "No schema found for SDK level: $fileSdk, was it deleted?"
+ )
+ }
+ // Test new schemas for backward compatibility.
+ for (sdk in fileSdk + 1..FileSdk.getMaxSdkVersion()) {
+ testSchema(sdk, context)
+ }
+ }
+
+ private fun testSchema(sdk: Int, context: Context): Boolean {
+ val xsdInputStream = FileSdk.getSchemaAsStream(sdk) ?: return false
+ val xsd = StreamSource(xsdInputStream)
val xml = StreamSource(context.file.inputStream())
val schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
try {
@@ -73,14 +97,15 @@ class ConfigSchemaDetector : Detector(), OtherFileScanner {
context.report(
ISSUE,
Location.create(context.file),
- e.message!!
+ "SAXException exception at sdk=$sdk: \"${e.message}\""
)
} catch (e: IOException) {
context.report(
ISSUE,
Location.create(context.file),
- e.message!!
+ "IOException exception at sdk=$sdk: \"${e.message}\""
)
}
+ return true
}
-} \ No newline at end of file
+}
diff --git a/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/FileSdk.kt b/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/FileSdk.kt
new file mode 100644
index 000000000..2d095967b
--- /dev/null
+++ b/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/FileSdk.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.safetycenter.lint
+
+import android.os.Build
+import android.os.Build.VERSION_CODES.TIRAMISU
+import com.google.common.annotations.VisibleForTesting
+import java.io.File
+import java.io.InputStream
+import java.lang.reflect.Modifier.isFinal
+import java.lang.reflect.Modifier.isPublic
+import java.lang.reflect.Modifier.isStatic
+
+/** A class that allows interacting with files that are versioned by sdk. */
+object FileSdk {
+ /**
+ * Linter constant to limit the mocked SDK levels that will be checked. We are making an
+ * important assumption here that if new parser logic is introduced that depends on a new SDK
+ * level, we expect a new schema to exist and a new version code to have been added.
+ */
+ private val MAX_VERSION: Int = maxOf(getMaxVersionCodesConstant(), getMaxSchemaVersion())
+
+ /** Test only override to further limit the mocked SDK that will be checked in a test */
+ @VisibleForTesting @Volatile @JvmStatic var maxVersionOverride: Int? = null
+
+ /**
+ * Returns the max SDK level version that should be used while linting to check for backward
+ * compatibility.
+ */
+ fun getMaxSdkVersion(): Int = maxVersionOverride ?: MAX_VERSION
+
+ /** Returns the SDK level version that a file resource belongs to. */
+ fun getSdkQualifier(file: File): Int {
+ val directParentName = file.parentFile.name
+ val lastQualifier = directParentName.substringAfterLast("-", "")
+ if (lastQualifier.isEmpty() || lastQualifier[0] != 'v') {
+ return TIRAMISU
+ }
+ return lastQualifier.substring(1).toIntOrNull() ?: TIRAMISU
+ }
+
+ /**
+ * Returns whether the file belongs to a basic configuration. By basic, we mean either the
+ * default configuration that has no qualifier, or a configuration that is defined only by an
+ * SDK level version.
+ */
+ fun belongsToABasicConfiguration(file: File): Boolean {
+ val directParentName = file.parentFile.name
+ val qualifierCount = directParentName.count { it == '-' }
+ val lastQualifier = directParentName.substringAfterLast("-", "")
+ if (
+ lastQualifier.isNotEmpty() &&
+ lastQualifier[0] == 'v' &&
+ lastQualifier.substring(1).toIntOrNull() != null
+ ) {
+ return qualifierCount == 1
+ }
+ return qualifierCount == 0
+ }
+
+ /** Returns the schema for the specific SDK level provided or null if it doesn't exist. */
+ fun getSchemaAsStream(sdk: Int): InputStream? =
+ FileSdk::class.java.getResourceAsStream("/safety_center_config${toQualifier(sdk)}.xsd")
+
+ private fun toQualifier(sdk: Int): String = if (sdk == TIRAMISU) "" else "-v$sdk"
+
+ private fun getMaxVersionCodesConstant(): Int =
+ Build.VERSION_CODES::class
+ .java
+ .declaredFields
+ .filter {
+ isPublic(it.modifiers) &&
+ isFinal(it.modifiers) &&
+ isStatic(it.modifiers) &&
+ it.type == Integer.TYPE
+ }
+ .maxOf { it.get(null) as Int }
+
+ private fun getMaxSchemaVersion(): Int =
+ // 99 is an arbitrary high value to look for the schema with the highest SDK level.
+ // Gaps are possible which is why we cannot just stop as soon as an SDK level has no schema.
+ (TIRAMISU..99).filter { getSchemaAsStream(it) != null }.maxOrNull() ?: 0
+}
diff --git a/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ParserExceptionDetector.kt b/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ParserExceptionDetector.kt
index e512b7e54..c05b5404c 100644
--- a/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ParserExceptionDetector.kt
+++ b/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ParserExceptionDetector.kt
@@ -19,6 +19,7 @@ package android.safetycenter.lint
import android.content.res.Resources
import com.android.SdkConstants.ATTR_NAME
import com.android.SdkConstants.TAG_STRING
+import com.android.modules.utils.build.SdkLevel
import com.android.resources.ResourceFolderType
import com.android.safetycenter.config.ParseException
import com.android.safetycenter.config.SafetyCenterConfigParser
@@ -34,6 +35,7 @@ import com.android.tools.lint.detector.api.Severity
import com.android.tools.lint.detector.api.XmlContext
import com.android.tools.lint.detector.api.XmlScanner
import java.util.EnumSet
+import kotlin.math.min
import org.w3c.dom.Element
import org.w3c.dom.Node
@@ -54,11 +56,13 @@ class ParserExceptionDetector : Detector(), OtherFileScanner, XmlScanner {
implementation =
Implementation(
ParserExceptionDetector::class.java,
- EnumSet.of(Scope.RESOURCE_FILE, Scope.OTHER)),
- androidSpecific = true)
+ EnumSet.of(Scope.RESOURCE_FILE, Scope.OTHER)
+ ),
+ androidSpecific = true
+ )
- val STRING_MAP_BUILD_PHASE = 1
- val CONFIG_PARSE_PHASE = 2
+ const val STRING_MAP_BUILD_PHASE = 1
+ const val CONFIG_PARSE_PHASE = 2
}
override fun appliesTo(folderType: ResourceFolderType): Boolean {
@@ -70,23 +74,33 @@ class ParserExceptionDetector : Detector(), OtherFileScanner, XmlScanner {
}
/** Implements XmlScanner and builds a map of string resources in the first phase */
- val mNameToIndex: MutableMap<String, Int> = mutableMapOf()
- val mIndexToValue: MutableMap<Int, String> = mutableMapOf()
- var mIndex = 1000
+ private val mNameToIndex: MutableMap<String, Int> = mutableMapOf()
+ private val mIndexToValue: MutableMap<Int, String> = mutableMapOf()
+ private val mIndexToMinSdk: MutableMap<Int, Int> = mutableMapOf()
+ private var mIndex = 1000
override fun getApplicableElements(): Collection<String>? {
return listOf(TAG_STRING)
}
override fun visitElement(context: XmlContext, element: Element) {
- if (context.driver.phase != STRING_MAP_BUILD_PHASE ||
- context.resourceFolderType != ResourceFolderType.VALUES) {
+ if (
+ context.driver.phase != STRING_MAP_BUILD_PHASE ||
+ context.resourceFolderType != ResourceFolderType.VALUES ||
+ !FileSdk.belongsToABasicConfiguration(context.file)
+ ) {
return
}
+ val minSdk = FileSdk.getSdkQualifier(context.file)
val name = element.getAttribute(ATTR_NAME)
+ val index = mNameToIndex[name]
+ if (index != null) {
+ mIndexToMinSdk[index] = min(mIndexToMinSdk[index]!!, minSdk)
+ return
+ }
var value = ""
- for (index in 0 until element.childNodes.length) {
- val child = element.childNodes.item(index)
+ for (childIndex in 0 until element.childNodes.length) {
+ val child = element.childNodes.item(childIndex)
if (child.nodeType == Node.TEXT_NODE) {
value = child.nodeValue
break
@@ -94,30 +108,52 @@ class ParserExceptionDetector : Detector(), OtherFileScanner, XmlScanner {
}
mNameToIndex[name] = mIndex
mIndexToValue[mIndex] = value
+ mIndexToMinSdk[mIndex] = minSdk
mIndex++
}
/** Implements OtherFileScanner and parses the XML config in the second phase */
override fun run(context: Context) {
- if (context.driver.phase != CONFIG_PARSE_PHASE ||
- context.file.name != "safety_center_config.xml") {
+ if (
+ context.driver.phase != CONFIG_PARSE_PHASE ||
+ context.file.name != "safety_center_config.xml"
+ ) {
return
}
- try {
- SafetyCenterConfigParser.parseXmlResource(
- context.file.inputStream(),
- // Note: using a map of the string resources present in the APK under analysis is
- // necessary in order to get the value of string resources that are resolved and
- // validated at parse time. The drawback of this is that the linter cannot be used
- // on overlay packages that refer to resources in the target package or on packages
- // that refer to Android global resources. However, we cannot use custom a linter
- // with the default soong overlay build rule regardless.
- Resources(context.project.`package`, mNameToIndex, mIndexToValue))
- } catch (e: ParseException) {
- context.report(
- ISSUE,
- Location.create(context.file),
- "Parser exception: \"${e.message}\", cause: \"${e.cause?.message}\"")
+ val minSdk = FileSdk.getSdkQualifier(context.file)
+ val maxSdk = maxOf(minSdk, FileSdk.getMaxSdkVersion())
+ // Test the parser at the SDK level for which the config was designed.
+ // Then test parsers at higher SDK levels for backward compatibility.
+ // This is slightly inefficient if a parser at a higher SDK level has no behavioral changes
+ // compared to one at a lower SDK level, but doing an exhaustive search is safer.
+ for (sdk in minSdk..maxSdk) {
+ synchronized(SdkLevel::class.java) {
+ SdkLevel.setSdkInt(sdk)
+ try {
+ SafetyCenterConfigParser.parseXmlResource(
+ context.file.inputStream(),
+ // Note: using a map of the string resources present in the APK under
+ // analysis is necessary in order to get the value of string resources that
+ // are resolved and validated at parse time. The drawback of this is that
+ // the linter cannot be used on overlay packages that refer to resources in
+ // the target package or on packages that refer to Android global resources.
+ // However, we cannot use a custom linter with the default soong overlay
+ // build rule regardless.
+ Resources(
+ context.project.`package`,
+ mNameToIndex.filterValues { sdk >= mIndexToMinSdk[it]!! },
+ mIndexToValue.filterKeys { sdk >= mIndexToMinSdk[it]!! }
+ )
+ )
+ } catch (e: ParseException) {
+ context.report(
+ ISSUE,
+ Location.create(context.file),
+ "Parser exception at sdk=$sdk: \"${e.message}\", cause: " +
+ "\"${e.cause?.message}\""
+ )
+ }
+ }
}
}
}
diff --git a/SafetyCenter/ConfigLintChecker/java/android/util/ArraySet.java b/SafetyCenter/ConfigLintChecker/java/android/util/ArraySet.java
new file mode 100644
index 000000000..2b5c5669a
--- /dev/null
+++ b/SafetyCenter/ConfigLintChecker/java/android/util/ArraySet.java
@@ -0,0 +1,42 @@
+/*
+ * 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.util;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * A simple ArraySet implementation for the lint checker.
+ *
+ * <p>It's not array based, but for this simple purpose that doesn't matter.
+ *
+ * @param <E> the type of elements maintained by this set
+ */
+public final class ArraySet<E> extends HashSet<E> {
+ public ArraySet() {
+ super();
+ }
+
+ public ArraySet(Collection<? extends E> c) {
+ super(c);
+ }
+
+ public ArraySet(E[] array) {
+ super(Arrays.stream(array).toList());
+ }
+}
diff --git a/SafetyCenter/ConfigLintChecker/java/com/android/modules/utils/build/SdkLevel.java b/SafetyCenter/ConfigLintChecker/java/com/android/modules/utils/build/SdkLevel.java
new file mode 100644
index 000000000..dbfaa56b1
--- /dev/null
+++ b/SafetyCenter/ConfigLintChecker/java/com/android/modules/utils/build/SdkLevel.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.modules.utils.build;
+
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+
+/** Stub class to compile the linter for host execution. */
+public final class SdkLevel {
+ private SdkLevel() {}
+
+ private static volatile int sSdkInt = TIRAMISU;
+
+ /**
+ * Linter only method to set the mocked SDK level for the Safety Center config code.
+ *
+ * <p>You must hold the class lock before calling this method. You should hold the class lock
+ * for the whole duration of the lint check.
+ */
+ public static void setSdkInt(int sdkInt) {
+ if (!Thread.holdsLock(SdkLevel.class)) {
+ throw new IllegalStateException("Lock not held.");
+ }
+ sSdkInt = sdkInt;
+ }
+
+ /** Method used in the Safety Center config code. */
+ public static boolean isAtLeastU() {
+ return sSdkInt >= UPSIDE_DOWN_CAKE;
+ }
+}
diff --git a/SafetyCenter/ConfigLintChecker/tests/java/android/safetycenter/lint/test/ConfigSchemaDetectorTest.kt b/SafetyCenter/ConfigLintChecker/tests/java/android/safetycenter/lint/test/ConfigSchemaDetectorTest.kt
index 0dd4afbd2..0931c479b 100644
--- a/SafetyCenter/ConfigLintChecker/tests/java/android/safetycenter/lint/test/ConfigSchemaDetectorTest.kt
+++ b/SafetyCenter/ConfigLintChecker/tests/java/android/safetycenter/lint/test/ConfigSchemaDetectorTest.kt
@@ -16,11 +16,14 @@
package android.safetycenter.lint.test
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.safetycenter.lint.ConfigSchemaDetector
+import android.safetycenter.lint.FileSdk
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.checks.infrastructure.TestLintTask
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
+import org.junit.After
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -34,11 +37,47 @@ class ConfigSchemaDetectorTest : LintDetectorTest() {
override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+ @After
+ fun resetOverrides() {
+ FileSdk.maxVersionOverride = null
+ }
+
+ @Test
+ fun validMinimumConfig_doesNotThrow() {
+ lint()
+ .files(
+ (xml(
+ "res/raw/safety_center_config.xml",
+ """
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="group"
+ title="@package:string/reference"
+ summary="@package:string/reference">
+ <static-safety-source
+ id="source"
+ title="@package:string/reference"
+ summary="@package:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
+ """
+ ))
+ )
+ .run()
+ .expectClean()
+ }
+
@Test
- fun validConfig_doesNotThrow() {
- lint().files((
- xml("res/raw/safety_center_config.xml",
- """
+ fun validFutureConfig_doesNotThrow() {
+ lint()
+ .files(
+ (xml(
+ "res/raw-99/safety_center_config.xml",
+ """
<safety-center-config>
<safety-sources-config>
<safety-sources-group
@@ -54,26 +93,89 @@ class ConfigSchemaDetectorTest : LintDetectorTest() {
</safety-sources-group>
</safety-sources-config>
</safety-center-config>
- """))).run().expectClean()
+ """
+ ))
+ )
+ .run()
+ .expectClean()
}
@Test
- fun invalidConfig_throws() {
- lint().files((xml("res/raw/safety_center_config.xml", "<invalid-root/>")))
- .run().expect("res/raw/safety_center_config.xml: Error: cvc-elt.1.a: Cannot find the " +
- "declaration of element 'invalid-root'. [InvalidSafetyCenterConfigSchema]\n1 " +
- "errors, 0 warnings")
+ fun invalidConfigWithSingleSchema_throwsOneError() {
+ FileSdk.maxVersionOverride = UPSIDE_DOWN_CAKE
+ lint()
+ .files((xml("res/raw-v34/safety_center_config.xml", "<invalid-root/>")))
+ .run()
+ .expect(
+ "res/raw-v34/safety_center_config.xml: Error: SAXException exception at sdk=34: " +
+ "\"cvc-elt.1.a: Cannot find the declaration of element 'invalid-root'.\" " +
+ "[InvalidSafetyCenterConfigSchema]\n1 errors, 0 warnings"
+ )
+ }
+
+ @Test
+ fun invalidConfigWithMultipleSchemas_throwsMultipleErrors() {
+ FileSdk.maxVersionOverride = UPSIDE_DOWN_CAKE
+ lint()
+ .files((xml("res/raw/safety_center_config.xml", "<invalid-root/>")))
+ .run()
+ .expect(
+ "res/raw/safety_center_config.xml: Error: SAXException exception at sdk=33: " +
+ "\"cvc-elt.1.a: Cannot find the declaration of element 'invalid-root'.\" " +
+ "[InvalidSafetyCenterConfigSchema]\nres/raw/safety_center_config.xml: " +
+ "Error: SAXException exception at sdk=34: \"cvc-elt.1.a: Cannot find the " +
+ "declaration of element 'invalid-root'.\" " +
+ "[InvalidSafetyCenterConfigSchema]\n2 errors, 0 warnings"
+ )
+ }
+
+ @Test
+ fun validUConfigWithUFields_throwsInT() {
+ FileSdk.maxVersionOverride = UPSIDE_DOWN_CAKE
+ lint()
+ .files(
+ (xml(
+ "res/raw/safety_center_config.xml",
+ """
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="group"
+ title="@package:string/reference"
+ summary="@package:string/reference">
+ <dynamic-safety-source
+ id="source"
+ packageName="package"
+ title="@package:string/reference"
+ summary="@package:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"
+ notificationsAllowed="true"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
+ """
+ ))
+ )
+ .run()
+ .expect(
+ "res/raw/safety_center_config.xml: Error: SAXException exception at sdk=33: " +
+ "\"cvc-complex-type.3.2.2: Attribute 'notificationsAllowed' is not allowed " +
+ "to appear in element 'dynamic-safety-source'.\" " +
+ "[InvalidSafetyCenterConfigSchema]\n1 errors, 0 warnings"
+ )
}
@Test
fun unrelatedFile_doesNotThrow() {
- lint().files((xml("res/raw/some_other_config.xml", "<some-other-root/>")))
- .run().expectClean()
+ lint()
+ .files((xml("res/raw/some_other_config.xml", "<some-other-root/>")))
+ .run()
+ .expectClean()
}
@Test
fun unrelatedFolder_doesNotThrow() {
- lint().files((xml("res/values/strings.xml", "<some-other-root/>")))
- .run().expectClean()
+ lint().files((xml("res/values/strings.xml", "<some-other-root/>"))).run().expectClean()
}
}
diff --git a/SafetyCenter/ConfigLintChecker/tests/java/android/safetycenter/lint/test/ParserExceptionDetectorTest.kt b/SafetyCenter/ConfigLintChecker/tests/java/android/safetycenter/lint/test/ParserExceptionDetectorTest.kt
index ad7d36685..1cd693ef6 100644
--- a/SafetyCenter/ConfigLintChecker/tests/java/android/safetycenter/lint/test/ParserExceptionDetectorTest.kt
+++ b/SafetyCenter/ConfigLintChecker/tests/java/android/safetycenter/lint/test/ParserExceptionDetectorTest.kt
@@ -16,11 +16,16 @@
package android.safetycenter.lint.test
+import android.os.Build.VERSION_CODES.TIRAMISU
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import android.safetycenter.lint.FileSdk
import android.safetycenter.lint.ParserExceptionDetector
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestFile
import com.android.tools.lint.checks.infrastructure.TestLintTask
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
+import org.junit.After
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -34,61 +39,171 @@ class ParserExceptionDetectorTest : LintDetectorTest() {
override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+ @After
+ fun resetOverrides() {
+ FileSdk.maxVersionOverride = null
+ }
+
@Test
- fun validConfig_doesNotThrow() {
+ fun validMinimumConfig_doesNotThrow() {
lint()
.files(
- (xml(
- "res/raw/safety_center_config.xml",
- """
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="group"
- title="@lint.test.pkg:string/reference"
- summary="@lint.test.pkg:string/reference">
- <static-safety-source
- id="source"
- title="@lint.test.pkg:string/reference"
- summary="@lint.test.pkg:string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
- """)),
- (xml(
- "res/values/strings.xml",
- """
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="reference" translatable="false">Reference</string>
-</resources>
- """)))
+ xml("res/raw/safety_center_config.xml", VALID_TIRAMISU_CONFIG),
+ STRINGS_WITH_REFERENCE_XML_DEFAULT
+ )
.run()
.expectClean()
}
@Test
- fun invalidConfig_throws() {
+ fun validFutureConfig_doesNotThrow() {
lint()
- .files((xml("res/raw/safety_center_config.xml", "<invalid-root/>")))
+ .files(
+ xml("res/raw-99/safety_center_config.xml", VALID_TIRAMISU_CONFIG),
+ STRINGS_WITH_REFERENCE_XML_DEFAULT
+ )
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun invalidConfigWithSingleSchema_throwsOneError() {
+ FileSdk.maxVersionOverride = UPSIDE_DOWN_CAKE
+ lint()
+ .files(xml("res/raw-v34/safety_center_config.xml", "<invalid-root/>"))
.run()
.expect(
- "res/raw/safety_center_config.xml: Error: Parser exception: " +
+ "res/raw-v34/safety_center_config.xml: Error: Parser exception at sdk=34: " +
"\"Element safety-center-config missing\", cause: \"null\" " +
- "[InvalidSafetyCenterConfig]\n1 errors, 0 warnings")
+ "[InvalidSafetyCenterConfig]\n1 errors, 0 warnings"
+ )
}
@Test
- fun unrelatedFile_doesNotThrow() {
+ fun invalidConfigWithMultipleSchemas_throwsMultipleErrors() {
+ FileSdk.maxVersionOverride = UPSIDE_DOWN_CAKE
lint()
- .files((xml("res/raw/some_other_config.xml", "<some-other-root/>")))
+ .files(xml("res/raw/safety_center_config.xml", "<invalid-root/>"))
.run()
- .expectClean()
+ .expect(
+ "res/raw/safety_center_config.xml: Error: Parser exception at sdk=33: " +
+ "\"Element safety-center-config missing\", cause: \"null\" " +
+ "[InvalidSafetyCenterConfig]\nres/raw/safety_center_config.xml: " +
+ "Error: Parser exception at sdk=34: " +
+ "\"Element safety-center-config missing\", cause: \"null\" " +
+ "[InvalidSafetyCenterConfig]\n2 errors, 0 warnings"
+ )
+ }
+
+ @Test
+ fun validUConfigWithUFields_throwsInT() {
+ FileSdk.maxVersionOverride = UPSIDE_DOWN_CAKE
+ lint()
+ .files(
+ xml("res/raw/safety_center_config.xml", VALID_UDC_CONFIG),
+ STRINGS_WITH_REFERENCE_XML_DEFAULT
+ )
+ .run()
+ .expect(
+ "res/raw/safety_center_config.xml: Error: Parser exception at sdk=33: " +
+ "\"Unexpected attribute dynamic-safety-source.notificationsAllowed\", cause: " +
+ "\"null\" [InvalidSafetyCenterConfig]\n1 errors, 0 warnings"
+ )
+ }
+
+ @Test
+ fun validTConfigWithUReference_throwsInT() {
+ FileSdk.maxVersionOverride = TIRAMISU
+ lint()
+ .files(
+ xml("res/raw/safety_center_config.xml", VALID_TIRAMISU_CONFIG),
+ xml("res/values-v34/strings.xml", STRINGS_WITH_REFERENCE_XML),
+ )
+ .run()
+ .expect(
+ "res/raw/safety_center_config.xml: Error: Parser exception at sdk=33: " +
+ "\"Resource name \"@lint.test.pkg:string/reference\" in " +
+ "safety-sources-group.title missing or invalid\", cause: \"null\" " +
+ "[InvalidSafetyCenterConfig]\n1 errors, 0 warnings"
+ )
+ }
+
+ @Test
+ fun validTConfigWithOtherLanguageReference_throwsInT() {
+ FileSdk.maxVersionOverride = TIRAMISU
+ lint()
+ .files(
+ xml("res/raw/safety_center_config.xml", VALID_TIRAMISU_CONFIG),
+ xml("res/values-ar/strings.xml", STRINGS_WITH_REFERENCE_XML),
+ )
+ .run()
+ .expect(
+ "res/raw/safety_center_config.xml: Error: Parser exception at sdk=33: " +
+ "\"Resource name \"@lint.test.pkg:string/reference\" in " +
+ "safety-sources-group.title missing or invalid\", cause: \"null\" " +
+ "[InvalidSafetyCenterConfig]\n1 errors, 0 warnings"
+ )
+ }
+
+ @Test
+ fun unrelatedFile_doesNotThrow() {
+ lint().files(xml("res/raw/some_other_config.xml", "<some-other-root/>")).run().expectClean()
}
@Test
fun unrelatedFolder_doesNotThrow() {
- lint().files((xml("res/values/strings.xml", "<some-other-root/>"))).run().expectClean()
+ lint().files(xml("res/values/strings.xml", "<some-other-root/>")).run().expectClean()
+ }
+
+ private companion object {
+ const val STRINGS_WITH_REFERENCE_XML =
+ """
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="reference" translatable="false">Reference</string>
+</resources>
+ """
+
+ val STRINGS_WITH_REFERENCE_XML_DEFAULT: TestFile =
+ xml("res/values/strings.xml", STRINGS_WITH_REFERENCE_XML)
+
+ const val VALID_TIRAMISU_CONFIG =
+ """
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="group"
+ title="@lint.test.pkg:string/reference"
+ summary="@lint.test.pkg:string/reference">
+ <static-safety-source
+ id="source"
+ title="@lint.test.pkg:string/reference"
+ summary="@lint.test.pkg:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
+ """
+
+ const val VALID_UDC_CONFIG =
+ """
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="group"
+ title="@lint.test.pkg:string/reference"
+ summary="@lint.test.pkg:string/reference">
+ <dynamic-safety-source
+ id="source"
+ packageName="package"
+ title="@lint.test.pkg:string/reference"
+ summary="@lint.test.pkg:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"
+ notificationsAllowed="true"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
+ """
}
}
diff --git a/SafetyCenter/InternalData/Android.bp b/SafetyCenter/InternalData/Android.bp
new file mode 100644
index 000000000..aa8f96c8b
--- /dev/null
+++ b/SafetyCenter/InternalData/Android.bp
@@ -0,0 +1,50 @@
+//
+// 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.
+//
+
+// Library for internal data used by Safety Center system service and UI.
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_library {
+ name: "safety-center-internal-data",
+ srcs: [
+ "java/**/*.java",
+ "proto/safety_center_internal_data.proto",
+ ],
+ libs: [
+ "androidx.annotation_annotation",
+ "safety-center-annotations",
+ ],
+ apex_available: [
+ "com.android.permission",
+ "test_com.android.permission",
+ ],
+ static_libs: [
+ "libprotobuf-java-lite",
+ "modules-utils-build_system",
+ ],
+ proto: {
+ type: "lite",
+ },
+ installable: false,
+ min_sdk_version: "30",
+ sdk_version: "system_current",
+ visibility: [
+ "//packages/modules/Permission:__subpackages__",
+ "//cts:__subpackages__",
+ ],
+}
diff --git a/SafetyCenter/InternalData/java/com/android/safetycenter/internaldata/SafetyCenterBundles.java b/SafetyCenter/InternalData/java/com/android/safetycenter/internaldata/SafetyCenterBundles.java
new file mode 100644
index 000000000..5fbf8796f
--- /dev/null
+++ b/SafetyCenter/InternalData/java/com/android/safetycenter/internaldata/SafetyCenterBundles.java
@@ -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.safetycenter.internaldata;
+
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+
+import android.os.Bundle;
+import android.safetycenter.SafetyCenterData;
+import android.safetycenter.SafetyCenterEntryGroup;
+import android.safetycenter.SafetyCenterIssue;
+import android.safetycenter.SafetyCenterStaticEntry;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+
+import com.android.modules.utils.build.SdkLevel;
+
+/** A class to facilitate working with Safety Center {@link Bundle}s. */
+@RequiresApi(TIRAMISU)
+public final class SafetyCenterBundles {
+
+ private SafetyCenterBundles() {}
+
+ /**
+ * A key used in {@link SafetyCenterData#getExtras()} that returns a {@link Bundle} mapping
+ * {@link SafetyCenterIssue} ids to their associated {@link SafetyCenterEntryGroup} ids.
+ */
+ public static final String ISSUES_TO_GROUPS_BUNDLE_KEY = "IssuesToGroups";
+
+ /**
+ * A key used in {@link SafetyCenterData#getExtras()} that returns a {@link Bundle} mapping
+ * {@link SafetyCenterStaticEntry} to their associated {@link SafetyCenterEntryId}.
+ *
+ * @see #getStaticEntryId(SafetyCenterData, SafetyCenterStaticEntry)
+ * @see #toBundleKey(SafetyCenterStaticEntry)
+ */
+ public static final String STATIC_ENTRIES_TO_IDS_BUNDLE_KEY = "StaticEntriesToIds";
+
+ /**
+ * Returns the {@link SafetyCenterEntryId} associated with a {@link SafetyCenterStaticEntry}
+ * using the {@link SafetyCenterData#getExtras()} {@link Bundle}.
+ *
+ * <p>Returns {@code null} if the {@link SafetyCenterEntryId} couldn't be retrieved.
+ *
+ * <p>This is a hack to workaround the fact that {@link SafetyCenterStaticEntry} doesn't expose
+ * an associated ID.
+ */
+ @Nullable
+ public static SafetyCenterEntryId getStaticEntryId(
+ SafetyCenterData safetyCenterData, SafetyCenterStaticEntry safetyCenterStaticEntry) {
+ if (!SdkLevel.isAtLeastU()) {
+ return null;
+ }
+ Bundle staticEntriesToIds =
+ safetyCenterData.getExtras().getBundle(STATIC_ENTRIES_TO_IDS_BUNDLE_KEY);
+ if (staticEntriesToIds == null) {
+ return null;
+ }
+ String entryIdString = staticEntriesToIds.getString(toBundleKey(safetyCenterStaticEntry));
+ if (entryIdString == null) {
+ return null;
+ }
+ return SafetyCenterIds.entryIdFromString(entryIdString);
+ }
+
+ /**
+ * Returns a {@code String} that uniquely identifies the {@link SafetyCenterStaticEntry} in the
+ * {@link SafetyCenterData#getExtras()} {@link Bundle}.
+ *
+ * <p>This key is generated based on the {@link SafetyCenterStaticEntry} content. This comes
+ * with the restriction that two separate {@link SafetyCenterStaticEntry} returned by Safety
+ * Center cannot be equal, as they would otherwise collide in the {@link Bundle}.
+ */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static String toBundleKey(SafetyCenterStaticEntry safetyCenterStaticEntry) {
+ SafetyCenterStaticEntryBundleKey.Builder keyBuilder =
+ SafetyCenterStaticEntryBundleKey.newBuilder()
+ .setTitle(safetyCenterStaticEntry.getTitle().toString());
+ CharSequence summary = safetyCenterStaticEntry.getSummary();
+ if (summary != null) {
+ keyBuilder.setSummary(summary.toString());
+ }
+ return SafetyCenterIds.encodeToString(keyBuilder.build());
+ }
+}
diff --git a/SafetyCenter/InternalData/java/com/android/safetycenter/internaldata/SafetyCenterIds.java b/SafetyCenter/InternalData/java/com/android/safetycenter/internaldata/SafetyCenterIds.java
new file mode 100644
index 000000000..ff737c66c
--- /dev/null
+++ b/SafetyCenter/InternalData/java/com/android/safetycenter/internaldata/SafetyCenterIds.java
@@ -0,0 +1,139 @@
+/*
+ * 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.internaldata;
+
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import android.util.Base64;
+
+import androidx.annotation.RequiresApi;
+
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.MessageLite;
+import com.google.protobuf.Parser;
+
+/** A class to facilitate working with Safety Center IDs. */
+@RequiresApi(TIRAMISU)
+public final class SafetyCenterIds {
+
+ private static final int ENCODING_FLAGS = Base64.NO_WRAP | Base64.URL_SAFE;
+
+ private SafetyCenterIds() {}
+
+ /**
+ * Converts a String to a {@link SafetyCenterEntryId}.
+ *
+ * <p>Throws an {@link IllegalArgumentException} if the String couldn't be converted to a {@link
+ * SafetyCenterEntryId}.
+ */
+ public static SafetyCenterEntryId entryIdFromString(String encoded) {
+ return decodeToProto(SafetyCenterEntryId.parser(), encoded);
+ }
+
+ /**
+ * Converts a String to a {@link SafetyCenterIssueId}.
+ *
+ * <p>Throws an {@link IllegalArgumentException} if the String couldn't be converted to a {@link
+ * SafetyCenterIssueId}.
+ */
+ public static SafetyCenterIssueId issueIdFromString(String encoded) {
+ return decodeToProto(SafetyCenterIssueId.parser(), encoded);
+ }
+
+ /**
+ * Converts a String to a {@link SafetyCenterIssueKey}.
+ *
+ * <p>Throws an {@link IllegalArgumentException} if the String couldn't be converted to a {@link
+ * SafetyCenterIssueKey}.
+ */
+ public static SafetyCenterIssueKey issueKeyFromString(String encoded) {
+ return decodeToProto(SafetyCenterIssueKey.parser(), encoded);
+ }
+
+ /**
+ * Converts a String to a {@link SafetyCenterIssueActionId}.
+ *
+ * <p>Throws an {@link IllegalArgumentException} if the String couldn't be converted to a {@link
+ * SafetyCenterIssueActionId}.
+ */
+ public static SafetyCenterIssueActionId issueActionIdFromString(String encoded) {
+ return decodeToProto(SafetyCenterIssueActionId.parser(), encoded);
+ }
+
+ /** Encodes a Safety Center id to a String. */
+ public static String encodeToString(MessageLite message) {
+ return Base64.encodeToString(message.toByteArray(), ENCODING_FLAGS);
+ }
+
+ /**
+ * Converts a {@link SafetyCenterIssueKey} to a readable string.
+ *
+ * <p>This is necessary as the implementation of {@link #toString()} for Java lite protos is
+ * optimized in production builds and does not return a user-readable output.
+ */
+ public static String toUserFriendlyString(SafetyCenterIssueKey safetyCenterIssueKey) {
+ return "SafetyCenterIssueKey{safetySourceId='"
+ + safetyCenterIssueKey.getSafetySourceId()
+ + "', safetySourceIssueId='"
+ + safetyCenterIssueKey.getSafetySourceIssueId()
+ + "', userId="
+ + safetyCenterIssueKey.getUserId()
+ + "}";
+ }
+
+ /**
+ * Converts a {@link SafetyCenterIssueId} to a readable string.
+ *
+ * <p>This is necessary as the implementation of {@link #toString()} for Java lite protos is
+ * optimized in production builds and does not return a user-readable output.
+ */
+ public static String toUserFriendlyString(SafetyCenterIssueId safetyCenterIssueId) {
+ return "SafetyCenterIssueId{safetyCenterIssueKey="
+ + toUserFriendlyString(safetyCenterIssueId.getSafetyCenterIssueKey())
+ + ", issueTypeId='"
+ + safetyCenterIssueId.getIssueTypeId()
+ + "', taskId="
+ + safetyCenterIssueId.getTaskId()
+ + "}";
+ }
+
+ /**
+ * Converts a {@link SafetyCenterIssueActionId} to a readable string.
+ *
+ * <p>This is necessary as the implementation of {@link #toString()} for Java lite protos is
+ * optimized in production builds and does not return a user-readable output.
+ */
+ public static String toUserFriendlyString(SafetyCenterIssueActionId safetyCenterIssueActionId) {
+ return "SafetyCenterIssueActionId{safetyCenterIssueKey="
+ + toUserFriendlyString(safetyCenterIssueActionId.getSafetyCenterIssueKey())
+ + ", safetySourceIssueActionId='"
+ + safetyCenterIssueActionId.getSafetySourceIssueActionId()
+ + "'}";
+ }
+
+ private static <T extends MessageLite> T decodeToProto(Parser<T> parser, String encoded) {
+ try {
+ return parser.parseFrom(Base64.decode(encoded, ENCODING_FLAGS));
+ } catch (InvalidProtocolBufferException e) {
+ throw new IllegalArgumentException(
+ "Invalid ID: "
+ + encoded
+ + " couldn't be parsed with "
+ + parser.getClass().getSimpleName());
+ }
+ }
+}
diff --git a/SafetyCenter/InternalData/java/com/android/safetycenter/internaldata/package-info.java b/SafetyCenter/InternalData/java/com/android/safetycenter/internaldata/package-info.java
new file mode 100644
index 000000000..cb88422ab
--- /dev/null
+++ b/SafetyCenter/InternalData/java/com/android/safetycenter/internaldata/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@NonNullByDefault
+package com.android.safetycenter.internaldata;
+
+import com.android.safetycenter.annotations.NonNullByDefault;
diff --git a/SafetyCenter/InternalData/proto/safety_center_internal_data.proto b/SafetyCenter/InternalData/proto/safety_center_internal_data.proto
new file mode 100644
index 000000000..f38127136
--- /dev/null
+++ b/SafetyCenter/InternalData/proto/safety_center_internal_data.proto
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package com.android.safetycenter.internaldata;
+
+option java_multiple_files = true;
+
+// An id for entries provided by the Safety Center.
+message SafetyCenterEntryId {
+ // The ID of the safety source that the entry originated from.
+ optional string safety_source_id = 1;
+ // The user ID associated with this entry.
+ optional int32 user_id = 2;
+}
+
+// An id for issues provided by the Safety Center.
+message SafetyCenterIssueId {
+ reserved 1, 2, 3;
+ // Key that has a 1 to 1 mapping with a safety source issue.
+ optional SafetyCenterIssueKey safety_center_issue_key = 4;
+ // The ID of the type of the safety source issue.
+ optional string issue_type_id = 5;
+ // A task ID to launch the issue's actions in, if applicable.
+ optional int32 task_id = 6;
+}
+
+// Key that has a 1 to 1 mapping with a safety source issue.
+message SafetyCenterIssueKey {
+ // The ID of the safety source that the issue originated from.
+ optional string safety_source_id = 1;
+ // The ID of the safety source issue that the issue originated from.
+ optional string safety_source_issue_id = 2;
+ // The user ID associated with this issue.
+ optional int32 user_id = 3;
+}
+
+// An id for issue actions provided by the Safety Center.
+message SafetyCenterIssueActionId {
+ reserved 1;
+ // The ID of the safety source issue action that the action originated from.
+ optional string safety_source_issue_action_id = 2;
+ // `SafetyCenterIssueKey` associated with this action.
+ optional SafetyCenterIssueKey safety_center_issue_key = 3;
+}
+
+// A bundle key for static entries provided by the Safety Center.
+message SafetyCenterStaticEntryBundleKey {
+ // The title of the SafetyCenterStaticEntry.
+ optional string title = 1;
+ // The summary of the SafetyCenterStaticEntry.
+ optional string summary = 2;
+}
diff --git a/SafetyCenter/OWNERS b/SafetyCenter/OWNERS
index eb1be6327..d9039e915 100644
--- a/SafetyCenter/OWNERS
+++ b/SafetyCenter/OWNERS
@@ -1,5 +1,12 @@
# Bug component: 1026964
+simonjw@google.com
davidcoffin@google.com
elliotsisteron@google.com
-kvakil@google.com
+fiscella@google.com
+shrigupt@google.com
+jtomljanovic@google.com
+deweytyl@google.com
+maxspencer@google.com
+prabalsingh@google.com
+yufimtsev@google.com
diff --git a/SafetyCenter/PendingIntents/Android.bp b/SafetyCenter/PendingIntents/Android.bp
new file mode 100644
index 000000000..05bec7988
--- /dev/null
+++ b/SafetyCenter/PendingIntents/Android.bp
@@ -0,0 +1,42 @@
+//
+// 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: "safety-center-pending-intents",
+ srcs: [
+ "java/**/*.java",
+ ],
+ libs: [
+ "androidx.annotation_annotation",
+ "safety-center-annotations",
+ ],
+ static_libs: [
+ "modules-utils-build_system",
+ ],
+ apex_available: [
+ "com.android.permission",
+ "test_com.android.permission",
+ ],
+ installable: false,
+ sdk_version: "system_current",
+ min_sdk_version: "30",
+ visibility: [
+ "//packages/modules/Permission:__subpackages__",
+ ],
+}
diff --git a/SafetyCenter/PendingIntents/java/com/android/safetycenter/pendingintents/PendingIntentSender.java b/SafetyCenter/PendingIntents/java/com/android/safetycenter/pendingintents/PendingIntentSender.java
new file mode 100644
index 000000000..9564f56eb
--- /dev/null
+++ b/SafetyCenter/PendingIntents/java/com/android/safetycenter/pendingintents/PendingIntentSender.java
@@ -0,0 +1,134 @@
+/*
+ * 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.pendingintents;
+
+import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+
+import android.app.ActivityOptions;
+import android.app.PendingIntent;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RequiresPermission;
+
+import com.android.modules.utils.build.SdkLevel;
+
+/** A class to facilitate sending {@link PendingIntent}s associated with Safety Center. */
+@RequiresApi(TIRAMISU)
+public final class PendingIntentSender {
+
+ private PendingIntentSender() {}
+
+ private static final String TAG = "PendingIntentSender";
+
+ /**
+ * Sends a {@link PendingIntent}.
+ *
+ * <p>On U+, launching activities in the background is opt-in by using {@link
+ * ActivityOptions#MODE_BACKGROUND_ACTIVITY_START_ALLOWED}. This call opts-in this behavior as
+ * the Safety Center intents come from trusted sources and are used for navigation purposes.
+ */
+ public static void send(PendingIntent pendingIntent) throws PendingIntent.CanceledException {
+ send(pendingIntent, createActivityOptions(pendingIntent, /* launchTaskId= */ null));
+ }
+
+ /** Same as {@link #send(PendingIntent)} but with the given optional {@code launchTaskId}. */
+ @RequiresPermission(START_TASKS_FROM_RECENTS)
+ public static void send(PendingIntent pendingIntent, @Nullable Integer launchTaskId)
+ throws PendingIntent.CanceledException {
+ send(pendingIntent, createActivityOptions(pendingIntent, launchTaskId));
+ }
+
+ private static void send(PendingIntent pendingIntent, @Nullable ActivityOptions activityOptions)
+ throws PendingIntent.CanceledException {
+ if (activityOptions == null) {
+ pendingIntent.send();
+ return;
+ }
+ pendingIntent.send(
+ /* context= */ null,
+ /* code= */ 0,
+ /* intent= */ null,
+ /* onFinished= */ null,
+ /* handler= */ null,
+ /* requiredPermission= */ null,
+ activityOptions.toBundle());
+ }
+
+ /**
+ * Same as {@link #send(PendingIntent)} but returns whether the call was successful instead of
+ * throwing a {@link PendingIntent#CanceledException}.
+ */
+ public static boolean trySend(PendingIntent pendingIntent) {
+ return trySend(
+ pendingIntent, createActivityOptions(pendingIntent, /* launchTaskId= */ null));
+ }
+
+ /**
+ * Same as {@link #send(PendingIntent, Integer)} but returns whether the call was successful
+ * instead of throwing a {@link PendingIntent#CanceledException}.
+ */
+ @RequiresPermission(START_TASKS_FROM_RECENTS)
+ public static boolean trySend(PendingIntent pendingIntent, @Nullable Integer launchTaskId) {
+ return trySend(pendingIntent, createActivityOptions(pendingIntent, launchTaskId));
+ }
+
+ private static boolean trySend(
+ PendingIntent pendingIntent, @Nullable ActivityOptions activityOptions) {
+ try {
+ send(pendingIntent, activityOptions);
+ return true;
+ } catch (PendingIntent.CanceledException ex) {
+ Log.e(
+ TAG,
+ "Couldn't send PendingIntent: "
+ + pendingIntent
+ + " with ActivityOptions:"
+ + activityOptions,
+ ex);
+ return false;
+ }
+ }
+
+ @Nullable
+ private static ActivityOptions createActivityOptions(
+ PendingIntent pendingIntent, @Nullable Integer launchTaskId) {
+ if (!pendingIntent.isActivity()) {
+ return null;
+ }
+ if (launchTaskId == null && !SdkLevel.isAtLeastU()) {
+ return null;
+ }
+ ActivityOptions activityOptions = ActivityOptions.makeBasic();
+ if (launchTaskId != null) {
+ activityOptions.setLaunchTaskId(launchTaskId);
+ }
+ if (SdkLevel.isAtLeastU()) {
+ setBackgroundActivityStartModeAllowed(activityOptions);
+ }
+ return activityOptions;
+ }
+
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ private static void setBackgroundActivityStartModeAllowed(ActivityOptions activityOptions) {
+ activityOptions.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ }
+}
diff --git a/SafetyCenter/PendingIntents/java/com/android/safetycenter/pendingintents/package-info.java b/SafetyCenter/PendingIntents/java/com/android/safetycenter/pendingintents/package-info.java
new file mode 100644
index 000000000..3d884f9e1
--- /dev/null
+++ b/SafetyCenter/PendingIntents/java/com/android/safetycenter/pendingintents/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@NonNullByDefault
+package com.android.safetycenter.pendingintents;
+
+import com.android.safetycenter.annotations.NonNullByDefault;
diff --git a/SafetyCenter/Persistence/Android.bp b/SafetyCenter/Persistence/Android.bp
new file mode 100644
index 000000000..56ce4491b
--- /dev/null
+++ b/SafetyCenter/Persistence/Android.bp
@@ -0,0 +1,36 @@
+//
+// 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"],
+}
+
+java_library {
+ name: "safety-center-persistence",
+ sdk_version: "system_current",
+ min_sdk_version: "30",
+ srcs: [
+ "java/**/*.java",
+ ],
+ libs: [
+ "androidx.annotation_annotation",
+ "safety-center-annotations",
+ ],
+ apex_available: [
+ "com.android.permission",
+ "test_com.android.permission",
+ ],
+ installable: false,
+}
diff --git a/SafetyCenter/Persistence/TEST_MAPPING b/SafetyCenter/Persistence/TEST_MAPPING
new file mode 100644
index 000000000..868c53157
--- /dev/null
+++ b/SafetyCenter/Persistence/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "SafetyCenterPersistenceTests"
+ }
+ ]
+}
diff --git a/SafetyCenter/Persistence/java/com/android/safetycenter/persistence/PersistedSafetyCenterIssue.java b/SafetyCenter/Persistence/java/com/android/safetycenter/persistence/PersistedSafetyCenterIssue.java
new file mode 100644
index 000000000..1eabf6c8b
--- /dev/null
+++ b/SafetyCenter/Persistence/java/com/android/safetycenter/persistence/PersistedSafetyCenterIssue.java
@@ -0,0 +1,188 @@
+/*
+ * 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.persistence;
+
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+
+import java.time.Instant;
+import java.util.Objects;
+
+/**
+ * Data class containing all the identifiers and metadata of a safety source issue that should be
+ * persisted.
+ */
+@RequiresApi(TIRAMISU)
+public final class PersistedSafetyCenterIssue {
+ private final String mKey;
+ private final Instant mFirstSeenAt;
+ @Nullable private final Instant mDismissedAt;
+ private final int mDismissCount;
+ @Nullable private final Instant mNotificationDismissedAt;
+
+ private PersistedSafetyCenterIssue(
+ String key,
+ Instant firstSeenAt,
+ @Nullable Instant dismissedAt,
+ int dismissCount,
+ @Nullable Instant notificationDismissedAt) {
+ mKey = key;
+ mFirstSeenAt = firstSeenAt;
+ mDismissedAt = dismissedAt;
+ mDismissCount = dismissCount;
+ mNotificationDismissedAt = notificationDismissedAt;
+ }
+
+ /** The unique key for a safety source issue. */
+ public String getKey() {
+ return mKey;
+ }
+
+ /** The instant when this issue was first seen. */
+ public Instant getFirstSeenAt() {
+ return mFirstSeenAt;
+ }
+
+ /** The instant when this issue was dismissed, {@code null} if the issue is not dismissed. */
+ @Nullable
+ public Instant getDismissedAt() {
+ return mDismissedAt;
+ }
+
+ /** The number of times this issue was dismissed. */
+ public int getDismissCount() {
+ return mDismissCount;
+ }
+
+ /**
+ * The instant when the notification for this issue was dismissed, {@code null} if the issue's
+ * notification is not dismissed.
+ */
+ @Nullable
+ public Instant getNotificationDismissedAt() {
+ return mNotificationDismissedAt;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof PersistedSafetyCenterIssue)) return false;
+ PersistedSafetyCenterIssue that = (PersistedSafetyCenterIssue) o;
+ return Objects.equals(mKey, that.mKey)
+ && Objects.equals(mFirstSeenAt, that.mFirstSeenAt)
+ && Objects.equals(mDismissedAt, that.mDismissedAt)
+ && mDismissCount == that.mDismissCount
+ && Objects.equals(mNotificationDismissedAt, that.mNotificationDismissedAt);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mKey, mFirstSeenAt, mDismissedAt, mDismissCount, mNotificationDismissedAt);
+ }
+
+ @Override
+ public String toString() {
+ return "PersistedSafetyCenterIssue{"
+ + "mKey="
+ + mKey
+ + ", mFirstSeenAt="
+ + mFirstSeenAt
+ + ", mDismissedAt="
+ + mDismissedAt
+ + ", mDismissCount="
+ + mDismissCount
+ + ", mNotificationDismissedAt="
+ + mNotificationDismissedAt
+ + '}';
+ }
+
+ /** Builder class for {@link PersistedSafetyCenterIssue}. */
+ public static final class Builder {
+ @Nullable private String mKey;
+ @Nullable private Instant mFirstSeenAt;
+ @Nullable private Instant mDismissedAt;
+ private int mDismissCount = 0;
+ @Nullable private Instant mNotificationDismissedAt;
+
+ /** Creates a {@link Builder} for a {@link PersistedSafetyCenterIssue}. */
+ public Builder() {}
+
+ /** The unique key for a safety source issue. */
+ public Builder setKey(@Nullable String key) {
+ mKey = key;
+ return this;
+ }
+
+ /** The instant when this issue was first seen. */
+ public Builder setFirstSeenAt(@Nullable Instant firstSeenAt) {
+ mFirstSeenAt = firstSeenAt;
+ return this;
+ }
+
+ /** The instant when this issue was dismissed. */
+ public Builder setDismissedAt(@Nullable Instant dismissedAt) {
+ mDismissedAt = dismissedAt;
+ return this;
+ }
+
+ /** The number of times this issue was dismissed. */
+ public Builder setDismissCount(int dismissCount) {
+ if (dismissCount < 0) {
+ throw new IllegalArgumentException("Dismiss count cannot be negative");
+ }
+ mDismissCount = dismissCount;
+ return this;
+ }
+
+ /** The instant when this issue's notification was dismissed. */
+ public Builder setNotificationDismissedAt(@Nullable Instant notificationDismissedAt) {
+ mNotificationDismissedAt = notificationDismissedAt;
+ return this;
+ }
+
+ /**
+ * Creates the {@link PersistedSafetyCenterIssue} defined by this {@link Builder}.
+ *
+ * <p>Throws an {@link IllegalStateException} if any constraint is violated.
+ */
+ public PersistedSafetyCenterIssue build() {
+ validateRequiredAttribute(mKey, "key");
+ validateRequiredAttribute(mFirstSeenAt, "firstSeenAt");
+
+ if (mDismissedAt != null && mDismissCount == 0) {
+ throw new IllegalStateException(
+ "dismissCount cannot be 0 if dismissedAt is present");
+ }
+ if (mDismissCount > 0 && mDismissedAt == null) {
+ throw new IllegalStateException(
+ "dismissedAt must be present if dismissCount is greater than 0");
+ }
+
+ return new PersistedSafetyCenterIssue(
+ mKey, mFirstSeenAt, mDismissedAt, mDismissCount, mNotificationDismissedAt);
+ }
+ }
+
+ private static void validateRequiredAttribute(@Nullable Object attribute, String name) {
+ if (attribute == null) {
+ throw new IllegalStateException("Required attribute " + name + " missing");
+ }
+ }
+}
diff --git a/SafetyCenter/Persistence/java/com/android/safetycenter/persistence/PersistenceException.java b/SafetyCenter/Persistence/java/com/android/safetycenter/persistence/PersistenceException.java
new file mode 100644
index 000000000..144aa160d
--- /dev/null
+++ b/SafetyCenter/Persistence/java/com/android/safetycenter/persistence/PersistenceException.java
@@ -0,0 +1,34 @@
+/*
+ * 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.persistence;
+
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import androidx.annotation.RequiresApi;
+
+/** Exception thrown when there is an error accessing persistent data. */
+@RequiresApi(TIRAMISU)
+public final class PersistenceException extends Exception {
+
+ public PersistenceException(String message) {
+ super(message);
+ }
+
+ public PersistenceException(String message, Throwable ex) {
+ super(message, ex);
+ }
+}
diff --git a/SafetyCenter/Persistence/java/com/android/safetycenter/persistence/SafetyCenterIssuesPersistence.java b/SafetyCenter/Persistence/java/com/android/safetycenter/persistence/SafetyCenterIssuesPersistence.java
new file mode 100644
index 000000000..40450e178
--- /dev/null
+++ b/SafetyCenter/Persistence/java/com/android/safetycenter/persistence/SafetyCenterIssuesPersistence.java
@@ -0,0 +1,307 @@
+/*
+ * 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.persistence;
+
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.END_TAG;
+import static org.xmlpull.v1.XmlPullParser.FEATURE_PROCESS_NAMESPACES;
+import static org.xmlpull.v1.XmlPullParser.START_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+import static org.xmlpull.v1.XmlPullParser.TEXT;
+
+import static java.util.Collections.unmodifiableList;
+
+import android.util.AtomicFile;
+import android.util.Log;
+import android.util.Xml;
+
+import androidx.annotation.RequiresApi;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+
+/** Utility class to persist identifiers and metadata of safety source issues related to a user. */
+@RequiresApi(TIRAMISU)
+public final class SafetyCenterIssuesPersistence {
+
+ private static final String TAG = "SafetyCenterIssuesPersi";
+
+ private static final String TAG_ISSUES = "issues";
+ private static final String TAG_ISSUE = "issue";
+
+ private static final String ATTRIBUTE_VERSION = "version";
+ private static final String ATTRIBUTE_KEY = "key";
+ private static final String ATTRIBUTE_FIRST_SEEN_AT = "first_seen_at_epoch_millis";
+ private static final String ATTRIBUTE_DISMISSED_AT = "dismissed_at_epoch_millis";
+ private static final String ATTRIBUTE_DISMISS_COUNT = "dismiss_count";
+ private static final String ATTRIBUTE_NOTIFICATION_DISMISSED_AT =
+ "notification_dismissed_at_epoch_millis";
+
+ private static final int NO_VERSION = -1;
+ private static final int CURRENT_VERSION = 2;
+ private static final int MIN_COMPATIBLE_VERSION = 0;
+
+ private SafetyCenterIssuesPersistence() {}
+
+ /**
+ * Read the issues state from persistence.
+ *
+ * <p>This will perform I/O operations synchronously.
+ *
+ * @param file the file to read from
+ * @return the list of issue states read or an empty list if the file does not exist
+ * @throws PersistenceException if there is an unexpected error while reading the file
+ */
+ public static List<PersistedSafetyCenterIssue> read(File file) throws PersistenceException {
+ XmlPullParser parser = Xml.newPullParser();
+ try (FileInputStream inputStream = new AtomicFile(file).openRead()) {
+ parser.setFeature(FEATURE_PROCESS_NAMESPACES, true);
+ parser.setInput(inputStream, null);
+ return unmodifiableList(parseXml(parser));
+ } catch (FileNotFoundException e) {
+ Log.i(TAG, "File not found: " + file);
+ return unmodifiableList(new ArrayList<>());
+ } catch (IOException | XmlPullParserException e) {
+ throw new PersistenceException("Failed to read file: " + file, e);
+ }
+ }
+
+ private static List<PersistedSafetyCenterIssue> parseXml(XmlPullParser parser)
+ throws IOException, PersistenceException, XmlPullParserException {
+ if (parser.getEventType() != START_DOCUMENT) {
+ throw new PersistenceException("Unexpected parser state");
+ }
+ parser.nextTag();
+ validateElementStart(parser, TAG_ISSUES);
+ List<PersistedSafetyCenterIssue> persistedSafetyCenterIssues = parseIssues(parser);
+ while (parser.getEventType() == TEXT && parser.isWhitespace()) {
+ parser.next();
+ }
+ if (parser.getEventType() != END_DOCUMENT) {
+ throw new PersistenceException("Unexpected extra root element");
+ }
+ return persistedSafetyCenterIssues;
+ }
+
+ private static List<PersistedSafetyCenterIssue> parseIssues(XmlPullParser parser)
+ throws IOException, PersistenceException, XmlPullParserException {
+ int version = NO_VERSION;
+ for (int i = 0; i < parser.getAttributeCount(); i++) {
+ switch (parser.getAttributeName(i)) {
+ case ATTRIBUTE_VERSION:
+ version = parseInteger(parser.getAttributeValue(i), parser.getAttributeName(i));
+ break;
+ default:
+ throw attributeUnexpected(parser.getAttributeName(i));
+ }
+ }
+ if (version == NO_VERSION) {
+ throw new PersistenceException("Missing version");
+ }
+ if (version > CURRENT_VERSION || version < MIN_COMPATIBLE_VERSION) {
+ throw new PersistenceException("Unsupported version: " + version);
+ }
+
+ List<PersistedSafetyCenterIssue> persistedSafetyCenterIssues = new ArrayList<>();
+ parser.nextTag();
+ while (parser.getEventType() == START_TAG && parser.getName().equals(TAG_ISSUE)) {
+ persistedSafetyCenterIssues.add(parseIssue(parser));
+ }
+ validateElementEnd(parser, TAG_ISSUES);
+ parser.next();
+ return persistedSafetyCenterIssues;
+ }
+
+ private static PersistedSafetyCenterIssue parseIssue(XmlPullParser parser)
+ throws IOException, PersistenceException, XmlPullParserException {
+ boolean hasDismissedAt = false;
+ boolean hasDismissCount = false;
+ PersistedSafetyCenterIssue.Builder builder = new PersistedSafetyCenterIssue.Builder();
+ for (int i = 0; i < parser.getAttributeCount(); i++) {
+ switch (parser.getAttributeName(i)) {
+ case ATTRIBUTE_KEY:
+ builder.setKey(parser.getAttributeValue(i));
+ break;
+ case ATTRIBUTE_FIRST_SEEN_AT:
+ builder.setFirstSeenAt(
+ parseInstant(parser.getAttributeValue(i), parser.getAttributeName(i)));
+ break;
+ case ATTRIBUTE_DISMISSED_AT:
+ hasDismissedAt = true;
+ builder.setDismissedAt(
+ parseInstant(parser.getAttributeValue(i), parser.getAttributeName(i)));
+ break;
+ case ATTRIBUTE_DISMISS_COUNT:
+ hasDismissCount = true;
+ try {
+ builder.setDismissCount(
+ parseInteger(
+ parser.getAttributeValue(i), parser.getAttributeName(i)));
+ } catch (IllegalArgumentException e) {
+ throw attributeInvalid(
+ parser.getAttributeValue(i), parser.getAttributeName(i), e);
+ }
+ break;
+ case ATTRIBUTE_NOTIFICATION_DISMISSED_AT:
+ builder.setNotificationDismissedAt(
+ parseInstant(parser.getAttributeValue(i), parser.getAttributeName(i)));
+ break;
+ default:
+ throw attributeUnexpected(parser.getAttributeName(i));
+ }
+ }
+ if (hasDismissedAt && !hasDismissCount) {
+ builder.setDismissCount(1);
+ }
+ parser.nextTag();
+ validateElementEnd(parser, TAG_ISSUE);
+ parser.nextTag();
+ try {
+ return builder.build();
+ } catch (IllegalStateException e) {
+ throw new PersistenceException("Element issue invalid", e);
+ }
+ }
+
+ private static void validateElementStart(XmlPullParser parser, String name)
+ throws PersistenceException, XmlPullParserException {
+ if (parser.getEventType() != START_TAG || !parser.getName().equals(name)) {
+ throw new PersistenceException(String.format("Element %s missing", name));
+ }
+ }
+
+ private static void validateElementEnd(XmlPullParser parser, String name)
+ throws PersistenceException, XmlPullParserException {
+ if (parser.getEventType() != END_TAG || !parser.getName().equals(name)) {
+ throw new PersistenceException(String.format("Element %s not closed", name));
+ }
+ }
+
+ private static int parseInteger(String value, String name) throws PersistenceException {
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw attributeInvalid(value, name, e);
+ }
+ }
+
+ private static Instant parseInstant(String value, String name) throws PersistenceException {
+ try {
+ return Instant.ofEpochMilli(Long.parseLong(value));
+ } catch (DateTimeException | NumberFormatException e) {
+ throw attributeInvalid(value, name, e);
+ }
+ }
+
+ private static PersistenceException attributeUnexpected(String name) {
+ return new PersistenceException("Unexpected attribute " + name);
+ }
+
+ private static PersistenceException attributeInvalid(String value, String name, Throwable ex) {
+ return new PersistenceException(
+ "Attribute value \"" + value + "\" for " + name + " invalid", ex);
+ }
+
+ /**
+ * Write the issues state to persistence.
+ *
+ * <p>This will perform I/O operations synchronously.
+ *
+ * @param persistedSafetyCenterIssues the issue states to write
+ * @param file the file to write to
+ */
+ public static void write(
+ List<PersistedSafetyCenterIssue> persistedSafetyCenterIssues, File file) {
+ AtomicFile atomicFile = new AtomicFile(file);
+ FileOutputStream outputStream = null;
+ try {
+ outputStream = atomicFile.startWrite();
+
+ XmlSerializer serializer = Xml.newSerializer();
+ serializer.setOutput(outputStream, StandardCharsets.UTF_8.name());
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ serializer.startDocument(null, true);
+
+ serializeIssues(serializer, persistedSafetyCenterIssues);
+
+ serializer.endDocument();
+ atomicFile.finishWrite(outputStream);
+ } catch (Exception e) {
+ Log.wtf(TAG, "Failed to write, restoring backup: " + file, e);
+ atomicFile.failWrite(outputStream);
+ } finally {
+ try {
+ outputStream.close();
+ } catch (Exception ignored) {
+ // Ignored.
+ }
+ }
+ }
+
+ private static void serializeIssues(
+ XmlSerializer serializer, List<PersistedSafetyCenterIssue> persistedSafetyCenterIssues)
+ throws IOException {
+ serializer.startTag(null, TAG_ISSUES);
+ serializer.attribute(null, ATTRIBUTE_VERSION, Integer.toString(CURRENT_VERSION));
+
+ for (int i = 0; i < persistedSafetyCenterIssues.size(); i++) {
+ PersistedSafetyCenterIssue persistedSafetyCenterIssue =
+ persistedSafetyCenterIssues.get(i);
+
+ serializer.startTag(null, TAG_ISSUE);
+ serializer.attribute(null, ATTRIBUTE_KEY, persistedSafetyCenterIssue.getKey());
+ serializer.attribute(
+ null,
+ ATTRIBUTE_FIRST_SEEN_AT,
+ Long.toString(persistedSafetyCenterIssue.getFirstSeenAt().toEpochMilli()));
+ Instant dismissedAt = persistedSafetyCenterIssue.getDismissedAt();
+ if (dismissedAt != null) {
+ serializer.attribute(
+ null, ATTRIBUTE_DISMISSED_AT, Long.toString(dismissedAt.toEpochMilli()));
+ }
+ int dismissCount = persistedSafetyCenterIssue.getDismissCount();
+ if (dismissCount > 0) {
+ serializer.attribute(null, ATTRIBUTE_DISMISS_COUNT, Integer.toString(dismissCount));
+ }
+ Instant notificationDismissedAt =
+ persistedSafetyCenterIssue.getNotificationDismissedAt();
+ if (notificationDismissedAt != null) {
+ serializer.attribute(
+ null,
+ ATTRIBUTE_NOTIFICATION_DISMISSED_AT,
+ Long.toString(notificationDismissedAt.toEpochMilli()));
+ }
+ serializer.endTag(null, TAG_ISSUE);
+ }
+
+ serializer.endTag(null, TAG_ISSUES);
+ }
+}
diff --git a/SafetyCenter/Persistence/java/com/android/safetycenter/persistence/package-info.java b/SafetyCenter/Persistence/java/com/android/safetycenter/persistence/package-info.java
new file mode 100644
index 000000000..958a8b287
--- /dev/null
+++ b/SafetyCenter/Persistence/java/com/android/safetycenter/persistence/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@NonNullByDefault
+package com.android.safetycenter.persistence;
+
+import com.android.safetycenter.annotations.NonNullByDefault;
diff --git a/SafetyCenter/Persistence/tests/Android.bp b/SafetyCenter/Persistence/tests/Android.bp
new file mode 100644
index 000000000..d72dfdd29
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/Android.bp
@@ -0,0 +1,36 @@
+// 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: "SafetyCenterPersistenceTests",
+ defaults: ["mts-target-sdk-version-current"],
+ sdk_version: "test_current",
+ min_sdk_version: "30",
+ srcs: ["java/**/*.kt"],
+ data: ["data/*"],
+ static_libs: [
+ "compatibility-device-util-axt",
+ "kotlinx-coroutines-android",
+ "safety-center-persistence",
+ "safety-center-test-util-lib",
+ ],
+ test_suites: [
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/SafetyCenter/Persistence/tests/AndroidManifest.xml b/SafetyCenter/Persistence/tests/AndroidManifest.xml
new file mode 100644
index 000000000..a685e7248
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/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="com.android.safetycenter.persistence.tests">
+
+ <application android:label="Safety Center Persistence Tests">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.safetycenter.persistence.tests"
+ android:label="Tests for the Safety Center Persistence library" />
+</manifest>
diff --git a/SafetyCenter/Persistence/tests/AndroidTest.xml b/SafetyCenter/Persistence/tests/AndroidTest.xml
new file mode 100644
index 000000000..0cf30daac
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/AndroidTest.xml
@@ -0,0 +1,86 @@
+<?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="Runs unit tests for the Safety Center Peristence library.">
+ <option name="test-tag" value="SafetyCenterPersistenceTests" />
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk33ModuleController" />
+
+ <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
+
+ <!-- Install test -->
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="test-file-name" value="SafetyCenterPersistenceTests.apk" />
+ <option name="cleanup-apks" 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/com/safetycenter/persistence/tests/" />
+ <option name="teardown-command" value="rm -rf /data/local/tmp/com/safetycenter/"/>
+ </target_preparer>
+
+ <!-- Load additional data onto device -->
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="push-file" key="invalid_file_corrupted.txt"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/invalid_file_corrupted.txt" />
+ <option name="push-file" key="invalid_file_extra_attribute.xml"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/invalid_file_extra_attribute.xml" />
+ <option name="push-file" key="invalid_file_extra_element.xml"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/invalid_file_extra_element.xml" />
+ <option name="push-file" key="invalid_file_extra_root.txt"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/invalid_file_extra_root.txt" />
+ <option name="push-file" key="invalid_file_inconsistent_dismiss_count.xml"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/invalid_file_inconsistent_dismiss_count.xml" />
+ <option name="push-file" key="invalid_file_inconsistent_dismissed_at.xml"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/invalid_file_inconsistent_dismissed_at.xml" />
+ <option name="push-file" key="invalid_file_invalid_dismiss_count.xml"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/invalid_file_invalid_dismiss_count.xml" />
+ <option name="push-file" key="invalid_file_invalid_dismissed_at.xml"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/invalid_file_invalid_dismissed_at.xml" />
+ <option name="push-file" key="invalid_file_invalid_first_seen_at.xml"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/invalid_file_invalid_first_seen_at.xml" />
+ <option name="push-file" key="invalid_file_invalid_notification_dismissed_at.xml"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/invalid_file_invalid_notification_dismissed_at.xml" />
+ <option name="push-file" key="invalid_file_invalid_version.xml"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/invalid_file_invalid_version.xml" />
+ <option name="push-file" key="invalid_file_missing_first_seen_at.xml"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/invalid_file_missing_first_seen_at.xml" />
+ <option name="push-file" key="invalid_file_missing_key.xml"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/invalid_file_missing_key.xml" />
+ <option name="push-file" key="invalid_file_missing_version.xml"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/invalid_file_missing_version.xml" />
+ <option name="push-file" key="invalid_file_negative_dismiss_count.xml"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/invalid_file_negative_dismiss_count.xml" />
+ <option name="push-file" key="invalid_file_wrong_root.xml"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/invalid_file_wrong_root.xml" />
+ <option name="push-file" key="invalid_file_wrong_version.xml"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/invalid_file_wrong_version.xml" />
+ <option name="push-file" key="valid_file_v0.xml"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/valid_file_v0.xml" />
+ <option name="push-file" key="valid_file_v1.xml"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/valid_file_v1.xml" />
+ <option name="push-file" key="valid_file_v2.xml"
+ value="/data/local/tmp/com/safetycenter/persistence/tests/valid_file_v2.xml" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.safetycenter.persistence.tests" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="exclude-annotation" value="org.junit.Ignore"/>
+ </test>
+</configuration>
diff --git a/SafetyCenter/Persistence/tests/data/invalid_file_corrupted.txt b/SafetyCenter/Persistence/tests/data/invalid_file_corrupted.txt
new file mode 100644
index 000000000..efc0d6101
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/invalid_file_corrupted.txt
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues version="0">
+ <issue key="key" first_seen_at_epoch_millis="0" />
+</iss
diff --git a/SafetyCenter/Persistence/tests/data/invalid_file_extra_attribute.xml b/SafetyCenter/Persistence/tests/data/invalid_file_extra_attribute.xml
new file mode 100644
index 000000000..03cb4ab0e
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/invalid_file_extra_attribute.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues version="0">
+ <issue key="key" first_seen_at_epoch_millis="1654041600000" dismissed_at_epoch_millis="1654214400000" extra="extra"/>
+</issues>
diff --git a/SafetyCenter/Persistence/tests/data/invalid_file_extra_element.xml b/SafetyCenter/Persistence/tests/data/invalid_file_extra_element.xml
new file mode 100644
index 000000000..b694f6389
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/invalid_file_extra_element.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues version="0">
+ <issue key="key" first_seen_at_epoch_millis="1654041600000" dismissed_at_epoch_millis="1654214400000">
+ <extra/>
+ </issue>
+</issues>
diff --git a/SafetyCenter/Persistence/tests/data/invalid_file_extra_root.txt b/SafetyCenter/Persistence/tests/data/invalid_file_extra_root.txt
new file mode 100644
index 000000000..22db26e23
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/invalid_file_extra_root.txt
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues version="0">
+ <issue key="key" first_seen_at_epoch_millis="1654041600000" dismissed_at_epoch_millis="1654214400000" />
+</issues>
+<issues version="99">
+ <issue key="key" first_seen_at_epoch_millis="0" />
+</issues>
diff --git a/SafetyCenter/Persistence/tests/data/invalid_file_inconsistent_dismiss_count.xml b/SafetyCenter/Persistence/tests/data/invalid_file_inconsistent_dismiss_count.xml
new file mode 100644
index 000000000..58c7193ef
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/invalid_file_inconsistent_dismiss_count.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues version="0">
+ <issue key="key" first_seen_at_epoch_millis="0" dismissed_at_epoch_millis="0" dismiss_count="0" />
+</issues>
diff --git a/SafetyCenter/Persistence/tests/data/invalid_file_inconsistent_dismissed_at.xml b/SafetyCenter/Persistence/tests/data/invalid_file_inconsistent_dismissed_at.xml
new file mode 100644
index 000000000..f0c8a0c52
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/invalid_file_inconsistent_dismissed_at.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues version="0">
+ <issue key="key" first_seen_at_epoch_millis="0" dismiss_count="1" />
+</issues>
diff --git a/SafetyCenter/Persistence/tests/data/invalid_file_invalid_dismiss_count.xml b/SafetyCenter/Persistence/tests/data/invalid_file_invalid_dismiss_count.xml
new file mode 100644
index 000000000..4ee21bb5d
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/invalid_file_invalid_dismiss_count.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues version="0">
+ <issue key="key" first_seen_at_epoch_millis="0" dismiss_count="NaN" />
+</issues>
diff --git a/SafetyCenter/Persistence/tests/data/invalid_file_invalid_dismissed_at.xml b/SafetyCenter/Persistence/tests/data/invalid_file_invalid_dismissed_at.xml
new file mode 100644
index 000000000..5d4365758
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/invalid_file_invalid_dismissed_at.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues version="0">
+ <issue key="key" first_seen_at_epoch_millis="0" dismissed_at_epoch_millis="NaN" />
+</issues>
diff --git a/SafetyCenter/Persistence/tests/data/invalid_file_invalid_first_seen_at.xml b/SafetyCenter/Persistence/tests/data/invalid_file_invalid_first_seen_at.xml
new file mode 100644
index 000000000..507818f19
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/invalid_file_invalid_first_seen_at.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues version="0">
+ <issue key="key" first_seen_at_epoch_millis="NaN" />
+</issues>
diff --git a/SafetyCenter/Persistence/tests/data/invalid_file_invalid_notification_dismissed_at.xml b/SafetyCenter/Persistence/tests/data/invalid_file_invalid_notification_dismissed_at.xml
new file mode 100644
index 000000000..e48d87d11
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/invalid_file_invalid_notification_dismissed_at.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues version="0">
+ <issue key="key" first_seen_at_epoch_millis="1654041600000" notification_dismissed_at_epoch_millis="NaN" />
+</issues>
diff --git a/SafetyCenter/Persistence/tests/data/invalid_file_invalid_version.xml b/SafetyCenter/Persistence/tests/data/invalid_file_invalid_version.xml
new file mode 100644
index 000000000..10c7914a0
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/invalid_file_invalid_version.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues version="NaN">
+ <issue key="key" first_seen_at_epoch_millis="0" />
+</issues>
diff --git a/SafetyCenter/Persistence/tests/data/invalid_file_missing_first_seen_at.xml b/SafetyCenter/Persistence/tests/data/invalid_file_missing_first_seen_at.xml
new file mode 100644
index 000000000..61013533a
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/invalid_file_missing_first_seen_at.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues version="0">
+ <issue key="key" />
+</issues>
diff --git a/SafetyCenter/Persistence/tests/data/invalid_file_missing_key.xml b/SafetyCenter/Persistence/tests/data/invalid_file_missing_key.xml
new file mode 100644
index 000000000..a4e823686
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/invalid_file_missing_key.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues version="0">
+ <issue first_seen_at_epoch_millis="0" />
+</issues>
diff --git a/SafetyCenter/Persistence/tests/data/invalid_file_missing_version.xml b/SafetyCenter/Persistence/tests/data/invalid_file_missing_version.xml
new file mode 100644
index 000000000..8a048ce0d
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/invalid_file_missing_version.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues>
+ <issue key="key" first_seen_at_epoch_millis="0" />
+</issues>
diff --git a/SafetyCenter/Persistence/tests/data/invalid_file_negative_dismiss_count.xml b/SafetyCenter/Persistence/tests/data/invalid_file_negative_dismiss_count.xml
new file mode 100644
index 000000000..491418e96
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/invalid_file_negative_dismiss_count.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues version="0">
+ <issue key="key" first_seen_at_epoch_millis="0" dismiss_count="-1" />
+</issues>
diff --git a/SafetyCenter/Persistence/tests/data/invalid_file_wrong_root.xml b/SafetyCenter/Persistence/tests/data/invalid_file_wrong_root.xml
new file mode 100644
index 000000000..0e93e7a15
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/invalid_file_wrong_root.xml
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<some-other-root/>
diff --git a/SafetyCenter/Persistence/tests/data/invalid_file_wrong_version.xml b/SafetyCenter/Persistence/tests/data/invalid_file_wrong_version.xml
new file mode 100644
index 000000000..5066baba4
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/invalid_file_wrong_version.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues version="99">
+ <issue key="key" first_seen_at_epoch_millis="0" />
+</issues>
diff --git a/SafetyCenter/Persistence/tests/data/valid_file_v0.xml b/SafetyCenter/Persistence/tests/data/valid_file_v0.xml
new file mode 100644
index 000000000..a34517a3a
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/valid_file_v0.xml
@@ -0,0 +1,5 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues version="0">
+ <issue key="key1" first_seen_at_epoch_millis="1654041600000" />
+ <issue key="key2" first_seen_at_epoch_millis="1654128000000" dismissed_at_epoch_millis="1654214400000" />
+</issues>
diff --git a/SafetyCenter/Persistence/tests/data/valid_file_v1.xml b/SafetyCenter/Persistence/tests/data/valid_file_v1.xml
new file mode 100644
index 000000000..e13e7c71f
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/valid_file_v1.xml
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues version="1">
+ <issue key="key0" first_seen_at_epoch_millis="1654041600000" />
+ <issue key="key1" first_seen_at_epoch_millis="1654041600000" dismiss_count="0" />
+ <issue key="key2" first_seen_at_epoch_millis="1654128000000" dismissed_at_epoch_millis="1654214400000" dismiss_count="1" />
+ <issue key="key3" first_seen_at_epoch_millis="1654128000000" dismissed_at_epoch_millis="1654214400000" dismiss_count="10" />
+</issues>
diff --git a/SafetyCenter/Persistence/tests/data/valid_file_v2.xml b/SafetyCenter/Persistence/tests/data/valid_file_v2.xml
new file mode 100644
index 000000000..c2252ebfa
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/data/valid_file_v2.xml
@@ -0,0 +1,9 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<issues version="2">
+ <issue key="key0" first_seen_at_epoch_millis="1654041600000" />
+ <issue key="key1" first_seen_at_epoch_millis="1654041600000" dismiss_count="0" />
+ <issue key="key2" first_seen_at_epoch_millis="1654128000000" dismissed_at_epoch_millis="1654214400000" dismiss_count="1" />
+ <issue key="key3" first_seen_at_epoch_millis="1654128000000" dismissed_at_epoch_millis="1654214400000" dismiss_count="10" />
+ <issue key="key4" first_seen_at_epoch_millis="1654128000000" dismissed_at_epoch_millis="1654214400000" dismiss_count="1" notification_dismissed_at_epoch_millis="1654214400000" />
+ <issue key="key5" first_seen_at_epoch_millis="1654128000000" notification_dismissed_at_epoch_millis="1654214400000" />
+</issues>
diff --git a/SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/PersistedSafetyCenterIssueTest.kt b/SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/PersistedSafetyCenterIssueTest.kt
new file mode 100644
index 000000000..d88100382
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/PersistedSafetyCenterIssueTest.kt
@@ -0,0 +1,126 @@
+/*
+ * 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.persistence
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.safetycenter.testing.EqualsHashCodeToStringTester
+import com.google.common.truth.Truth.assertThat
+import java.time.Instant
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** CTS tests for [PersistedSafetyCenterIssue]. */
+@RunWith(AndroidJUnit4::class)
+class PersistedSafetyCenterIssueTest {
+
+ @Test
+ fun getKey_returnsKey() {
+ assertThat(ACTIVE_ISSUE.key).isEqualTo(ACTIVE_ISSUE_KEY)
+ assertThat(DISMISSED_ISSUE.key).isEqualTo(DISMISSED_ISSUE_KEY)
+ }
+
+ @Test
+ fun getFirstSeenAt_returnsFirstSeenAt() {
+ assertThat(ACTIVE_ISSUE.firstSeenAt).isEqualTo(INSTANT)
+ assertThat(DISMISSED_ISSUE.firstSeenAt).isEqualTo(INSTANT)
+ }
+
+ @Test
+ fun getDismissedAt_returnsDismissedAt() {
+ assertThat(ACTIVE_ISSUE.dismissedAt).isEqualTo(null)
+ assertThat(DISMISSED_ISSUE.dismissedAt).isEqualTo(INSTANT)
+ }
+
+ @Test
+ fun getDismissCount_returnsDismissCount() {
+ assertThat(ACTIVE_ISSUE.dismissCount).isEqualTo(0)
+ assertThat(DISMISSED_ISSUE.dismissCount).isEqualTo(1)
+ }
+
+ @Test
+ fun getNotificationDismissedAt_returnsNotificationDismissedAt() {
+ assertThat(ACTIVE_ISSUE.notificationDismissedAt).isEqualTo(null)
+ assertThat(DISMISSED_ISSUE.notificationDismissedAt).isEqualTo(INSTANT)
+ }
+
+ @Test
+ fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
+ EqualsHashCodeToStringTester.of<PersistedSafetyCenterIssue>()
+ .addEqualityGroup(
+ ACTIVE_ISSUE,
+ PersistedSafetyCenterIssue.Builder()
+ .setKey(ACTIVE_ISSUE_KEY)
+ .setFirstSeenAt(INSTANT)
+ .build()
+ )
+ .addEqualityGroup(DISMISSED_ISSUE)
+ .addEqualityGroup(
+ PersistedSafetyCenterIssue.Builder()
+ .setKey("other")
+ .setFirstSeenAt(INSTANT)
+ .setDismissedAt(INSTANT)
+ .setDismissCount(1)
+ .build()
+ )
+ .addEqualityGroup(
+ PersistedSafetyCenterIssue.Builder()
+ .setKey(DISMISSED_ISSUE_KEY)
+ .setFirstSeenAt(Instant.ofEpochMilli(0))
+ .setDismissedAt(INSTANT)
+ .setDismissCount(1)
+ .build()
+ )
+ .addEqualityGroup(
+ PersistedSafetyCenterIssue.Builder()
+ .setKey(DISMISSED_ISSUE_KEY)
+ .setFirstSeenAt(INSTANT)
+ .setDismissedAt(Instant.ofEpochMilli(0))
+ .setDismissCount(1)
+ .build()
+ )
+ .addEqualityGroup(
+ PersistedSafetyCenterIssue.Builder()
+ .setKey(DISMISSED_ISSUE_KEY)
+ .setFirstSeenAt(INSTANT)
+ .setDismissedAt(INSTANT)
+ .setDismissCount(99)
+ .build()
+ )
+ .test()
+ }
+
+ companion object {
+ private const val ACTIVE_ISSUE_KEY = "active_key"
+ private const val DISMISSED_ISSUE_KEY = "dismissed_key"
+ private val INSTANT = Instant.ofEpochMilli(1654041600000)
+
+ private val ACTIVE_ISSUE =
+ PersistedSafetyCenterIssue.Builder()
+ .setKey(ACTIVE_ISSUE_KEY)
+ .setFirstSeenAt(INSTANT)
+ .build()
+
+ private val DISMISSED_ISSUE =
+ PersistedSafetyCenterIssue.Builder()
+ .setKey(DISMISSED_ISSUE_KEY)
+ .setFirstSeenAt(INSTANT)
+ .setDismissedAt(INSTANT)
+ .setDismissCount(1)
+ .setNotificationDismissedAt(INSTANT)
+ .build()
+ }
+}
diff --git a/SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/PersistenceConstants.kt b/SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/PersistenceConstants.kt
new file mode 100644
index 000000000..0302d0e73
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/PersistenceConstants.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 com.android.safetycenter.persistence
+
+/** A class that provides constants used for persistence testing. */
+object PersistenceConstants {
+ const val PATH = "/data/local/tmp/com/safetycenter/persistence/tests/"
+}
diff --git a/SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/PersistenceExceptionTest.kt b/SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/PersistenceExceptionTest.kt
new file mode 100644
index 000000000..80a193078
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/PersistenceExceptionTest.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.persistence
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** CTS tests for [PersistenceException]. */
+@RunWith(AndroidJUnit4::class)
+class PersistenceExceptionTest {
+
+ @Test
+ fun propagatesMessage() {
+ val message = "error message"
+
+ val exception = PersistenceException(message)
+
+ assertThat(exception).hasMessageThat().isEqualTo(message)
+ assertThat(exception).hasCauseThat().isNull()
+ }
+
+ @Test
+ fun propagatesMessageAndCause() {
+ val message = "error message"
+ val cause = Exception("error message for cause")
+
+ val exception = PersistenceException(message, cause)
+
+ assertThat(exception).hasMessageThat().isEqualTo(message)
+ assertThat(exception).hasCauseThat().isEqualTo(cause)
+ }
+}
diff --git a/SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/SafetyCenterIssuesPersistenceInvalidTest.kt b/SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/SafetyCenterIssuesPersistenceInvalidTest.kt
new file mode 100644
index 000000000..766f38fac
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/SafetyCenterIssuesPersistenceInvalidTest.kt
@@ -0,0 +1,160 @@
+/*
+ * 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.persistence
+
+import com.android.safetycenter.persistence.PersistenceConstants.PATH
+import com.google.common.truth.Truth.assertThat
+import java.io.File
+import org.junit.Assert.assertThrows
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class SafetyCenterIssuesPersistenceInvalidTest {
+
+ data class Params(
+ private val testName: String,
+ val fileName: String,
+ val errorMessage: String,
+ val causeErrorMessage: String?
+ ) {
+ override fun toString() = testName
+ }
+
+ @Parameterized.Parameter lateinit var params: Params
+
+ @Test
+ fun invalidFile_throws() {
+ val file = File(PATH + params.fileName)
+
+ val thrown =
+ assertThrows(PersistenceException::class.java) {
+ SafetyCenterIssuesPersistence.read(file)
+ }
+
+ assertThat(thrown).hasMessageThat().isEqualTo(params.errorMessage)
+ if (params.causeErrorMessage != null) {
+ assertThat(thrown.cause).hasMessageThat().isEqualTo(params.causeErrorMessage)
+ }
+ }
+
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun parameters() =
+ arrayOf(
+ Params(
+ "Corrupted",
+ "invalid_file_corrupted.txt",
+ "Failed to read file: ${PATH}invalid_file_corrupted.txt",
+ null
+ ),
+ Params(
+ "ExtraAttribute",
+ "invalid_file_extra_attribute.xml",
+ "Unexpected attribute extra",
+ null
+ ),
+ Params(
+ "ExtraElement",
+ "invalid_file_extra_element.xml",
+ "Element issue not closed",
+ null
+ ),
+ Params(
+ "ExtraRoot",
+ "invalid_file_extra_root.txt",
+ "Unexpected extra root element",
+ null
+ ),
+ Params(
+ "InconsistentDismissCount",
+ "invalid_file_inconsistent_dismiss_count.xml",
+ "Element issue invalid",
+ "dismissCount cannot be 0 if dismissedAt is present"
+ ),
+ Params(
+ "InconsistentDismissedAt",
+ "invalid_file_inconsistent_dismissed_at.xml",
+ "Element issue invalid",
+ "dismissedAt must be present if dismissCount is greater than 0"
+ ),
+ Params(
+ "InvalidDismissCount",
+ "invalid_file_invalid_dismiss_count.xml",
+ "Attribute value \"NaN\" for dismiss_count invalid",
+ null
+ ),
+ Params(
+ "InvalidDismissedAt",
+ "invalid_file_invalid_dismissed_at.xml",
+ "Attribute value \"NaN\" for dismissed_at_epoch_millis invalid",
+ null
+ ),
+ Params(
+ "InvalidFirstSeenAt",
+ "invalid_file_invalid_first_seen_at.xml",
+ "Attribute value \"NaN\" for first_seen_at_epoch_millis invalid",
+ null
+ ),
+ Params(
+ "InvalidNotificationDismissedAt",
+ "invalid_file_invalid_notification_dismissed_at.xml",
+ "Attribute value \"NaN\" for notification_dismissed_at_epoch_millis invalid",
+ null
+ ),
+ Params(
+ "InvalidVersion",
+ "invalid_file_invalid_version.xml",
+ "Attribute value \"NaN\" for version invalid",
+ null
+ ),
+ Params(
+ "MissingFirstSeenAt",
+ "invalid_file_missing_first_seen_at.xml",
+ "Element issue invalid",
+ "Required attribute firstSeenAt missing"
+ ),
+ Params(
+ "MissingKey",
+ "invalid_file_missing_key.xml",
+ "Element issue invalid",
+ "Required attribute key missing"
+ ),
+ Params(
+ "MissingVersion",
+ "invalid_file_missing_version.xml",
+ "Missing version",
+ null
+ ),
+ Params(
+ "NegativeDismissCount",
+ "invalid_file_negative_dismiss_count.xml",
+ "Attribute value \"-1\" for dismiss_count invalid",
+ null
+ ),
+ Params("WrongRoot", "invalid_file_wrong_root.xml", "Element issues missing", null),
+ Params(
+ "WrongVersion",
+ "invalid_file_wrong_version.xml",
+ "Unsupported version: 99",
+ null
+ )
+ )
+ }
+}
diff --git a/SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/SafetyCenterIssuesPersistenceValidTest.kt b/SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/SafetyCenterIssuesPersistenceValidTest.kt
new file mode 100644
index 000000000..7a3d7e102
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/SafetyCenterIssuesPersistenceValidTest.kt
@@ -0,0 +1,107 @@
+/*
+ * 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.persistence
+
+import com.android.safetycenter.persistence.PersistenceConstants.PATH
+import com.google.common.truth.Truth.assertThat
+import java.io.File
+import java.time.Instant
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class SafetyCenterIssuesPersistenceValidTest {
+ data class Params(
+ private val testName: String,
+ val fileName: String,
+ val expected: List<PersistedSafetyCenterIssue>
+ ) {
+ override fun toString() = testName
+ }
+
+ @Parameterized.Parameter lateinit var params: Params
+
+ @Test
+ fun validFile_matchesExpected() {
+ val file = File(PATH + params.fileName)
+
+ val actual = SafetyCenterIssuesPersistence.read(file)
+
+ assertThat(actual).isEqualTo(params.expected)
+ }
+
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun parameters() =
+ arrayOf(
+ Params("FileNotFound", "file_not_found.xml", emptyList()),
+ Params("ValidV0", "valid_file_v0.xml", listOf(ISSUE_1, ISSUE_2)),
+ Params("ValidV1", "valid_file_v1.xml", listOf(ISSUE_0, ISSUE_1, ISSUE_2, ISSUE_3)),
+ Params(
+ "ValidV2",
+ "valid_file_v2.xml",
+ listOf(ISSUE_0, ISSUE_1, ISSUE_2, ISSUE_3, ISSUE_4, ISSUE_5)
+ )
+ )
+
+ private val ISSUE_0 =
+ PersistedSafetyCenterIssue.Builder()
+ .setKey("key0")
+ .setFirstSeenAt(Instant.ofEpochMilli(1654041600000))
+ .build()
+
+ private val ISSUE_1 =
+ PersistedSafetyCenterIssue.Builder()
+ .setKey("key1")
+ .setFirstSeenAt(Instant.ofEpochMilli(1654041600000))
+ .build()
+
+ private val ISSUE_2 =
+ PersistedSafetyCenterIssue.Builder()
+ .setKey("key2")
+ .setFirstSeenAt(Instant.ofEpochMilli(1654128000000))
+ .setDismissedAt(Instant.ofEpochMilli(1654214400000))
+ .setDismissCount(1)
+ .build()
+
+ private val ISSUE_3 =
+ PersistedSafetyCenterIssue.Builder()
+ .setKey("key3")
+ .setFirstSeenAt(Instant.ofEpochMilli(1654128000000))
+ .setDismissedAt(Instant.ofEpochMilli(1654214400000))
+ .setDismissCount(10)
+ .build()
+
+ private val ISSUE_4 =
+ PersistedSafetyCenterIssue.Builder()
+ .setKey("key4")
+ .setFirstSeenAt(Instant.ofEpochMilli(1654128000000))
+ .setDismissedAt(Instant.ofEpochMilli(1654214400000))
+ .setNotificationDismissedAt(Instant.ofEpochMilli(1654214400000))
+ .setDismissCount(1)
+ .build()
+
+ private val ISSUE_5 =
+ PersistedSafetyCenterIssue.Builder()
+ .setKey("key5")
+ .setFirstSeenAt(Instant.ofEpochMilli(1654128000000))
+ .setNotificationDismissedAt(Instant.ofEpochMilli(1654214400000))
+ .build()
+ }
+}
diff --git a/SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/SafetyCenterIssuesPersistenceWriteTest.kt b/SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/SafetyCenterIssuesPersistenceWriteTest.kt
new file mode 100644
index 000000000..b5c6d238a
--- /dev/null
+++ b/SafetyCenter/Persistence/tests/java/com/android/safetycenter/persistence/SafetyCenterIssuesPersistenceWriteTest.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.safetycenter.persistence
+
+import com.google.common.truth.Truth.assertThat
+import java.io.File
+import java.time.Instant
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class SafetyCenterIssuesPersistenceWriteTest {
+ data class Params(
+ private val testName: String,
+ val fileName: String,
+ val original: List<PersistedSafetyCenterIssue>
+ ) {
+ override fun toString() = testName
+ }
+
+ @Parameterized.Parameter lateinit var params: Params
+
+ @Test
+ fun writeRoundTrip_recreatesEqual() {
+ val file = File.createTempFile(params.fileName, "xml")
+ file.deleteOnExit()
+
+ SafetyCenterIssuesPersistence.write(params.original, file)
+ val read = SafetyCenterIssuesPersistence.read(file)
+
+ assertThat(read).isEqualTo(params.original)
+ }
+
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun parameters() =
+ arrayOf(
+ Params("WithoutIssues", "valid_file_without_issues_written.xml", emptyList()),
+ Params(
+ "WithIssues",
+ "valid_file_with_issues_written.xml",
+ listOf(
+ PersistedSafetyCenterIssue.Builder()
+ .setKey("key1")
+ .setFirstSeenAt(Instant.ofEpochMilli(1654041600000))
+ .build(),
+ PersistedSafetyCenterIssue.Builder()
+ .setKey("key2")
+ .setFirstSeenAt(Instant.ofEpochMilli(1654041600000))
+ .setDismissedAt(Instant.ofEpochMilli(1654214400000))
+ .setDismissCount(1)
+ .build(),
+ PersistedSafetyCenterIssue.Builder()
+ .setKey("key3")
+ .setFirstSeenAt(Instant.ofEpochMilli(1654128000000))
+ .setDismissedAt(Instant.ofEpochMilli(1654214400000))
+ .setDismissCount(10)
+ .build(),
+ PersistedSafetyCenterIssue.Builder()
+ .setKey("key4")
+ .setFirstSeenAt(Instant.ofEpochMilli(1654128000000))
+ .setDismissedAt(Instant.ofEpochMilli(1654214400000))
+ .setNotificationDismissedAt(Instant.ofEpochMilli(1654214400000))
+ .setDismissCount(1)
+ .build(),
+ PersistedSafetyCenterIssue.Builder()
+ .setKey("key5")
+ .setFirstSeenAt(Instant.ofEpochMilli(1654128000000))
+ .setNotificationDismissedAt(Instant.ofEpochMilli(1654214400000))
+ .build()
+ )
+ )
+ )
+ }
+}
diff --git a/SafetyCenter/Resources/Android.bp b/SafetyCenter/Resources/Android.bp
index 05f9f4c37..06f7e5f25 100644
--- a/SafetyCenter/Resources/Android.bp
+++ b/SafetyCenter/Resources/Android.bp
@@ -19,17 +19,34 @@ package {
default_applicable_licenses: ["Android-Apache-2.0"],
}
+android_library {
+ name: "SafetyCenterResourcesShared",
+ sdk_version: "system_current",
+ min_sdk_version: "30",
+ apex_available: ["com.android.permission"],
+ resource_dirs: [
+ "shared_res",
+ ],
+ manifest: "AndroidManifestLibrary.xml",
+ visibility: [
+ "//packages/modules/Permission:__subpackages__",
+ "//vendor:__subpackages__",
+ ],
+}
+
android_app {
name: "SafetyCenterResources",
privileged: true,
sdk_version: "system_current",
min_sdk_version: "30",
- target_sdk_version: "32",
apex_available: ["com.android.permission"],
certificate: ":com.android.safetycenter.resources.certificate",
lint: {
extra_check_modules: ["ConfigLintChecker"],
},
+ static_libs: [
+ "SafetyCenterResourcesShared",
+ ],
}
android_app_certificate {
diff --git a/SafetyCenter/Resources/AndroidManifestLibrary.xml b/SafetyCenter/Resources/AndroidManifestLibrary.xml
new file mode 100644
index 000000000..861a34f50
--- /dev/null
+++ b/SafetyCenter/Resources/AndroidManifestLibrary.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.safetycenter.resources">
+</manifest>
diff --git a/SafetyCenter/Resources/res/drawable-night-v34/illustration_android_lock_screen_sources.xml b/SafetyCenter/Resources/res/drawable-night-v34/illustration_android_lock_screen_sources.xml
new file mode 100644
index 000000000..b48dbf525
--- /dev/null
+++ b/SafetyCenter/Resources/res/drawable-night-v34/illustration_android_lock_screen_sources.xml
@@ -0,0 +1,62 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="380dp"
+ android:height="276dp"
+ android:viewportWidth="380"
+ android:viewportHeight="276">
+ <path
+ android:pathData="M354.34,276H25.66C11.56,276 0,264.2 0,249.8V26.24C0,11.8 11.56,0 25.66,0H354.44C368.44,0 380,11.8 380,26.2V249.9C380,264.2 368.44,276 354.34,276Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M190,37.72C185.34,37.71 180.72,38.64 176.42,40.45C170.09,43.12 164.69,47.58 160.9,53.3C157.1,59.01 155.09,65.72 155.1,72.57V90.07H155.29V111.34H161.69V72.57C161.67,67.12 163.23,61.79 166.18,57.2L166.04,57.11C166.1,57.01 166.16,56.92 166.23,56.82C169.33,52.16 173.74,48.5 178.91,46.33C185.11,43.73 192.03,43.39 198.45,45.38C204.88,47.37 210.39,51.55 214.02,57.2L214.02,57.2C216.96,61.79 218.52,67.12 218.51,72.57V111.34H224.9V72.57C224.92,65.9 223.01,59.37 219.4,53.76L215.27,56.4L219.39,53.76C216.24,48.83 211.9,44.78 206.76,41.98C201.62,39.17 195.86,37.71 190,37.72Z"
+ android:fillColor="#669DF6"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M250.08,227.69H129.93C126.53,227.69 123.28,226.35 120.88,223.96C118.48,221.56 117.14,218.32 117.14,214.93V122.24C117.14,118.86 118.48,115.61 120.88,113.22C123.28,110.83 126.53,109.48 129.93,109.48H250.08C253.47,109.48 256.72,110.83 259.12,113.22C261.52,115.61 262.86,118.86 262.86,122.24V214.93C262.86,218.32 261.52,221.56 259.12,223.96C256.72,226.35 253.47,227.69 250.08,227.69ZM129.93,113.13C127.5,113.13 125.18,114.09 123.47,115.8C121.75,117.5 120.79,119.82 120.79,122.24V214.93C120.79,217.35 121.75,219.67 123.47,221.38C125.18,223.09 127.5,224.05 129.93,224.05H250.08C252.5,224.05 254.82,223.09 256.54,221.38C258.25,219.67 259.21,217.35 259.21,214.93V122.24C259.21,119.82 258.25,117.5 256.54,115.8C254.82,114.09 252.5,113.13 250.08,113.13H129.93Z"
+ android:fillColor="#80868B"/>
+ <path
+ android:pathData="M281.78,245.93C303.27,245.93 320.69,228.59 320.69,207.21C320.69,185.83 303.27,168.49 281.78,168.49C260.29,168.49 242.86,185.83 242.86,207.21C242.86,228.59 260.29,245.93 281.78,245.93Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M281.77,168.36C260.2,168.36 242.57,185.76 242.57,207.37C242.57,228.97 260.06,246.37 281.77,246.37C303.49,246.37 320.97,228.97 320.97,207.37C320.97,185.76 303.35,168.36 281.77,168.36ZM281.77,238.37C264.57,238.37 250.47,224.34 250.47,207.22C250.47,190.11 264.57,176.08 281.77,176.08C298.98,176.08 313.08,190.11 313.08,207.22C313.08,224.48 298.98,238.37 281.77,238.37Z"
+ android:fillColor="#669DF6"/>
+ <path
+ android:pathData="M281.77,170.07C261.13,170.07 244.28,186.71 244.28,207.37C244.28,228.02 260.99,244.66 281.77,244.66C302.56,244.66 319.27,228.02 319.27,207.37C319.27,186.71 302.42,170.07 281.77,170.07ZM281.77,240.07C263.64,240.07 248.77,225.29 248.77,207.22C248.77,189.16 263.64,174.38 281.77,174.38C299.91,174.38 314.78,189.16 314.78,207.22C314.78,225.43 299.9,240.07 281.77,240.07ZM242.57,207.37C242.57,185.76 260.2,168.36 281.77,168.36C303.35,168.36 320.97,185.76 320.97,207.37C320.97,228.97 303.49,246.37 281.77,246.37C260.06,246.37 242.57,228.97 242.57,207.37ZM250.47,207.22C250.47,224.34 264.57,238.37 281.77,238.37C298.98,238.37 313.08,224.48 313.08,207.22C313.08,190.11 298.98,176.08 281.77,176.08C264.57,176.08 250.47,190.11 250.47,207.22Z"
+ android:fillColor="#000000"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M301.48,193.25C301.48,191.56 300.44,190.07 298.85,189.48L283.36,183.85C282.49,183.54 281.54,183.54 280.66,183.85L265.15,189.48C263.56,190.07 262.52,191.56 262.52,193.25V203.97C262.56,205.8 262.69,207.57 262.93,209.4C264.07,217.18 268.46,226.02 280.47,232.19C281.42,232.68 282.56,232.68 283.51,232.19C295.52,225.99 299.9,217.18 301.05,209.4C301.29,207.59 301.44,205.8 301.46,203.97V193.25H301.48Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M291.62,222.69C291.74,222.13 292.45,218.26 290.38,214.37C289.21,212.19 287.7,210.92 285.63,209.28C284.22,208.18 280.47,205.76 279.52,205.17C279.56,205.19 279.64,205.27 279.69,205.29C279.17,204.97 279.2,204.97 279.52,205.17C278.47,204.46 276.67,203.04 275.3,200.59C273.67,197.68 273.62,194.96 273.62,194.45C273.62,194.4 273.62,194.38 273.62,194.33C273.62,191.05 274.64,188.5 276.28,186.67C277.49,185.3 278.88,184.51 280.05,184.05L265.15,189.48C263.56,190.04 262.52,191.56 262.52,193.25V203.97C262.56,205.8 262.69,207.57 262.93,209.4C264.07,217.18 268.46,226.02 280.47,232.18C281.42,232.67 282.56,232.67 283.51,232.18C284.63,231.62 285.65,231.01 286.63,230.4C288.14,229.27 290.79,226.78 291.6,222.69H291.62Z"
+ android:fillColor="#3957E2"/>
+ <path
+ android:pathData="M279.69,205.29C279.69,205.29 279.57,205.19 279.52,205.17C279.2,204.97 279.18,204.97 279.69,205.29Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M298.85,189.48L283.36,183.85C282.49,183.54 281.54,183.54 280.66,183.85L280.05,184.07C278.91,184.54 277.49,185.32 276.28,186.69C274.64,188.53 273.62,191.07 273.62,194.35C273.62,194.4 273.62,194.43 273.62,194.48C273.62,194.99 273.69,197.71 275.3,200.62C276.67,203.06 278.44,204.46 279.52,205.19C280.46,205.8 284.22,208.2 285.63,209.3C287.7,210.94 289.23,212.22 290.38,214.4C292.45,218.26 291.72,222.15 291.62,222.71C290.82,226.8 288.16,229.27 286.65,230.42C296.3,224.4 300.02,216.48 301.07,209.43C301.31,207.62 301.46,205.83 301.48,203.99V193.25C301.48,191.56 300.44,190.07 298.85,189.48Z"
+ android:fillColor="#698FF7"/>
+ <path
+ android:pathData="M157.35,137.23C157.97,136.58 158.83,136.2 159.73,136.17C160.63,136.14 161.5,136.47 162.16,137.08L162.31,137.22L163.18,138.14C163.57,138.57 164.07,138.88 164.62,139.06C165.17,139.24 165.76,139.26 166.32,139.15L167.53,138.91C168.42,138.74 169.34,138.93 170.09,139.44C170.84,139.95 171.36,140.73 171.54,141.61C171.54,141.68 171.55,141.74 171.59,141.8L171.73,143.06C171.8,143.62 172.01,144.17 172.35,144.63C172.69,145.09 173.14,145.46 173.66,145.7L174.77,146.27C175.58,146.66 176.21,147.36 176.52,148.2C176.83,149.05 176.79,149.98 176.41,150.8C176.37,150.84 176.37,150.94 176.32,150.99L175.74,152.05C175.45,152.55 175.3,153.11 175.3,153.69C175.3,154.26 175.46,154.82 175.74,155.32L176.32,156.43C176.74,157.22 176.84,158.16 176.58,159.02C176.32,159.89 175.73,160.62 174.94,161.06C174.89,161.1 174.8,161.1 174.75,161.15L173.63,161.68C173.11,161.92 172.66,162.29 172.32,162.76C171.99,163.22 171.77,163.76 171.71,164.33L171.56,165.59C171.44,166.48 170.97,167.28 170.26,167.84C169.54,168.38 168.64,168.63 167.74,168.53C167.68,168.54 167.61,168.52 167.55,168.48L166.38,168.24C165.82,168.15 165.23,168.19 164.69,168.36C164.14,168.54 163.64,168.85 163.24,169.25L162.39,170.13C161.76,170.78 160.91,171.16 160.01,171.19C159.11,171.22 158.23,170.89 157.57,170.28L157.43,170.14L156.55,169.22C156.16,168.8 155.66,168.49 155.1,168.31C154.54,168.14 153.95,168.12 153.39,168.25L152.18,168.49C151.29,168.66 150.37,168.47 149.62,167.96C148.87,167.46 148.35,166.67 148.17,165.79C148.18,165.72 148.16,165.65 148.12,165.6L147.98,164.34C147.91,163.77 147.7,163.23 147.36,162.77C147.02,162.3 146.57,161.93 146.05,161.69L144.94,161.16C144.53,160.97 144.16,160.7 143.85,160.37C143.55,160.03 143.32,159.64 143.16,159.21C143.01,158.78 142.94,158.33 142.96,157.88C142.99,157.43 143.1,156.99 143.3,156.58C143.34,156.53 143.34,156.44 143.39,156.39L143.97,155.28C144.26,154.78 144.4,154.22 144.4,153.65C144.4,153.07 144.26,152.51 143.97,152.01L143.39,150.9C142.97,150.1 142.88,149.17 143.13,148.3C143.39,147.44 143.98,146.71 144.77,146.28C144.82,146.23 144.91,146.23 144.96,146.18L146.08,145.65C146.6,145.41 147.05,145.04 147.39,144.57C147.72,144.11 147.94,143.57 148,143L148.15,141.75C148.27,140.86 148.74,140.05 149.46,139.5C150.17,138.95 151.07,138.7 151.97,138.81C152.04,138.8 152.1,138.82 152.16,138.86L153.37,139.1C153.93,139.19 154.51,139.15 155.06,138.97C155.6,138.8 156.1,138.49 156.5,138.09L157.35,137.24L157.35,137.23Z"
+ android:fillColor="#EE675C"/>
+ <path
+ android:pathData="M165.34,152.63L157.4,148.13C156.85,147.86 156.31,147.99 156.03,148.54C155.9,148.68 155.9,148.81 155.9,149.09V158.08C155.9,158.63 156.31,159.04 156.85,159.04C156.99,159.04 157.27,159.04 157.4,158.9L165.2,154.4C165.75,154.13 165.89,153.59 165.61,153.04C165.61,152.9 165.47,152.77 165.34,152.63Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M236.54,176.53L226.88,171.29C226.22,170.97 225.55,171.13 225.22,171.77C225.05,171.93 225.05,172.09 225.05,172.4V182.9C225.05,183.53 225.55,184.01 226.22,184.01C226.39,184.01 226.72,184.01 226.88,183.85L236.37,178.6C237.04,178.28 237.21,177.65 236.87,177.01C236.87,176.85 236.7,176.7 236.54,176.53Z"
+ android:fillColor="#3C4043"/>
+ <path
+ android:pathData="M148.49,207.01C143.41,207.01 139.27,202.88 139.27,197.81C139.27,192.74 143.41,188.61 148.49,188.61C153.58,188.61 157.72,192.74 157.72,197.81C157.72,202.88 153.58,207.01 148.49,207.01Z"
+ android:fillColor="#3C4043"/>
+ <path
+ android:pathData="M224.65,129.5L213.61,128.09C212.49,127.95 211.34,128.11 210.3,128.56C209.26,129 208.34,129.71 207.66,130.61L200.9,139.5C200.21,140.4 199.78,141.48 199.63,142.61C199.49,143.74 199.65,144.89 200.09,145.93L204.37,156.22C204.81,157.27 205.52,158.18 206.42,158.87C207.33,159.55 208.4,159.99 209.52,160.13L220.56,161.52C221.69,161.67 222.83,161.51 223.88,161.07C224.93,160.63 225.84,159.92 226.53,159.01L233.26,150.14C233.95,149.23 234.39,148.16 234.53,147.03C234.67,145.9 234.52,144.75 234.08,143.7L229.79,133.42C229.35,132.37 228.65,131.45 227.74,130.76C226.84,130.07 225.77,129.64 224.65,129.5Z"
+ android:fillColor="#FCC934"/>
+ <path
+ android:pathData="M210.34,150.41L223.25,151.73L224.57,138.86L211.66,137.54L210.34,150.41ZM210.15,152.25C209.64,152.2 209.23,151.98 208.9,151.58C208.58,151.18 208.44,150.73 208.5,150.23L209.82,137.35C209.87,136.85 210.09,136.43 210.49,136.11C210.89,135.78 211.34,135.65 211.85,135.7L224.76,137.02C225.26,137.07 225.68,137.29 226,137.69C226.33,138.09 226.46,138.54 226.41,139.04L225.09,151.92C225.04,152.43 224.81,152.84 224.42,153.16C224.02,153.49 223.57,153.62 223.06,153.57L210.15,152.25ZM211.45,148.67L222.51,149.8L219.53,144.85L216.38,148.24L214.59,145.27L211.45,148.67L211.45,148.67ZM211.66,137.54L210.34,150.41L211.66,137.54Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M178.53,187.68C174.35,181.53 179.88,173.46 187.15,175.11L188.35,175.38C190.56,175.88 192.89,175.44 194.77,174.17L195.79,173.48C201.96,169.32 210.05,174.84 208.4,182.08L208.13,183.28C207.62,185.49 208.06,187.81 209.34,189.69L210.02,190.7C214.2,196.85 208.67,204.93 201.41,203.28L200.21,203.01C197.99,202.5 195.66,202.94 193.78,204.21L192.76,204.9C186.6,209.07 178.5,203.55 180.15,196.3L180.43,195.1C180.93,192.9 180.5,190.57 179.22,188.7L178.53,187.68L178.53,187.68Z"
+ android:fillColor="#5BB974"/>
+ <path
+ android:pathData="M189.5,195.21C190.11,194.34 190.86,193.6 191.77,192.99C192.68,192.39 193.71,191.98 194.85,191.76C196,191.54 197.1,191.55 198.17,191.78C199.24,192.01 200.21,192.42 201.1,193.01L199.08,182.41L187.48,184.61L189.5,195.21ZM194.54,190.11C195.33,189.96 195.97,189.54 196.42,188.87C196.88,188.2 197.04,187.46 196.88,186.67C196.73,185.87 196.32,185.24 195.65,184.79C194.98,184.34 194.23,184.18 193.44,184.33C192.64,184.48 192,184.89 191.55,185.57C191.09,186.24 190.93,186.97 191.09,187.77C191.24,188.56 191.65,189.2 192.33,189.65C193,190.1 193.74,190.26 194.54,190.11ZM189.99,197.8C189.54,197.89 189.12,197.8 188.73,197.54C188.34,197.28 188.11,196.92 188.02,196.47L185.82,184.92C185.74,184.46 185.83,184.04 186.09,183.66C186.35,183.27 186.71,183.04 187.16,182.95L198.76,180.76C199.22,180.67 199.64,180.76 200.02,181.02C200.41,181.28 200.65,181.63 200.73,182.09L202.93,193.64C203.02,194.1 202.93,194.51 202.67,194.9C202.4,195.29 202.05,195.52 201.59,195.6L189.99,197.8ZM189.68,196.15L201.28,193.96L201.1,193C200.21,192.41 199.24,192.01 198.17,191.77C197.1,191.54 195.99,191.54 194.85,191.76C193.71,191.97 192.68,192.38 191.77,192.99C190.86,193.59 190.11,194.33 189.5,195.2L189.68,196.15ZM189.5,195.21L187.48,184.61L199.08,182.41L201.1,193.01C200.21,192.42 199.24,192.01 198.17,191.78C197.1,191.55 196,191.54 194.85,191.76C193.71,191.98 192.68,192.39 191.77,192.99C190.86,193.6 190.11,194.34 189.5,195.21Z"
+ android:fillColor="#ffffff"/>
+</vector>
diff --git a/SafetyCenter/Resources/res/drawable-v34/illustration_android_lock_screen_sources.xml b/SafetyCenter/Resources/res/drawable-v34/illustration_android_lock_screen_sources.xml
new file mode 100644
index 000000000..e851e36c2
--- /dev/null
+++ b/SafetyCenter/Resources/res/drawable-v34/illustration_android_lock_screen_sources.xml
@@ -0,0 +1,62 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="380dp"
+ android:height="276dp"
+ android:viewportWidth="380"
+ android:viewportHeight="276">
+ <path
+ android:pathData="M354.34,276H25.66C11.56,276 0,264.2 0,249.8V26.24C0,11.8 11.56,0 25.66,0H354.44C368.44,0 380,11.8 380,26.2V249.9C380,264.2 368.44,276 354.34,276Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M190,37.72C185.34,37.71 180.72,38.64 176.42,40.45C170.09,43.12 164.69,47.58 160.9,53.3C157.1,59.01 155.09,65.72 155.1,72.57V90.07H155.29V111.34H161.69V72.57C161.67,67.12 163.23,61.79 166.18,57.2L166.04,57.11C166.1,57.01 166.16,56.92 166.23,56.82C169.33,52.16 173.74,48.5 178.91,46.33C185.11,43.73 192.03,43.39 198.45,45.38C204.88,47.37 210.39,51.55 214.02,57.2L214.02,57.2C216.96,61.79 218.52,67.12 218.51,72.57V111.34H224.9V72.57C224.92,65.9 223.01,59.37 219.4,53.76L215.27,56.4L219.39,53.76C216.24,48.83 211.9,44.78 206.76,41.98C201.62,39.17 195.86,37.71 190,37.72Z"
+ android:fillColor="#1A73E8"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M250.08,227.69H129.93C126.53,227.69 123.28,226.35 120.88,223.96C118.48,221.56 117.14,218.32 117.14,214.93V122.24C117.14,118.86 118.48,115.61 120.88,113.22C123.28,110.83 126.53,109.48 129.93,109.48H250.08C253.47,109.48 256.72,110.83 259.12,113.22C261.52,115.61 262.86,118.86 262.86,122.24V214.93C262.86,218.32 261.52,221.56 259.12,223.96C256.72,226.35 253.47,227.69 250.08,227.69ZM129.93,113.13C127.5,113.13 125.18,114.09 123.47,115.8C121.75,117.5 120.79,119.82 120.79,122.24V214.93C120.79,217.35 121.75,219.67 123.47,221.38C125.18,223.09 127.5,224.05 129.93,224.05H250.08C252.5,224.05 254.82,223.09 256.54,221.38C258.25,219.67 259.21,217.35 259.21,214.93V122.24C259.21,119.82 258.25,117.5 256.54,115.8C254.82,114.09 252.5,113.13 250.08,113.13H129.93Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M281.78,245.93C303.27,245.93 320.69,228.59 320.69,207.21C320.69,185.83 303.27,168.49 281.78,168.49C260.29,168.49 242.86,185.83 242.86,207.21C242.86,228.59 260.29,245.93 281.78,245.93Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M281.77,168.36C260.2,168.36 242.57,185.76 242.57,207.37C242.57,228.97 260.06,246.37 281.77,246.37C303.49,246.37 320.97,228.97 320.97,207.37C320.97,185.76 303.35,168.36 281.77,168.36ZM281.77,238.37C264.57,238.37 250.47,224.34 250.47,207.22C250.47,190.11 264.57,176.08 281.77,176.08C298.98,176.08 313.08,190.11 313.08,207.22C313.08,224.48 298.98,238.37 281.77,238.37Z"
+ android:fillColor="#1A73E8"/>
+ <path
+ android:pathData="M281.77,170.07C261.13,170.07 244.28,186.71 244.28,207.37C244.28,228.02 260.99,244.66 281.77,244.66C302.56,244.66 319.27,228.02 319.27,207.37C319.27,186.71 302.42,170.07 281.77,170.07ZM281.77,240.07C263.64,240.07 248.77,225.29 248.77,207.22C248.77,189.16 263.64,174.38 281.77,174.38C299.91,174.38 314.78,189.16 314.78,207.22C314.78,225.43 299.9,240.07 281.77,240.07ZM242.57,207.37C242.57,185.76 260.2,168.36 281.77,168.36C303.35,168.36 320.97,185.76 320.97,207.37C320.97,228.97 303.49,246.37 281.77,246.37C260.06,246.37 242.57,228.97 242.57,207.37ZM250.47,207.22C250.47,224.34 264.57,238.37 281.77,238.37C298.98,238.37 313.08,224.48 313.08,207.22C313.08,190.11 298.98,176.08 281.77,176.08C264.57,176.08 250.47,190.11 250.47,207.22Z"
+ android:fillColor="#ffffff"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M301.48,192.92C301.48,191.23 300.44,189.74 298.85,189.15L283.36,183.52C282.49,183.21 281.54,183.21 280.66,183.52L265.15,189.15C263.56,189.74 262.52,191.23 262.52,192.92V203.64C262.56,205.48 262.69,207.24 262.93,209.07C264.07,216.85 268.46,225.69 280.47,231.86C281.42,232.35 282.56,232.35 283.51,231.86C295.52,225.66 299.9,216.85 301.05,209.07C301.29,207.26 301.44,205.48 301.46,203.64V192.92H301.48Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M291.62,222.36C291.74,221.8 292.45,217.93 290.38,214.04C289.21,211.86 287.7,210.59 285.63,208.95C284.22,207.85 280.47,205.43 279.52,204.84C279.56,204.86 279.64,204.94 279.69,204.96C279.17,204.64 279.2,204.64 279.52,204.84C278.47,204.13 276.67,202.71 275.3,200.26C273.67,197.35 273.62,194.63 273.62,194.12C273.62,194.07 273.62,194.05 273.62,194C273.62,190.72 274.64,188.17 276.28,186.34C277.49,184.97 278.88,184.18 280.05,183.72L265.15,189.15C263.56,189.71 262.52,191.23 262.52,192.92V203.64C262.56,205.47 262.69,207.24 262.93,209.07C264.07,216.85 268.46,225.69 280.47,231.85C281.42,232.34 282.56,232.34 283.51,231.85C284.63,231.29 285.65,230.68 286.63,230.07C288.14,228.94 290.79,226.45 291.6,222.36H291.62Z"
+ android:fillColor="#0842A0"/>
+ <path
+ android:pathData="M279.69,204.96C279.69,204.96 279.57,204.86 279.52,204.84C279.2,204.64 279.18,204.64 279.69,204.96Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M298.85,189.15L283.36,183.52C282.49,183.21 281.54,183.21 280.66,183.52L280.05,183.74C278.91,184.21 277.49,184.99 276.28,186.36C274.64,188.2 273.62,190.74 273.62,194.02C273.62,194.07 273.62,194.1 273.62,194.15C273.62,194.66 273.69,197.38 275.3,200.29C276.67,202.73 278.44,204.13 279.52,204.86C280.46,205.48 284.22,207.87 285.63,208.97C287.7,210.61 289.23,211.89 290.38,214.07C292.45,217.93 291.72,221.82 291.62,222.38C290.82,226.47 288.16,228.94 286.65,230.09C296.3,224.07 300.02,216.15 301.07,209.1C301.31,207.29 301.46,205.5 301.48,203.66V192.92C301.48,191.23 300.44,189.74 298.85,189.15Z"
+ android:fillColor="#467CF1"/>
+ <path
+ android:pathData="M157.35,137.23C157.97,136.58 158.83,136.2 159.73,136.17C160.63,136.14 161.5,136.47 162.16,137.08L162.31,137.22L163.18,138.14C163.57,138.57 164.07,138.88 164.62,139.06C165.17,139.24 165.76,139.26 166.32,139.15L167.53,138.91C168.42,138.74 169.34,138.93 170.09,139.44C170.84,139.95 171.36,140.73 171.54,141.61C171.54,141.68 171.55,141.74 171.59,141.8L171.73,143.06C171.8,143.62 172.01,144.17 172.35,144.63C172.69,145.09 173.14,145.46 173.66,145.7L174.77,146.27C175.58,146.66 176.21,147.36 176.52,148.2C176.83,149.05 176.79,149.98 176.41,150.8C176.37,150.84 176.37,150.94 176.32,150.99L175.74,152.05C175.45,152.55 175.3,153.11 175.3,153.69C175.3,154.26 175.46,154.82 175.74,155.32L176.32,156.43C176.74,157.22 176.84,158.16 176.58,159.02C176.32,159.89 175.73,160.62 174.94,161.06C174.89,161.1 174.8,161.1 174.75,161.15L173.63,161.68C173.11,161.92 172.66,162.29 172.32,162.76C171.99,163.22 171.77,163.76 171.71,164.33L171.56,165.59C171.44,166.48 170.97,167.28 170.26,167.84C169.54,168.38 168.64,168.63 167.74,168.53C167.68,168.54 167.61,168.52 167.55,168.48L166.38,168.24C165.82,168.15 165.23,168.19 164.69,168.36C164.14,168.54 163.64,168.85 163.24,169.25L162.39,170.13C161.76,170.78 160.91,171.16 160.01,171.19C159.11,171.22 158.23,170.89 157.57,170.28L157.43,170.14L156.55,169.22C156.16,168.8 155.66,168.49 155.1,168.31C154.54,168.14 153.95,168.12 153.39,168.25L152.18,168.49C151.29,168.66 150.37,168.47 149.62,167.96C148.87,167.46 148.35,166.67 148.17,165.79C148.18,165.72 148.16,165.65 148.12,165.6L147.98,164.34C147.91,163.77 147.7,163.23 147.36,162.77C147.02,162.3 146.57,161.93 146.05,161.69L144.94,161.16C144.53,160.97 144.16,160.7 143.85,160.37C143.55,160.03 143.32,159.64 143.16,159.21C143.01,158.78 142.94,158.33 142.96,157.88C142.99,157.43 143.1,156.99 143.3,156.58C143.34,156.53 143.34,156.44 143.39,156.39L143.97,155.28C144.26,154.78 144.4,154.22 144.4,153.65C144.4,153.07 144.26,152.51 143.97,152.01L143.39,150.9C142.97,150.1 142.88,149.17 143.13,148.3C143.39,147.44 143.98,146.71 144.77,146.28C144.82,146.23 144.91,146.23 144.96,146.18L146.08,145.65C146.6,145.41 147.05,145.04 147.39,144.57C147.72,144.11 147.94,143.57 148,143L148.15,141.75C148.27,140.86 148.74,140.05 149.46,139.5C150.17,138.95 151.07,138.7 151.97,138.81C152.04,138.8 152.1,138.82 152.16,138.86L153.37,139.1C153.93,139.19 154.51,139.15 155.06,138.97C155.6,138.8 156.1,138.49 156.5,138.09L157.35,137.24L157.35,137.23Z"
+ android:fillColor="#D93025"/>
+ <path
+ android:pathData="M165.34,152.63L157.4,148.13C156.85,147.86 156.31,147.99 156.03,148.54C155.9,148.68 155.9,148.81 155.9,149.09V158.08C155.9,158.63 156.31,159.04 156.85,159.04C156.99,159.04 157.27,159.04 157.4,158.9L165.2,154.4C165.75,154.13 165.89,153.59 165.61,153.04C165.61,152.9 165.47,152.77 165.34,152.63Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M236.54,176.53L226.88,171.29C226.22,170.97 225.55,171.13 225.22,171.77C225.05,171.93 225.05,172.09 225.05,172.4V182.9C225.05,183.53 225.55,184.01 226.22,184.01C226.39,184.01 226.72,184.01 226.88,183.85L236.37,178.6C237.04,178.28 237.21,177.65 236.87,177.01C236.87,176.85 236.7,176.7 236.54,176.53Z"
+ android:fillColor="#E8EAED"/>
+ <path
+ android:pathData="M148.49,207.01C143.41,207.01 139.27,202.88 139.27,197.81C139.27,192.74 143.41,188.61 148.49,188.61C153.58,188.61 157.72,192.74 157.72,197.81C157.72,202.88 153.58,207.01 148.49,207.01Z"
+ android:fillColor="#E8EAED"/>
+ <path
+ android:pathData="M224.65,129.5L213.61,128.09C212.49,127.95 211.34,128.11 210.3,128.56C209.26,129 208.34,129.71 207.66,130.61L200.9,139.5C200.21,140.4 199.78,141.48 199.63,142.61C199.49,143.74 199.65,144.89 200.09,145.93L204.37,156.22C204.81,157.27 205.52,158.18 206.42,158.87C207.33,159.55 208.4,159.99 209.52,160.13L220.56,161.52C221.69,161.67 222.83,161.51 223.88,161.07C224.93,160.63 225.84,159.92 226.53,159.01L233.26,150.14C233.95,149.23 234.39,148.16 234.53,147.03C234.67,145.9 234.52,144.75 234.08,143.7L229.79,133.42C229.35,132.37 228.65,131.45 227.74,130.76C226.84,130.07 225.77,129.64 224.65,129.5Z"
+ android:fillColor="#F9AB00"/>
+ <path
+ android:pathData="M210.34,150.41L223.25,151.73L224.57,138.86L211.66,137.54L210.34,150.41ZM210.15,152.25C209.64,152.2 209.23,151.98 208.9,151.58C208.58,151.18 208.44,150.73 208.5,150.23L209.82,137.35C209.87,136.85 210.09,136.43 210.49,136.11C210.89,135.78 211.34,135.65 211.85,135.7L224.76,137.02C225.26,137.07 225.68,137.29 226,137.69C226.33,138.09 226.46,138.54 226.41,139.04L225.09,151.92C225.04,152.43 224.81,152.84 224.42,153.16C224.02,153.49 223.57,153.62 223.06,153.57L210.15,152.25ZM211.45,148.67L222.51,149.8L219.53,144.85L216.38,148.24L214.59,145.27L211.45,148.67L211.45,148.67ZM211.66,137.54L210.34,150.41L211.66,137.54Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M178.53,187.68C174.35,181.53 179.88,173.46 187.15,175.11L188.35,175.38C190.56,175.88 192.89,175.44 194.77,174.17L195.79,173.48C201.96,169.32 210.05,174.84 208.4,182.08L208.13,183.28C207.62,185.49 208.06,187.81 209.34,189.69L210.02,190.7C214.2,196.85 208.67,204.93 201.41,203.28L200.21,203.01C197.99,202.5 195.66,202.94 193.78,204.21L192.76,204.9C186.6,209.07 178.5,203.55 180.15,196.3L180.43,195.1C180.93,192.9 180.5,190.57 179.22,188.7L178.53,187.68L178.53,187.68Z"
+ android:fillColor="#1E8E3E"/>
+ <path
+ android:pathData="M189.5,195.21C190.11,194.34 190.86,193.6 191.77,192.99C192.68,192.39 193.71,191.98 194.85,191.76C196,191.54 197.1,191.55 198.17,191.78C199.24,192.01 200.21,192.42 201.1,193.01L199.08,182.41L187.48,184.61L189.5,195.21ZM194.54,190.11C195.33,189.96 195.97,189.54 196.42,188.87C196.88,188.2 197.04,187.46 196.88,186.67C196.73,185.87 196.32,185.24 195.65,184.79C194.98,184.34 194.23,184.18 193.44,184.33C192.64,184.48 192,184.89 191.55,185.57C191.09,186.24 190.93,186.97 191.09,187.77C191.24,188.56 191.65,189.2 192.33,189.65C193,190.1 193.74,190.26 194.54,190.11ZM189.99,197.8C189.54,197.89 189.12,197.8 188.73,197.54C188.34,197.28 188.11,196.92 188.02,196.47L185.82,184.92C185.74,184.46 185.83,184.04 186.09,183.66C186.35,183.27 186.71,183.04 187.16,182.95L198.76,180.76C199.22,180.67 199.64,180.76 200.02,181.02C200.41,181.28 200.65,181.63 200.73,182.09L202.93,193.64C203.02,194.1 202.93,194.51 202.67,194.9C202.4,195.29 202.05,195.52 201.59,195.6L189.99,197.8ZM189.68,196.15L201.28,193.96L201.1,193C200.21,192.41 199.24,192.01 198.17,191.77C197.1,191.54 195.99,191.54 194.85,191.76C193.71,191.97 192.68,192.38 191.77,192.99C190.86,193.59 190.11,194.33 189.5,195.2L189.68,196.15ZM189.5,195.21L187.48,184.61L199.08,182.41L201.1,193.01C200.21,192.42 199.24,192.01 198.17,191.78C197.1,191.55 196,191.54 194.85,191.76C193.71,191.98 192.68,192.39 191.77,192.99C190.86,193.6 190.11,194.34 189.5,195.21Z"
+ android:fillColor="#ffffff"/>
+</vector>
diff --git a/SafetyCenter/Resources/res/drawable-w480dp-night-v34/illustration_android_lock_screen_sources.xml b/SafetyCenter/Resources/res/drawable-w480dp-night-v34/illustration_android_lock_screen_sources.xml
new file mode 100644
index 000000000..f47f2b1e6
--- /dev/null
+++ b/SafetyCenter/Resources/res/drawable-w480dp-night-v34/illustration_android_lock_screen_sources.xml
@@ -0,0 +1,62 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="844dp"
+ android:height="276dp"
+ android:viewportWidth="844"
+ android:viewportHeight="276">
+ <path
+ android:pathData="M28,0L816,0A28,28 0,0 1,844 28L844,248A28,28 0,0 1,816 276L28,276A28,28 0,0 1,0 248L0,28A28,28 0,0 1,28 0z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M422,37.72C417.34,37.71 412.72,38.64 408.42,40.45C402.09,43.12 396.69,47.58 392.89,53.3C389.1,59.01 387.09,65.72 387.1,72.57V90.07H387.29V111.34H393.69V72.57C393.67,67.12 395.23,61.79 398.18,57.2L398.04,57.11C398.1,57.01 398.17,56.92 398.23,56.82C401.33,52.16 405.74,48.5 410.92,46.33C417.11,43.73 424.03,43.39 430.45,45.38C436.88,47.37 442.39,51.55 446.02,57.2L446.02,57.2C448.96,61.79 450.52,67.12 450.51,72.57V111.34H456.9V72.57C456.92,65.9 455.01,59.37 451.4,53.76L447.27,56.4L451.39,53.76C448.24,48.83 443.89,44.78 438.76,41.98C433.62,39.17 427.86,37.71 422,37.72Z"
+ android:fillColor="#669DF6"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M482.08,227.69H361.92C358.53,227.69 355.28,226.35 352.88,223.96C350.48,221.56 349.14,218.32 349.14,214.93V122.24C349.14,118.86 350.48,115.61 352.88,113.22C355.28,110.83 358.53,109.48 361.92,109.48H482.08C485.47,109.48 488.72,110.83 491.12,113.22C493.52,115.61 494.86,118.86 494.86,122.24V214.93C494.86,218.32 493.52,221.56 491.12,223.96C488.72,226.35 485.47,227.69 482.08,227.69ZM361.92,113.13C359.5,113.13 357.18,114.09 355.47,115.8C353.75,117.5 352.79,119.82 352.79,122.24V214.93C352.79,217.35 353.75,219.67 355.47,221.38C357.18,223.09 359.5,224.05 361.92,224.05H482.08C484.5,224.05 486.82,223.09 488.54,221.38C490.25,219.67 491.21,217.35 491.21,214.93V122.24C491.21,119.82 490.25,117.5 488.54,115.8C486.82,114.09 484.5,113.13 482.08,113.13H361.92Z"
+ android:fillColor="#80868B"/>
+ <path
+ android:pathData="M513.78,245.93C535.27,245.93 552.69,228.59 552.69,207.21C552.69,185.83 535.27,168.49 513.78,168.49C492.29,168.49 474.86,185.83 474.86,207.21C474.86,228.59 492.29,245.93 513.78,245.93Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M513.77,168.36C492.2,168.36 474.57,185.76 474.57,207.37C474.57,228.97 492.06,246.37 513.77,246.37C535.49,246.37 552.97,228.97 552.97,207.37C552.97,185.76 535.35,168.36 513.77,168.36ZM513.77,238.37C496.57,238.37 482.47,224.34 482.47,207.22C482.47,190.11 496.57,176.08 513.77,176.08C530.98,176.08 545.08,190.11 545.08,207.22C545.08,224.48 530.98,238.37 513.77,238.37Z"
+ android:fillColor="#669DF6"/>
+ <path
+ android:pathData="M513.77,170.07C493.13,170.07 476.28,186.71 476.28,207.37C476.28,228.02 492.99,244.66 513.77,244.66C534.56,244.66 551.27,228.02 551.27,207.37C551.27,186.71 534.42,170.07 513.77,170.07ZM513.77,240.07C495.64,240.07 480.77,225.29 480.77,207.22C480.77,189.16 495.64,174.38 513.77,174.38C531.91,174.38 546.78,189.16 546.78,207.22C546.78,225.43 531.9,240.07 513.77,240.07ZM474.57,207.37C474.57,185.76 492.2,168.36 513.77,168.36C535.35,168.36 552.97,185.76 552.97,207.37C552.97,228.97 535.49,246.37 513.77,246.37C492.06,246.37 474.57,228.97 474.57,207.37ZM482.47,207.22C482.47,224.34 496.57,238.37 513.77,238.37C530.98,238.37 545.08,224.48 545.08,207.22C545.08,190.11 530.98,176.08 513.77,176.08C496.57,176.08 482.47,190.11 482.47,207.22Z"
+ android:fillColor="#000000"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M533.48,193.25C533.48,191.56 532.44,190.07 530.85,189.48L515.36,183.85C514.49,183.54 513.54,183.54 512.66,183.85L497.15,189.48C495.56,190.07 494.52,191.56 494.52,193.25V203.97C494.56,205.8 494.69,207.57 494.93,209.4C496.07,217.18 500.46,226.02 512.47,232.19C513.41,232.68 514.56,232.68 515.51,232.19C527.52,225.99 531.9,217.18 533.05,209.4C533.29,207.59 533.44,205.8 533.46,203.97V193.25H533.48Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M523.62,222.69C523.74,222.13 524.45,218.26 522.38,214.37C521.21,212.19 519.7,210.92 517.63,209.28C516.22,208.18 512.47,205.76 511.52,205.17C511.56,205.19 511.64,205.27 511.69,205.29C511.17,204.97 511.2,204.97 511.52,205.17C510.47,204.46 508.67,203.04 507.3,200.59C505.67,197.68 505.62,194.96 505.62,194.45C505.62,194.4 505.62,194.38 505.62,194.33C505.62,191.05 506.64,188.5 508.28,186.67C509.49,185.3 510.88,184.51 512.05,184.05L497.15,189.48C495.56,190.04 494.52,191.56 494.52,193.25V203.97C494.56,205.8 494.69,207.57 494.93,209.4C496.07,217.18 500.46,226.02 512.47,232.18C513.41,232.67 514.56,232.67 515.51,232.18C516.63,231.62 517.65,231.01 518.63,230.4C520.14,229.27 522.79,226.78 523.6,222.69H523.62Z"
+ android:fillColor="#3957E2"/>
+ <path
+ android:pathData="M511.69,205.29C511.69,205.29 511.57,205.19 511.52,205.17C511.2,204.97 511.18,204.97 511.69,205.29Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M530.85,189.48L515.36,183.85C514.49,183.54 513.54,183.54 512.66,183.85L512.05,184.07C510.91,184.54 509.49,185.32 508.28,186.69C506.64,188.53 505.62,191.07 505.62,194.35C505.62,194.4 505.62,194.43 505.62,194.48C505.62,194.99 505.69,197.71 507.3,200.62C508.67,203.06 510.44,204.46 511.52,205.19C512.47,205.8 516.22,208.2 517.63,209.3C519.7,210.94 521.23,212.22 522.38,214.4C524.45,218.26 523.72,222.15 523.62,222.71C522.82,226.8 520.16,229.27 518.65,230.42C528.3,224.4 532.02,216.48 533.07,209.43C533.31,207.62 533.46,205.83 533.48,203.99V193.25C533.48,191.56 532.44,190.07 530.85,189.48Z"
+ android:fillColor="#698FF7"/>
+ <path
+ android:pathData="M389.35,137.23C389.97,136.58 390.83,136.2 391.73,136.17C392.63,136.14 393.5,136.47 394.16,137.08L394.31,137.22L395.18,138.14C395.57,138.57 396.07,138.88 396.62,139.06C397.17,139.24 397.76,139.26 398.32,139.15L399.53,138.91C400.42,138.74 401.34,138.93 402.09,139.44C402.84,139.95 403.36,140.73 403.54,141.61C403.54,141.68 403.55,141.74 403.59,141.8L403.73,143.06C403.8,143.62 404.01,144.17 404.35,144.63C404.69,145.09 405.14,145.46 405.66,145.7L406.77,146.27C407.58,146.66 408.21,147.36 408.52,148.2C408.83,149.05 408.79,149.98 408.41,150.8C408.37,150.84 408.37,150.94 408.32,150.99L407.74,152.05C407.45,152.55 407.3,153.11 407.3,153.69C407.3,154.26 407.45,154.82 407.74,155.32L408.32,156.43C408.74,157.22 408.84,158.16 408.58,159.02C408.32,159.89 407.73,160.62 406.94,161.06C406.89,161.1 406.8,161.1 406.75,161.15L405.63,161.68C405.11,161.92 404.66,162.29 404.33,162.76C403.99,163.22 403.77,163.76 403.71,164.33L403.56,165.59C403.44,166.48 402.97,167.28 402.26,167.84C401.54,168.38 400.64,168.63 399.74,168.53C399.67,168.54 399.61,168.52 399.55,168.48L398.38,168.24C397.82,168.15 397.23,168.19 396.69,168.36C396.14,168.54 395.64,168.85 395.24,169.25L394.39,170.13C393.76,170.78 392.91,171.16 392.01,171.19C391.11,171.22 390.23,170.89 389.57,170.28L389.43,170.14L388.55,169.22C388.16,168.8 387.66,168.49 387.1,168.31C386.54,168.14 385.95,168.12 385.39,168.25L384.18,168.49C383.29,168.66 382.37,168.47 381.62,167.96C380.87,167.46 380.35,166.67 380.17,165.79C380.18,165.72 380.16,165.65 380.12,165.6L379.98,164.34C379.91,163.77 379.7,163.23 379.36,162.77C379.02,162.3 378.58,161.93 378.05,161.69L376.94,161.16C376.53,160.97 376.16,160.7 375.86,160.37C375.55,160.03 375.32,159.64 375.16,159.21C375.01,158.78 374.94,158.33 374.96,157.88C374.99,157.43 375.1,156.99 375.3,156.58C375.34,156.53 375.34,156.44 375.39,156.39L375.97,155.28C376.26,154.78 376.4,154.22 376.4,153.65C376.4,153.07 376.26,152.51 375.97,152.01L375.39,150.9C374.97,150.1 374.88,149.17 375.13,148.3C375.39,147.44 375.98,146.71 376.77,146.28C376.82,146.23 376.91,146.23 376.96,146.18L378.08,145.65C378.6,145.41 379.05,145.04 379.39,144.57C379.72,144.11 379.94,143.57 380,143L380.15,141.75C380.27,140.86 380.74,140.05 381.45,139.5C382.17,138.95 383.07,138.7 383.97,138.81C384.04,138.8 384.1,138.82 384.16,138.86L385.36,139.1C385.93,139.19 386.51,139.15 387.06,138.97C387.6,138.8 388.1,138.49 388.5,138.09L389.35,137.24L389.35,137.23Z"
+ android:fillColor="#EE675C"/>
+ <path
+ android:pathData="M397.34,152.63L389.4,148.13C388.85,147.86 388.31,147.99 388.03,148.54C387.89,148.68 387.89,148.81 387.89,149.09V158.08C387.89,158.63 388.31,159.04 388.85,159.04C388.99,159.04 389.27,159.04 389.4,158.9L397.2,154.4C397.75,154.13 397.89,153.59 397.61,153.04C397.61,152.9 397.47,152.77 397.34,152.63Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M468.54,176.53L458.88,171.29C458.22,170.97 457.55,171.13 457.22,171.77C457.05,171.93 457.05,172.09 457.05,172.4V182.9C457.05,183.53 457.55,184.01 458.22,184.01C458.39,184.01 458.72,184.01 458.88,183.85L468.37,178.6C469.04,178.28 469.21,177.65 468.87,177.01C468.87,176.85 468.7,176.7 468.54,176.53Z"
+ android:fillColor="#3C4043"/>
+ <path
+ android:pathData="M380.49,207.01C375.41,207.01 371.27,202.88 371.27,197.81C371.27,192.74 375.41,188.61 380.49,188.61C385.58,188.61 389.72,192.74 389.72,197.81C389.72,202.88 385.58,207.01 380.49,207.01Z"
+ android:fillColor="#3C4043"/>
+ <path
+ android:pathData="M456.65,129.5L445.61,128.09C444.49,127.95 443.35,128.11 442.3,128.56C441.26,129 440.35,129.71 439.66,130.61L432.9,139.5C432.21,140.4 431.78,141.48 431.64,142.61C431.49,143.74 431.65,144.89 432.09,145.93L436.37,156.22C436.81,157.27 437.52,158.18 438.42,158.87C439.33,159.55 440.4,159.99 441.52,160.13L452.56,161.52C453.69,161.67 454.83,161.51 455.88,161.07C456.93,160.63 457.85,159.92 458.54,159.01L465.26,150.14C465.95,149.23 466.39,148.16 466.53,147.03C466.67,145.9 466.52,144.75 466.08,143.7L461.79,133.42C461.36,132.37 460.65,131.45 459.75,130.76C458.84,130.07 457.77,129.64 456.65,129.5Z"
+ android:fillColor="#FCC934"/>
+ <path
+ android:pathData="M442.34,150.41L455.25,151.73L456.57,138.86L443.66,137.54L442.34,150.41ZM442.15,152.25C441.64,152.2 441.23,151.98 440.9,151.58C440.58,151.18 440.45,150.73 440.5,150.23L441.82,137.35C441.87,136.85 442.09,136.43 442.49,136.11C442.89,135.78 443.34,135.65 443.85,135.7L456.76,137.02C457.27,137.07 457.68,137.29 458.01,137.69C458.33,138.09 458.46,138.54 458.41,139.04L457.09,151.92C457.04,152.43 456.82,152.84 456.42,153.16C456.02,153.49 455.57,153.62 455.06,153.57L442.15,152.25ZM443.45,148.67L454.52,149.8L451.53,144.85L448.39,148.24L446.59,145.27L443.45,148.67L443.45,148.67ZM443.66,137.54L442.34,150.41L443.66,137.54Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M410.53,187.68C406.35,181.53 411.88,173.46 419.14,175.11L420.35,175.38C422.56,175.88 424.89,175.44 426.77,174.17L427.79,173.48C433.95,169.32 442.05,174.84 440.4,182.08L440.13,183.28C439.62,185.49 440.06,187.81 441.33,189.69L442.02,190.7C446.2,196.85 440.67,204.93 433.41,203.28L432.21,203.01C429.99,202.5 427.66,202.94 425.78,204.21L424.76,204.9C418.6,209.07 410.5,203.55 412.15,196.3L412.43,195.1C412.93,192.9 412.5,190.57 411.22,188.7L410.53,187.68L410.53,187.68Z"
+ android:fillColor="#5BB974"/>
+ <path
+ android:pathData="M421.5,195.21C422.11,194.34 422.86,193.6 423.77,192.99C424.68,192.39 425.71,191.98 426.85,191.76C428,191.54 429.1,191.55 430.17,191.78C431.24,192.01 432.21,192.42 433.1,193.01L431.08,182.41L419.48,184.61L421.5,195.21ZM426.54,190.11C427.33,189.96 427.97,189.54 428.42,188.87C428.88,188.2 429.04,187.46 428.89,186.67C428.73,185.87 428.32,185.24 427.65,184.79C426.98,184.34 426.23,184.18 425.44,184.33C424.64,184.48 424,184.89 423.55,185.57C423.09,186.24 422.93,186.97 423.09,187.77C423.24,188.56 423.65,189.2 424.33,189.65C425,190.1 425.74,190.26 426.54,190.11ZM421.99,197.8C421.54,197.89 421.12,197.8 420.73,197.54C420.34,197.28 420.11,196.92 420.02,196.47L417.82,184.92C417.74,184.46 417.83,184.04 418.09,183.66C418.35,183.27 418.71,183.04 419.17,182.95L430.76,180.76C431.22,180.67 431.64,180.76 432.02,181.02C432.42,181.28 432.64,181.63 432.73,182.09L434.93,193.64C435.02,194.1 434.93,194.51 434.67,194.9C434.4,195.29 434.05,195.52 433.59,195.6L421.99,197.8ZM421.68,196.15L433.28,193.96L433.1,193C432.21,192.41 431.24,192.01 430.17,191.77C429.1,191.54 427.99,191.54 426.85,191.76C425.7,191.97 424.68,192.38 423.77,192.99C422.86,193.59 422.11,194.33 421.5,195.2L421.68,196.15ZM421.5,195.21L419.48,184.61L431.08,182.41L433.1,193.01C432.21,192.42 431.24,192.01 430.17,191.78C429.1,191.55 428,191.54 426.85,191.76C425.71,191.98 424.68,192.39 423.77,192.99C422.86,193.6 422.11,194.34 421.5,195.21Z"
+ android:fillColor="#ffffff"/>
+</vector>
diff --git a/SafetyCenter/Resources/res/drawable-w480dp-v34/illustration_android_lock_screen_sources.xml b/SafetyCenter/Resources/res/drawable-w480dp-v34/illustration_android_lock_screen_sources.xml
new file mode 100644
index 000000000..62026009f
--- /dev/null
+++ b/SafetyCenter/Resources/res/drawable-w480dp-v34/illustration_android_lock_screen_sources.xml
@@ -0,0 +1,62 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="844dp"
+ android:height="276dp"
+ android:viewportWidth="844"
+ android:viewportHeight="276">
+ <path
+ android:pathData="M28,0L816,0A28,28 0,0 1,844 28L844,248A28,28 0,0 1,816 276L28,276A28,28 0,0 1,0 248L0,28A28,28 0,0 1,28 0z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M422,37.72C417.34,37.71 412.72,38.64 408.42,40.45C402.09,43.12 396.69,47.58 392.89,53.3C389.1,59.01 387.09,65.72 387.1,72.57V90.07H387.29V111.34H393.69V72.57C393.67,67.12 395.23,61.79 398.18,57.2L398.04,57.11C398.1,57.01 398.17,56.92 398.23,56.82C401.33,52.16 405.74,48.5 410.92,46.33C417.11,43.73 424.03,43.39 430.45,45.38C436.88,47.37 442.39,51.55 446.02,57.2L446.02,57.2C448.96,61.79 450.52,67.12 450.51,72.57V111.34H456.9V72.57C456.92,65.9 455.01,59.37 451.4,53.76L447.27,56.4L451.39,53.76C448.24,48.83 443.89,44.78 438.76,41.98C433.62,39.17 427.86,37.71 422,37.72Z"
+ android:fillColor="#1A73E8"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M482.08,227.69H361.92C358.53,227.69 355.28,226.35 352.88,223.96C350.48,221.56 349.14,218.32 349.14,214.93V122.24C349.14,118.86 350.48,115.61 352.88,113.22C355.28,110.83 358.53,109.48 361.92,109.48H482.08C485.47,109.48 488.72,110.83 491.12,113.22C493.52,115.61 494.86,118.86 494.86,122.24V214.93C494.86,218.32 493.52,221.56 491.12,223.96C488.72,226.35 485.47,227.69 482.08,227.69ZM361.92,113.13C359.5,113.13 357.18,114.09 355.47,115.8C353.75,117.5 352.79,119.82 352.79,122.24V214.93C352.79,217.35 353.75,219.67 355.47,221.38C357.18,223.09 359.5,224.05 361.92,224.05H482.08C484.5,224.05 486.82,223.09 488.54,221.38C490.25,219.67 491.21,217.35 491.21,214.93V122.24C491.21,119.82 490.25,117.5 488.54,115.8C486.82,114.09 484.5,113.13 482.08,113.13H361.92Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M513.78,245.93C535.27,245.93 552.69,228.59 552.69,207.21C552.69,185.83 535.27,168.49 513.78,168.49C492.29,168.49 474.86,185.83 474.86,207.21C474.86,228.59 492.29,245.93 513.78,245.93Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M513.77,168.36C492.2,168.36 474.57,185.76 474.57,207.37C474.57,228.97 492.06,246.37 513.77,246.37C535.49,246.37 552.97,228.97 552.97,207.37C552.97,185.76 535.35,168.36 513.77,168.36ZM513.77,238.37C496.57,238.37 482.47,224.34 482.47,207.22C482.47,190.11 496.57,176.08 513.77,176.08C530.98,176.08 545.08,190.11 545.08,207.22C545.08,224.48 530.98,238.37 513.77,238.37Z"
+ android:fillColor="#1A73E8"/>
+ <path
+ android:pathData="M513.77,170.07C493.13,170.07 476.28,186.71 476.28,207.37C476.28,228.02 492.99,244.66 513.77,244.66C534.56,244.66 551.27,228.02 551.27,207.37C551.27,186.71 534.42,170.07 513.77,170.07ZM513.77,240.07C495.64,240.07 480.77,225.29 480.77,207.22C480.77,189.16 495.64,174.38 513.77,174.38C531.91,174.38 546.78,189.16 546.78,207.22C546.78,225.43 531.9,240.07 513.77,240.07ZM474.57,207.37C474.57,185.76 492.2,168.36 513.77,168.36C535.35,168.36 552.97,185.76 552.97,207.37C552.97,228.97 535.49,246.37 513.77,246.37C492.06,246.37 474.57,228.97 474.57,207.37ZM482.47,207.22C482.47,224.34 496.57,238.37 513.77,238.37C530.98,238.37 545.08,224.48 545.08,207.22C545.08,190.11 530.98,176.08 513.77,176.08C496.57,176.08 482.47,190.11 482.47,207.22Z"
+ android:fillColor="#ffffff"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M533.48,192.92C533.48,191.23 532.44,189.74 530.85,189.15L515.36,183.52C514.49,183.21 513.54,183.21 512.66,183.52L497.15,189.15C495.56,189.74 494.52,191.23 494.52,192.92V203.64C494.56,205.48 494.69,207.24 494.93,209.07C496.07,216.85 500.46,225.69 512.47,231.86C513.41,232.35 514.56,232.35 515.51,231.86C527.52,225.66 531.9,216.85 533.05,209.07C533.29,207.26 533.44,205.48 533.46,203.64V192.92H533.48Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M523.62,222.36C523.74,221.8 524.45,217.93 522.38,214.04C521.21,211.86 519.7,210.59 517.63,208.95C516.22,207.85 512.47,205.43 511.52,204.84C511.56,204.86 511.64,204.94 511.69,204.96C511.17,204.64 511.2,204.64 511.52,204.84C510.47,204.13 508.67,202.71 507.3,200.26C505.67,197.35 505.62,194.63 505.62,194.12C505.62,194.07 505.62,194.05 505.62,194C505.62,190.72 506.64,188.17 508.28,186.34C509.49,184.97 510.88,184.18 512.05,183.72L497.15,189.15C495.56,189.71 494.52,191.23 494.52,192.92V203.64C494.56,205.47 494.69,207.24 494.93,209.07C496.07,216.85 500.46,225.69 512.47,231.85C513.41,232.34 514.56,232.34 515.51,231.85C516.63,231.29 517.65,230.68 518.63,230.07C520.14,228.94 522.79,226.45 523.6,222.36H523.62Z"
+ android:fillColor="#0842A0"/>
+ <path
+ android:pathData="M511.69,204.96C511.69,204.96 511.57,204.86 511.52,204.84C511.2,204.64 511.18,204.64 511.69,204.96Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M530.85,189.15L515.36,183.52C514.49,183.21 513.54,183.21 512.66,183.52L512.05,183.74C510.91,184.21 509.49,184.99 508.28,186.36C506.64,188.2 505.62,190.74 505.62,194.02C505.62,194.07 505.62,194.1 505.62,194.15C505.62,194.66 505.69,197.38 507.3,200.29C508.67,202.73 510.44,204.13 511.52,204.86C512.47,205.48 516.22,207.87 517.63,208.97C519.7,210.61 521.23,211.89 522.38,214.07C524.45,217.93 523.72,221.82 523.62,222.38C522.82,226.47 520.16,228.94 518.65,230.09C528.3,224.07 532.02,216.15 533.07,209.1C533.31,207.29 533.46,205.5 533.48,203.66V192.92C533.48,191.23 532.44,189.74 530.85,189.15Z"
+ android:fillColor="#467CF1"/>
+ <path
+ android:pathData="M389.35,137.23C389.97,136.58 390.83,136.2 391.73,136.17C392.63,136.14 393.5,136.47 394.16,137.08L394.31,137.22L395.18,138.14C395.57,138.57 396.07,138.88 396.62,139.06C397.17,139.24 397.76,139.26 398.32,139.15L399.53,138.91C400.42,138.74 401.34,138.93 402.09,139.44C402.84,139.95 403.36,140.73 403.54,141.61C403.54,141.68 403.55,141.74 403.59,141.8L403.73,143.06C403.8,143.62 404.01,144.17 404.35,144.63C404.69,145.09 405.14,145.46 405.66,145.7L406.77,146.27C407.58,146.66 408.21,147.36 408.52,148.2C408.83,149.05 408.79,149.98 408.41,150.8C408.37,150.84 408.37,150.94 408.32,150.99L407.74,152.05C407.45,152.55 407.3,153.11 407.3,153.69C407.3,154.26 407.45,154.82 407.74,155.32L408.32,156.43C408.74,157.22 408.84,158.16 408.58,159.02C408.32,159.89 407.73,160.62 406.94,161.06C406.89,161.1 406.8,161.1 406.75,161.15L405.63,161.68C405.11,161.92 404.66,162.29 404.33,162.76C403.99,163.22 403.77,163.76 403.71,164.33L403.56,165.59C403.44,166.48 402.97,167.28 402.26,167.84C401.54,168.38 400.64,168.63 399.74,168.53C399.67,168.54 399.61,168.52 399.55,168.48L398.38,168.24C397.82,168.15 397.23,168.19 396.69,168.36C396.14,168.54 395.64,168.85 395.24,169.25L394.39,170.13C393.76,170.78 392.91,171.16 392.01,171.19C391.11,171.22 390.23,170.89 389.57,170.28L389.43,170.14L388.55,169.22C388.16,168.8 387.66,168.49 387.1,168.31C386.54,168.14 385.95,168.12 385.39,168.25L384.18,168.49C383.29,168.66 382.37,168.47 381.62,167.96C380.87,167.46 380.35,166.67 380.17,165.79C380.18,165.72 380.16,165.65 380.12,165.6L379.98,164.34C379.91,163.77 379.7,163.23 379.36,162.77C379.02,162.3 378.58,161.93 378.05,161.69L376.94,161.16C376.53,160.97 376.16,160.7 375.86,160.37C375.55,160.03 375.32,159.64 375.16,159.21C375.01,158.78 374.94,158.33 374.96,157.88C374.99,157.43 375.1,156.99 375.3,156.58C375.34,156.53 375.34,156.44 375.39,156.39L375.97,155.28C376.26,154.78 376.4,154.22 376.4,153.65C376.4,153.07 376.26,152.51 375.97,152.01L375.39,150.9C374.97,150.1 374.88,149.17 375.13,148.3C375.39,147.44 375.98,146.71 376.77,146.28C376.82,146.23 376.91,146.23 376.96,146.18L378.08,145.65C378.6,145.41 379.05,145.04 379.39,144.57C379.72,144.11 379.94,143.57 380,143L380.15,141.75C380.27,140.86 380.74,140.05 381.45,139.5C382.17,138.95 383.07,138.7 383.97,138.81C384.04,138.8 384.1,138.82 384.16,138.86L385.36,139.1C385.93,139.19 386.51,139.15 387.06,138.97C387.6,138.8 388.1,138.49 388.5,138.09L389.35,137.24L389.35,137.23Z"
+ android:fillColor="#D93025"/>
+ <path
+ android:pathData="M397.34,152.63L389.4,148.13C388.85,147.86 388.31,147.99 388.03,148.54C387.89,148.68 387.89,148.81 387.89,149.09V158.08C387.89,158.63 388.31,159.04 388.85,159.04C388.99,159.04 389.27,159.04 389.4,158.9L397.2,154.4C397.75,154.13 397.89,153.59 397.61,153.04C397.61,152.9 397.47,152.77 397.34,152.63Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M468.54,176.53L458.88,171.29C458.22,170.97 457.55,171.13 457.22,171.77C457.05,171.93 457.05,172.09 457.05,172.4V182.9C457.05,183.53 457.55,184.01 458.22,184.01C458.39,184.01 458.72,184.01 458.88,183.85L468.37,178.6C469.04,178.28 469.21,177.65 468.87,177.01C468.87,176.85 468.7,176.7 468.54,176.53Z"
+ android:fillColor="#E8EAED"/>
+ <path
+ android:pathData="M380.49,207.01C375.41,207.01 371.27,202.88 371.27,197.81C371.27,192.74 375.41,188.61 380.49,188.61C385.58,188.61 389.72,192.74 389.72,197.81C389.72,202.88 385.58,207.01 380.49,207.01Z"
+ android:fillColor="#E8EAED"/>
+ <path
+ android:pathData="M456.65,129.5L445.61,128.09C444.49,127.95 443.35,128.11 442.3,128.56C441.26,129 440.35,129.71 439.66,130.61L432.9,139.5C432.21,140.4 431.78,141.48 431.64,142.61C431.49,143.74 431.65,144.89 432.09,145.93L436.37,156.22C436.81,157.27 437.52,158.18 438.42,158.87C439.33,159.55 440.4,159.99 441.52,160.13L452.56,161.52C453.69,161.67 454.83,161.51 455.88,161.07C456.93,160.63 457.85,159.92 458.54,159.01L465.26,150.14C465.95,149.23 466.39,148.16 466.53,147.03C466.67,145.9 466.52,144.75 466.08,143.7L461.79,133.42C461.36,132.37 460.65,131.45 459.75,130.76C458.84,130.07 457.77,129.64 456.65,129.5Z"
+ android:fillColor="#F9AB00"/>
+ <path
+ android:pathData="M442.34,150.41L455.25,151.73L456.57,138.86L443.66,137.54L442.34,150.41ZM442.15,152.25C441.64,152.2 441.23,151.98 440.9,151.58C440.58,151.18 440.45,150.73 440.5,150.23L441.82,137.35C441.87,136.85 442.09,136.43 442.49,136.11C442.89,135.78 443.34,135.65 443.85,135.7L456.76,137.02C457.27,137.07 457.68,137.29 458.01,137.69C458.33,138.09 458.46,138.54 458.41,139.04L457.09,151.92C457.04,152.43 456.82,152.84 456.42,153.16C456.02,153.49 455.57,153.62 455.06,153.57L442.15,152.25ZM443.45,148.67L454.52,149.8L451.53,144.85L448.39,148.24L446.59,145.27L443.45,148.67L443.45,148.67ZM443.66,137.54L442.34,150.41L443.66,137.54Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M410.53,187.68C406.35,181.53 411.88,173.46 419.14,175.11L420.35,175.38C422.56,175.88 424.89,175.44 426.77,174.17L427.79,173.48C433.95,169.32 442.05,174.84 440.4,182.08L440.13,183.28C439.62,185.49 440.06,187.81 441.33,189.69L442.02,190.7C446.2,196.85 440.67,204.93 433.41,203.28L432.21,203.01C429.99,202.5 427.66,202.94 425.78,204.21L424.76,204.9C418.6,209.07 410.5,203.55 412.15,196.3L412.43,195.1C412.93,192.9 412.5,190.57 411.22,188.7L410.53,187.68L410.53,187.68Z"
+ android:fillColor="#1E8E3E"/>
+ <path
+ android:pathData="M421.5,195.21C422.11,194.34 422.86,193.6 423.77,192.99C424.68,192.39 425.71,191.98 426.85,191.76C428,191.54 429.1,191.55 430.17,191.78C431.24,192.01 432.21,192.42 433.1,193.01L431.08,182.41L419.48,184.61L421.5,195.21ZM426.54,190.11C427.33,189.96 427.97,189.54 428.42,188.87C428.88,188.2 429.04,187.46 428.89,186.67C428.73,185.87 428.32,185.24 427.65,184.79C426.98,184.34 426.23,184.18 425.44,184.33C424.64,184.48 424,184.89 423.55,185.57C423.09,186.24 422.93,186.97 423.09,187.77C423.24,188.56 423.65,189.2 424.33,189.65C425,190.1 425.74,190.26 426.54,190.11ZM421.99,197.8C421.54,197.89 421.12,197.8 420.73,197.54C420.34,197.28 420.11,196.92 420.02,196.47L417.82,184.92C417.74,184.46 417.83,184.04 418.09,183.66C418.35,183.27 418.71,183.04 419.17,182.95L430.76,180.76C431.22,180.67 431.64,180.76 432.02,181.02C432.42,181.28 432.64,181.63 432.73,182.09L434.93,193.64C435.02,194.1 434.93,194.51 434.67,194.9C434.4,195.29 434.05,195.52 433.59,195.6L421.99,197.8ZM421.68,196.15L433.28,193.96L433.1,193C432.21,192.41 431.24,192.01 430.17,191.77C429.1,191.54 427.99,191.54 426.85,191.76C425.7,191.97 424.68,192.38 423.77,192.99C422.86,193.59 422.11,194.33 421.5,195.2L421.68,196.15ZM421.5,195.21L419.48,184.61L431.08,182.41L433.1,193.01C432.21,192.42 431.24,192.01 430.17,191.78C429.1,191.55 428,191.54 426.85,191.76C425.71,191.98 424.68,192.39 423.77,192.99C422.86,193.6 422.11,194.34 421.5,195.21Z"
+ android:fillColor="#ffffff"/>
+</vector>
diff --git a/SafetyCenter/Resources/res/raw-v34/safety_center_config.xml b/SafetyCenter/Resources/res/raw-v34/safety_center_config.xml
new file mode 100644
index 000000000..d40b64792
--- /dev/null
+++ b/SafetyCenter/Resources/res/raw-v34/safety_center_config.xml
@@ -0,0 +1,127 @@
+<!--
+ ~ 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="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"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Resources/res/raw/safety_center_config.xml b/SafetyCenter/Resources/res/raw/safety_center_config.xml
index b4739b528..ba4197fd0 100644
--- a/SafetyCenter/Resources/res/raw/safety_center_config.xml
+++ b/SafetyCenter/Resources/res/raw/safety_center_config.xml
@@ -26,12 +26,17 @@
profile="primary_profile_only"
title="@com.android.safetycenter.resources:string/lock_screen_title"
summary="@com.android.safetycenter.resources:string/lock_screen_summary_disabled"
- initialDisplayState="disabled"/>
+ searchTerms="@com.android.safetycenter.resources:string/lock_screen_search_terms"
+ initialDisplayState="disabled"
+ refreshOnPageOpenAllowed="true"/>
<dynamic-safety-source
id="AndroidBiometrics"
packageName="com.android.settings"
profile="primary_profile_only"
- initialDisplayState="hidden"/>
+ title="@com.android.safetycenter.resources:string/biometrics_title"
+ searchTerms="@com.android.safetycenter.resources:string/biometrics_search_terms"
+ initialDisplayState="hidden"
+ refreshOnPageOpenAllowed="true"/>
</safety-sources-group>
<safety-sources-group
id="AndroidPrivacySources"
@@ -43,35 +48,66 @@
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"/>
+ summary="@com.android.safetycenter.resources:string/permission_usage_summary"
+ searchTerms="@com.android.safetycenter.resources:string/permission_usage_search_terms"/>
<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"/>
+ summary="@com.android.safetycenter.resources:string/permission_manager_summary"
+ searchTerms="@com.android.safetycenter.resources:string/permission_manager_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"/>
+ 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"
+ refreshOnPageOpenAllowed="true"/>
+ <issue-only-safety-source
+ id="AndroidNotificationListener"
+ packageName="com.android.permissioncontroller"
+ profile="primary_profile_only"
+ refreshOnPageOpenAllowed="true"/>
+ <issue-only-safety-source
+ id="AndroidBackgroundLocation"
+ packageName="com.android.permissioncontroller"
+ profile="all_profiles"
+ refreshOnPageOpenAllowed="true"/>
+ <issue-only-safety-source
+ id="AndroidPermissionAutoRevoke"
+ packageName="com.android.permissioncontroller"
+ profile="all_profiles"
+ 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"
+ initialDisplayState="hidden"
+ refreshOnPageOpenAllowed="true"/>
<static-safety-source
id="AndroidAdvancedSecurity"
profile="primary_profile_only"
intentAction="com.android.settings.security.SECURITY_ADVANCED_SETTINGS"
title="@com.android.safetycenter.resources:string/advanced_security_title"
- summary="@com.android.safetycenter.resources:string/advanced_security_summary"/>
+ summary="@com.android.safetycenter.resources:string/advanced_security_summary"
+ searchTerms="@com.android.safetycenter.resources:string/advanced_security_search_terms"/>
<static-safety-source
id="AndroidAdvancedPrivacy"
profile="primary_profile_only"
intentAction="android.settings.PRIVACY_ADVANCED_SETTINGS"
title="@com.android.safetycenter.resources:string/advanced_privacy_title"
- summary="@com.android.safetycenter.resources:string/advanced_privacy_summary"/>
+ summary="@com.android.safetycenter.resources:string/advanced_privacy_summary"
+ searchTerms="@com.android.safetycenter.resources:string/advanced_privacy_search_terms"/>
</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
new file mode 100644
index 000000000..ad8401412
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-af-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Toestelontsluiting"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometriese data vir werk"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Toestemmings, kontroleskerm, kontroles"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-af/strings.xml
index 62f3b2e8b..ff0fc873d 100644
--- a/SafetyCenter/Resources/res/values-af/strings.xml
+++ b/SafetyCenter/Resources/res/values-af/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Skermslot"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Nog geen inligting nie"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Toestelslot, Skermslot, Sluit skerm, Sluitskerm, Wagwoord, Pin, Patroon"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometrie"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Vingerafdruk, Vinger, Voeg vingerafdruk by, Gesigslot, Gesig"</string>
<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>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Toestemmings, Toestemmingsbestuurder"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Privaatheidkontroles"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Beheer toesteltoegang tot mikrofoon, kamera en meer"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privaatheid, Privaatheidkontroles"</string>
<string name="advanced_title" msgid="8745436380690561172">"Meer instellings"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Meer sekuriteitinstellings"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Enkripsie, eiebewyse, en meer"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Meer privaatheidinstellings"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Outovul, aktiwiteitkontroles, en meer"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-am-v34/strings.xml b/SafetyCenter/Resources/res/values-am-v34/strings.xml
new file mode 100644
index 000000000..6b94d58ca
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-am-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="biometrics_title_for_work" msgid="1842284049407771568">"የሥራ ባዮሜትሪክስ"</string>
+ <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_search_terms" msgid="8414777373734245398">"ውሂብ፣ የውሂብ ማጋራት፣ የውሂብ ማጋራት ዝማኔዎች፣ የአካባቢ የውሂብ ማጋራት ዝማኔዎች፣ ማጋራት"</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-am/strings.xml b/SafetyCenter/Resources/res/values-am/strings.xml
index 36763bcc5..5d0914a79 100644
--- a/SafetyCenter/Resources/res/values-am/strings.xml
+++ b/SafetyCenter/Resources/res/values-am/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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="biometrics_title" msgid="5859504610285212938">"ባዮሜትሪክስ"</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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"ግላዊነት፣ የግላዊነት ቁጥጥሮች"</string>
<string name="advanced_title" msgid="8745436380690561172">"ተጨማሪ ቅንብሮች"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"ተጨማሪ የደህንነት ቅንብሮች"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"ምስጠራ፣ የመግቢያ ማስረጃዎች እና ሌሎችም"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"ተጨማሪ የግላዊነት ቅንብሮች"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"ራስ-ሙላ፣ የእንቅስቃሴ መቆጣጠሪያዎች እና ሌሎችም"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ar-v34/strings.xml b/SafetyCenter/Resources/res/values-ar-v34/strings.xml
new file mode 100644
index 000000000..4449b333c
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ar-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-ar/strings.xml
index b122c4587..2a97af99a 100644
--- a/SafetyCenter/Resources/res/values-ar/strings.xml
+++ b/SafetyCenter/Resources/res/values-ar/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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="biometrics_title" msgid="5859504610285212938">"المقاييس الحيوية"</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_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>
<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_summary" msgid="6172253327022425123">"التشفير وبيانات الاعتماد وغير ذلك"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"المزيد من إعدادات الخصوصية"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"الملء التلقائي وعناصر التحكُّم في النشاط وغير ذلك"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-as-v34/strings.xml b/SafetyCenter/Resources/res/values-as-v34/strings.xml
new file mode 100644
index 000000000..e8a084491
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-as-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-as/strings.xml
index 8cea99e78..94bf132fb 100644
--- a/SafetyCenter/Resources/res/values-as/strings.xml
+++ b/SafetyCenter/Resources/res/values-as/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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="biometrics_title" msgid="5859504610285212938">"বায়’মেট্ৰিক্স"</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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"গোপনীয়তা, গোপনীয়তাৰ নিয়ন্ত্ৰণ"</string>
<string name="advanced_title" msgid="8745436380690561172">"অধিক ছেটিং"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"সুৰক্ষা সম্পৰ্কীয় অধিক ছেটিং"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"এনক্ৰিপশ্বন, ক্ৰেডেনশ্বিয়েল আৰু বহুতো"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"গোপনীয়তাৰ অধিক ছেটিং"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"স্বয়ংক্ৰিয়ভাৱে পূৰ হোৱা সুবিধা, কাৰ্যকলাপৰ নিয়ন্ত্ৰণসমূহ আৰু বহুতো"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-az-v34/strings.xml b/SafetyCenter/Resources/res/values-az-v34/strings.xml
new file mode 100644
index 000000000..474dec23c
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-az-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Cihazın kiliddən çıxarılması"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"İş üçün biometrik seçimlər"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"İcazələr, panel, nizamlayıcılar"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-az/strings.xml
index 766367ef9..bf10a0f08 100644
--- a/SafetyCenter/Resources/res/values-az/strings.xml
+++ b/SafetyCenter/Resources/res/values-az/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Ekran kilidi"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Hələ ki, məlumat yoxdur"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Cihaz kilidi, Ekran kilidi, Kilid ekranı, Kilid ekranı, Parol, Pin, Model"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometriklər"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Barmaq izi, Barmaq, Barmaq izini əlavə edin, Üz ilə kiliddən çıxarın, Üz"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Məxfilik"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"İdarə paneli, icazələr, nəzarətlər"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Məxfilik paneli"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Hansı tətbiqlərin bu yaxınlarda icazələri istifadə etdiyini göstərin"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Məxfilik, Məxfilik paneli"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"İcazə meneceri"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Tətbiqin datanıza girişinə nəzarət edin"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"İcazələr, İcazə meneceri"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Məxfilik kontrolları"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Mikrofona, kameraya və daha çoxuna cihaz girişini idarə edin"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Məxfilik, Məxfilik nizamlayıcıları"</string>
<string name="advanced_title" msgid="8745436380690561172">"Digər ayarlar"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Digər güvənlik ayarları"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Şifrələmə, giriş məlumatları və s."</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Digər məxfilik ayarları"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Avto doldurma, fəaliyyətə nəzarət və s."</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></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
new file mode 100644
index 000000000..a61fc129a
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-b+sr+Latn-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Otključavanje uređaja"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometrija za posao"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Dozvole, kontrolna tabla, kontrole"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Povezivanje zdravlja"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-b+sr+Latn/strings.xml
index 7b44f8b39..c4328fe12 100644
--- a/SafetyCenter/Resources/res/values-b+sr+Latn/strings.xml
+++ b/SafetyCenter/Resources/res/values-b+sr+Latn/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"otisak prsta, prst, dodaj otisak prsta, otključavanje licem, lice"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privatnost"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Kontrolna tabla, dozvole, kontrole"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Kontrolna tabla za privatnost"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Prikazuje koje aplikacije su nedavno koristile dozvole"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"privatnost, kontrolna tabla za privatnost"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Menadžer dozvola"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Kontroliše pristup aplikacija podacima"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"dozvole, menadžer dozvola"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Kontrole privatnosti"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Kontroliše pristup uređaja mikrofonu, kameri i drugom"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"privatnost, kontrole privatnosti"</string>
<string name="advanced_title" msgid="8745436380690561172">"Još podešavanja"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Još bezbednosnih podešavanja"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Šifrovanje, akreditivi i drugo"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Još podešavanja privatnosti"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Automatsko popunjavanje, kontrole aktivnosti i drugo"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-be-v34/strings.xml b/SafetyCenter/Resources/res/values-be-v34/strings.xml
new file mode 100644
index 000000000..6c348b44c
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-be-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="biometrics_title_for_work" msgid="1842284049407771568">"Біяметрыя для працоўных праграм"</string>
+ <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_search_terms" msgid="8414777373734245398">"Даныя, абагульванне даных, Змяненні ў абагульванні даных, Змяненні ў абагульванні даных пра месцазнаходжанне, абагульванне"</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/strings.xml b/SafetyCenter/Resources/res/values-be/strings.xml
index 92706ee6a..b1d0b58cc 100644
--- a/SafetyCenter/Resources/res/values-be/strings.xml
+++ b/SafetyCenter/Resources/res/values-be/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Прыватнасць, налады прыватнасці"</string>
<string name="advanced_title" msgid="8745436380690561172">"Дадатковыя налады"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Іншыя налады бяспекі"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Шыфраванне, уліковыя даныя і іншыя звесткі"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Іншыя налады прыватнасці"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Аўтазапаўненне, адсочванне дзеянняў і іншыя функцыі"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-bg-v34/strings.xml b/SafetyCenter/Resources/res/values-bg-v34/strings.xml
new file mode 100644
index 000000000..4799cdaec
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-bg-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-bg/strings.xml
index 25fcd8cba..b9029d224 100644
--- a/SafetyCenter/Resources/res/values-bg/strings.xml
+++ b/SafetyCenter/Resources/res/values-bg/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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="biometrics_title" msgid="5859504610285212938">"Биометрика"</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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Поверителност, контроли за поверителност"</string>
<string name="advanced_title" msgid="8745436380690561172">"Още настройки"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Още настройки за сигурност"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Шифроване, идентификационни данни и др."</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Още настройки за поверителност"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Автоматично попълване, контроли за активността и др."</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-bn-v34/strings.xml b/SafetyCenter/Resources/res/values-bn-v34/strings.xml
new file mode 100644
index 000000000..02435f415
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-bn-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-bn/strings.xml
index 09f0e4f12..012f83055 100644
--- a/SafetyCenter/Resources/res/values-bn/strings.xml
+++ b/SafetyCenter/Resources/res/values-bn/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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="biometrics_title" msgid="5859504610285212938">"বায়োমেট্রিক্স"</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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"গোপনীয়তা, গোপনীয়তা নিয়ন্ত্রণ"</string>
<string name="advanced_title" msgid="8745436380690561172">"আরও সেটিংস"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"আরও নিরাপত্তা সেটিংস"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"এনক্রিপশন, ক্রেডেনশিয়াল এবং আরও অনেক কিছু"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"আরও গোপনীয়তা সেটিংস"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"অটোফিল, অ্যাক্টিভিটি নিয়ন্ত্রণ এবং আরও অনেক কিছু"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-bs-v34/strings.xml b/SafetyCenter/Resources/res/values-bs-v34/strings.xml
new file mode 100644
index 000000000..f863c8824
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-bs-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Otključavanje uređaja"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometrija za rad"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Odobrenja, kontrolna tabla, kontrole"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-bs/strings.xml
index 9ed383f88..f24d6415f 100644
--- a/SafetyCenter/Resources/res/values-bs/strings.xml
+++ b/SafetyCenter/Resources/res/values-bs/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Zaključavanje ekrana"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Još uvijek nema informacija"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"zaključavanje uređaja, zaključavanje ekrana, zaključan ekran, lozinka, pin, uzorak"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometrija"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"otisak prsta, prst, dodajte otisak prsta, otključavanje licem, lice"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privatnost"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Kontrolna tabla, odobrenja, kontrole"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Kontrolna tabla za privatnost"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Prikaz aplikacija koje su nedavno koristile odobrenja"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"privatnost, kontrolna tabla za privatnost"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Upravitelj odobrenja"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Kontrolirajte pristup aplikacija podacima"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"odobrenja, upravitelj odobrenja"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Kontrole privatnosti"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Kontrolirajte pristup uređaja mikrofonu, kameri i drugom"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"privatnost, kontrole privatnosti"</string>
<string name="advanced_title" msgid="8745436380690561172">"Više postavki"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Više postavki sigurnosti"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Šifriranje, akreditivi i drugo"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Više postavki privatnosti"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Automatsko popunjavanje, kontrole aktivnosti i drugo"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ca-v34/strings.xml b/SafetyCenter/Resources/res/values-ca-v34/strings.xml
new file mode 100644
index 000000000..fb88118fd
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ca-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Desbloqueig del dispositiu"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometria per al treball"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Permisos, tauler i controls"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Salut connectada"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-ca/strings.xml
index 7bea20b0d..97fb5f8be 100644
--- a/SafetyCenter/Resources/res/values-ca/strings.xml
+++ b/SafetyCenter/Resources/res/values-ca/strings.xml
@@ -18,21 +18,29 @@
<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>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Bloqueig de dispositius, bloqueig de pantalla, pantalla de bloqueig, contrasenya, PIN, patró"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometria"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Empremta digital, dit, afegir una empremta digital, desbloqueig facial, cara"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privadesa"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Tauler, permisos, controls"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Tauler de privadesa"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Mostra quines aplicacions han utilitzat permisos fa poc"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Privadesa, tauler de privadesa"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Gestor de permisos"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Controla l\'accés de les aplicacions a les teves dades"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Permisos, gestor de permisos"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Controls de privadesa"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Controla l\'accés del dispositiu al micròfon, la càmera i més"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privadesa, controls de privadesa"</string>
<string name="advanced_title" msgid="8745436380690561172">"Més opcions de configuració"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Més opcions de configuració de seguretat"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Encriptació, credencials i més"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Més opcions de configuració de privadesa"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Emplenament automàtic, controls d\'activitat i més"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-cs-v34/strings.xml b/SafetyCenter/Resources/res/values-cs-v34/strings.xml
new file mode 100644
index 000000000..4f9c811aa
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-cs-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Odemknutí zařízení"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometrie pro práci"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Oprávnění, panel, ovládací prvky"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-cs/strings.xml
index a898fe3f8..a980c789d 100644
--- a/SafetyCenter/Resources/res/values-cs/strings.xml
+++ b/SafetyCenter/Resources/res/values-cs/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Zámek obrazovky"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Zatím žádné údaje"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Zámek zařízení, Zámek obrazovky, Obrazovka uzamčení, Heslo, Pin, Gesto"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometrické údaje"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Otisk prstu, Prst, Přidat otisk prstu, Odemknutí obličejem, Obličej"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Ochrana soukromí"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Panel, oprávnění, ovládací prvky"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Panel ochrany soukromí"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Zobrazení aplikací, které v poslední době využívaly oprávnění"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Ochrana soukromí, Panel ochrany soukromí"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Správce oprávnění"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Ovládání přístupu aplikací k vašim datům"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Oprávnění, Správce oprávnění"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Nastavení ochrany soukromí"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Spravujte přístup zařízení k mikrofonu, fotoaparátu a dalším funkcím"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Ochrana soukromí, Nastavení ochrany soukromí"</string>
<string name="advanced_title" msgid="8745436380690561172">"Další nastavení"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Další nastavení zabezpečení"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Šifrování, přihlašovací údaje a další"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Další nastavení ochrany soukromí"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Automatické vyplňování, ovládací prvky aktivity a další"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-da-v34/strings.xml b/SafetyCenter/Resources/res/values-da-v34/strings.xml
new file mode 100644
index 000000000..d4dbdf7b9
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-da-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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 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="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/strings.xml b/SafetyCenter/Resources/res/values-da/strings.xml
index 941d7a4b6..59d275320 100644
--- a/SafetyCenter/Resources/res/values-da/strings.xml
+++ b/SafetyCenter/Resources/res/values-da/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Skærm­lås"</string>
<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, 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>
<string name="permission_usage_summary" msgid="5323079206029964468">"Vis, hvilke apps der har brugt tilladelser for nylig"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Privatliv, privatlivspanel"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Tilladelses­administrator"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Administrer appadgang til dine data"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Tilladelser, administration af tilladelser"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Privatlivsindstillinger"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Styr enhedens adgang til mikrofonen, kameraet og mere"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privatliv, privatlivsindstillinger"</string>
<string name="advanced_title" msgid="8745436380690561172">"Flere indstillinger"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Flere sikkerhedsindstillinger"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Kryptering, loginoplysninger og mere"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Flere privatlivsindstillinger"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Autofyld, aktivitetsadministration og mere"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-de-v34/strings.xml b/SafetyCenter/Resources/res/values-de-v34/strings.xml
new file mode 100644
index 000000000..4289c14a0
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-de-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Geräteentsperrung"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometrische Verfahren für geschäftliche Apps"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Berechtigungen, Dashboard, Einstellungen"</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">"Ä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="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/strings.xml b/SafetyCenter/Resources/res/values-de/strings.xml
index 59902e21c..8491f5adc 100644
--- a/SafetyCenter/Resources/res/values-de/strings.xml
+++ b/SafetyCenter/Resources/res/values-de/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Dis­play­sper­re"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Noch keine Daten erhalten"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Gerätesperre, Displaysperre, Sperrbildschirm, Lockscreen, Passwort, PIN, Muster"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometrisches Verfahren"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Fingerabdruck, Finger, Fingerabdruck hinzufügen, Entsperrung per Gesichtserkennung, Gesicht"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Datenschutz"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Dashboard, Berechtigungen, Einstellungen"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Privatsphäre­dashboard"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Anzeigen, welche Apps zuletzt Berechtigungen genutzt haben"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Privatsphäre, Privatsphäredashboard"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Berechtigungsmanager"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"App-Zugriff auf Daten festlegen"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Berechtigungen, Berechtigungsmanager"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Datenschutzeinstellungen"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Gerätezugriff auf Mikrofon, Kamera und mehr festlegen"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Datenschutz, Datenschutzeinstellungen"</string>
<string name="advanced_title" msgid="8745436380690561172">"Weitere Einstellungen"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Weitere Sicher­heits­einstellungen"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Verschlüsselung, Anmeldedaten und mehr"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Weitere Datenschutzeinstellungen"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Autofill, Aktivitätseinstellungen und mehr"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-el-v34/strings.xml b/SafetyCenter/Resources/res/values-el-v34/strings.xml
new file mode 100644
index 000000000..651f580eb
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-el-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-el/strings.xml
index 9bcf7e295..19e0a3b64 100644
--- a/SafetyCenter/Resources/res/values-el/strings.xml
+++ b/SafetyCenter/Resources/res/values-el/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Απόρρητο, στοιχεία ελέγχου απορρήτου"</string>
<string name="advanced_title" msgid="8745436380690561172">"Περισσότερες ρυθμίσεις"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Περισσότερες ρυθμίσεις ασφαλείας"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Κρυπτογράφηση, διαπιστευτήρια και περισσότερα"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Περισσότερες ρυθμίσεις απορρήτου"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Αυτόματη συμπλήρωση, στοιχεία ελέγχου δραστηριότητας και περισσότερα"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-en-rAU-v34/strings.xml b/SafetyCenter/Resources/res/values-en-rAU-v34/strings.xml
new file mode 100644
index 000000000..af32d279d
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-en-rAU-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Device unlock"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometrics for work"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Permissions, dashboard, controls"</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">"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="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-rAU/strings.xml b/SafetyCenter/Resources/res/values-en-rAU/strings.xml
index 4c5a9c77a..79d538664 100644
--- a/SafetyCenter/Resources/res/values-en-rAU/strings.xml
+++ b/SafetyCenter/Resources/res/values-en-rAU/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Screen lock"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"No info yet"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Device lock, Screen lock, Lock screen, Lockscreen, Password, Pin, Pattern"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometrics"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Fingerprint, Finger, Add fingerprint, Face unlock, Face"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privacy"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Dashboard, permissions, controls"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Privacy dashboard"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Show which apps recently used permissions"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Privacy, Privacy dashboard"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Permission manager"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Control app access to your data"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Permissions, Permissions manager"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Privacy controls"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Control device access to microphone, camera and more"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privacy, Privacy controls"</string>
<string name="advanced_title" msgid="8745436380690561172">"More settings"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"More security settings"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Encryption, credentials and more"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"More privacy settings"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Auto-fill, Activity controls and more"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-en-rCA-v34/strings.xml b/SafetyCenter/Resources/res/values-en-rCA-v34/strings.xml
new file mode 100644
index 000000000..05cc98e75
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-en-rCA-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Device unlock"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometrics for work"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Permissions, dashboard, controls"</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">"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="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/strings.xml b/SafetyCenter/Resources/res/values-en-rCA/strings.xml
index 36754e5cc..813a09061 100644
--- a/SafetyCenter/Resources/res/values-en-rCA/strings.xml
+++ b/SafetyCenter/Resources/res/values-en-rCA/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Screen lock"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"No info yet"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Device lock, Screen lock, Lock screen, Lockscreen, Password, Pin, Pattern"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometrics"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Fingerprint, Finger, Add fingerprint, Face unlock, Face"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privacy"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Dashboard, permissions, controls"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Privacy dashboard"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Show which apps recently used permissions"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Privacy, Privacy dashboard"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Permission manager"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Control app access to your data"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Permissions, Permissions manager"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Privacy controls"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Control device access to microphone, camera, and more"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privacy, Privacy controls"</string>
<string name="advanced_title" msgid="8745436380690561172">"More settings"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"More security settings"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Encryption, credentials, and more"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"More privacy settings"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Autofill, activity controls, and more"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-en-rGB-v34/strings.xml b/SafetyCenter/Resources/res/values-en-rGB-v34/strings.xml
new file mode 100644
index 000000000..af32d279d
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-en-rGB-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Device unlock"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometrics for work"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Permissions, dashboard, controls"</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">"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="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-rGB/strings.xml b/SafetyCenter/Resources/res/values-en-rGB/strings.xml
index 4c5a9c77a..79d538664 100644
--- a/SafetyCenter/Resources/res/values-en-rGB/strings.xml
+++ b/SafetyCenter/Resources/res/values-en-rGB/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Screen lock"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"No info yet"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Device lock, Screen lock, Lock screen, Lockscreen, Password, Pin, Pattern"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometrics"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Fingerprint, Finger, Add fingerprint, Face unlock, Face"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privacy"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Dashboard, permissions, controls"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Privacy dashboard"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Show which apps recently used permissions"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Privacy, Privacy dashboard"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Permission manager"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Control app access to your data"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Permissions, Permissions manager"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Privacy controls"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Control device access to microphone, camera and more"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privacy, Privacy controls"</string>
<string name="advanced_title" msgid="8745436380690561172">"More settings"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"More security settings"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Encryption, credentials and more"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"More privacy settings"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Auto-fill, Activity controls and more"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-en-rIN-v34/strings.xml b/SafetyCenter/Resources/res/values-en-rIN-v34/strings.xml
new file mode 100644
index 000000000..af32d279d
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-en-rIN-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Device unlock"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometrics for work"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Permissions, dashboard, controls"</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">"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="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-rIN/strings.xml b/SafetyCenter/Resources/res/values-en-rIN/strings.xml
index 4c5a9c77a..79d538664 100644
--- a/SafetyCenter/Resources/res/values-en-rIN/strings.xml
+++ b/SafetyCenter/Resources/res/values-en-rIN/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Screen lock"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"No info yet"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Device lock, Screen lock, Lock screen, Lockscreen, Password, Pin, Pattern"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometrics"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Fingerprint, Finger, Add fingerprint, Face unlock, Face"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privacy"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Dashboard, permissions, controls"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Privacy dashboard"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Show which apps recently used permissions"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Privacy, Privacy dashboard"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Permission manager"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Control app access to your data"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Permissions, Permissions manager"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Privacy controls"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Control device access to microphone, camera and more"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privacy, Privacy controls"</string>
<string name="advanced_title" msgid="8745436380690561172">"More settings"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"More security settings"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Encryption, credentials and more"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"More privacy settings"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Auto-fill, Activity controls and more"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-en-rXC-v34/strings.xml b/SafetyCenter/Resources/res/values-en-rXC-v34/strings.xml
new file mode 100644
index 000000000..f408d1fdb
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-en-rXC-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‎‏‏‎‎‏‎‎‏‎Device unlock‎‏‎‎‏‎"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‎‎‎‏‎‎‎‏‏‎‏‏‏‎‎‏‎‏‎‏‎‎‎‎‎‏‎‎‎‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‏‎‏‏‎‎‎‎‎Biometrics for work‎‏‎‎‏‎"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‏‏‎‎‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‏‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎Permissions, dashboard, controls‎‏‎‎‏‎"</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">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎‏‏‏‎‏‏‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‏‎‏‏‎‏‎‏‏‎‎‎‏‏‏‏‏‎‎‎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="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/strings.xml b/SafetyCenter/Resources/res/values-en-rXC/strings.xml
index f0093d594..66e9e135e 100644
--- a/SafetyCenter/Resources/res/values-en-rXC/strings.xml
+++ b/SafetyCenter/Resources/res/values-en-rXC/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‎‏‏‏‎‏‎‏‎‏‎‏‏‏‏‎‏‏‎‎‎‎‎‎‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‏‎‏‎‏‎‏‎Screen lock‎‏‎‎‏‎"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‎‏‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‎‎‏‏‏‏‏‎‏‎‎‎No info yet‎‏‎‎‏‎"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎‏‎‏‏‏‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎‏‎‏‏‎‎‏‏‎‎‏‏‎‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‏‎‏‎‎Device lock, Screen lock, Lock screen, Lockscreen, Password, Pin, Pattern‎‏‎‎‏‎"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‎‏‎‎‎‎‏‎‏‎‎Biometrics‎‏‎‎‏‎"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‎‎‎‏‎‎‏‎‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎Fingerprint, Finger, Add fingerprint, Face unlock, Face‎‏‎‎‏‎"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‏‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎Privacy‎‏‎‎‏‎"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‎‎‎‎‏‏‎‎‏‏‎‏‎‏‎‏‎‎‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‎‏‏‏‎‎‎‎‎‎Dashboard, permissions, controls‎‏‎‎‏‎"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‏‏‎‏‏‏‎‎‎‏‏‏‎‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‏‎Privacy dashboard‎‏‎‎‏‎"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‏‎‏‎‏‎‏‏‏‎‎‎‎‏‎‏‎‏‎‏‏‏‏‎‎‏‏‎‏‎‎‏‎‏‏‎‏‎‎‎Show which apps recently used permissions‎‏‎‎‏‎"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‏‎‏‏‎‎‏‎‎‎‏‏‎‎‎‎‏‎‏‏‎‎‏‎‎‏‏‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎‎‎‏‏‏‎‏‎‎‎‎‎Privacy, Privacy dashboard‎‏‎‎‏‎"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‏‎‏‏‎‎‏‏‏‎Permission manager‎‏‎‎‏‎"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‎‎‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‏‎‏‎‎‏‏‏‎‏‎‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‎Control app access to your data‎‏‎‎‏‎"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎‏‎‎‎‏‏‏‎‏‏‎‎‏‎‎‎‎‎‏‎‎‏‏‎‏‎‏‎‎‎‎‎‏‎‎Permissions, Permissions manager‎‏‎‎‏‎"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‏‎‎‎‏‎‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‎‏‏‎Privacy controls‎‏‎‎‏‎"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‎‏‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‏‎‎‎‎‎‎Control device access to microphone, camera, and more‎‏‎‎‏‎"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‎‎‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‎Privacy, Privacy controls‎‏‎‎‏‎"</string>
<string name="advanced_title" msgid="8745436380690561172">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‎‎‏‏‎‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‏‎‏‎‏‏‏‎‎‎‏‎‎‏‎‏‎‎‎More settings‎‏‎‎‏‎"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‏‎‎‎‎‏‏‏‏‎‎‏‏‏‎‎‎‏‏‏‎‏‎‎‏‎‏‎‏‎‏‏‎‏‎‏‏‏‏‏‏‏‎‏‏‎More security settings‎‏‎‎‏‎"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‎‏‏‏‎‎‏‎‏‎‎‎‎‎‏‎‎‎‎‏‎‎‎‏‏‎Encryption, credentials, and more‎‏‎‎‏‎"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‎‎‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎‏‎‏‎‏‏‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‎‎‏‏‎More privacy settings‎‏‎‎‏‎"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‏‎‏‏‎‎‏‏‎‎‏‎‏‏‎‏‏‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‎‏‏‎‎‏‏‏‎Autofill, activity controls, and more‎‏‎‎‏‎"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-es-rUS-v34/strings.xml b/SafetyCenter/Resources/res/values-es-rUS-v34/strings.xml
new file mode 100644
index 000000000..4158efa92
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-es-rUS-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Desbloqueo del dispositivo"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biométricos para apps de trabajo"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Permisos, panel, controles"</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">"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="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/strings.xml b/SafetyCenter/Resources/res/values-es-rUS/strings.xml
index 11478c6c1..f6465b2f1 100644
--- a/SafetyCenter/Resources/res/values-es-rUS/strings.xml
+++ b/SafetyCenter/Resources/res/values-es-rUS/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Bloqueo de pantalla"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Aún no hay información"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Desbloqueo del dispositivo, Bloqueo de pantalla, Pantalla de bloqueo, Pantalla bloqueada, Contraseña, PIN, Patrón"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Datos biométricos"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Huella dactilar, Dedo, Agregar huella dactilar, Desbloqueo facial, Rostro"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privacidad"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Panel, permisos, controles"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Panel de privacidad"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Muestra qué apps usaron permisos recientemente"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Privacidad, Panel de privacidad"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Administrador de permisos"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Controla el acceso de las apps a tus datos"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Permisos, Administrador de permisos"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Controles de privacidad"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Controla el acceso del dispositivo al micrófono, la cámara y más"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privacidad, Controles de privacidad"</string>
<string name="advanced_title" msgid="8745436380690561172">"Más parámetros de configuración"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Más parámetros de seguridad"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Encriptación, credenciales y más"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Más parámetros de privacidad"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Autocompletar, controles de actividad y más"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-es-v34/strings.xml b/SafetyCenter/Resources/res/values-es-v34/strings.xml
new file mode 100644
index 000000000..d03b74605
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-es-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Desbloqueo del dispositivo"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometría para el trabajo"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Permisos, panel de control y controles"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Salud conectada"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-es/strings.xml
index 27c20aeaf..6f7f380c3 100644
--- a/SafetyCenter/Resources/res/values-es/strings.xml
+++ b/SafetyCenter/Resources/res/values-es/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Bloqueo de pantalla"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Aún no hay información"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"bloqueo del dispositivo, bloqueo de pantalla, pantalla de bloqueo, contraseña, PIN, patrón"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometría"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"huella digital, huella, añadir huella digital, desbloqueo facial, cara"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privacidad"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Panel de control, permisos, controles"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Panel de privacidad"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Muestra qué aplicaciones han usado permisos recientemente"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"privacidad, panel de privacidad"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Gestor de permisos"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Controla el acceso de las aplicaciones a tus datos"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"permisos, gestor de permisos"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Controles de privacidad"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Controla el acceso del dispositivo al micrófono, la cámara y más"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"privacidad, controles de privacidad"</string>
<string name="advanced_title" msgid="8745436380690561172">"Más ajustes"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Más ajustes de seguridad"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Cifrado, credenciales y más"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Más ajustes de privacidad"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Autocompletar, controles de actividad y más"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-et-v34/strings.xml b/SafetyCenter/Resources/res/values-et-v34/strings.xml
new file mode 100644
index 000000000..914dcc54b
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-et-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Seadme avamine"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Töörakenduste biomeetriavalikud"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Load, juhtpaneel, juhtelemendid"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
+ <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="advanced_title" msgid="6259362998269627310">"Muud seaded"</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/strings.xml b/SafetyCenter/Resources/res/values-et/strings.xml
index f1500b276..a7ff48201 100644
--- a/SafetyCenter/Resources/res/values-et/strings.xml
+++ b/SafetyCenter/Resources/res/values-et/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Ekraanilukk"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Teavet ei ole veel"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Seadme lukustus, seadme lukustamine, ekraani lukustamine, ekraanilukk, lukustuskuva, parool, PIN, PIN-kood, muster"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biomeetria"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Sõrmejälg, sõrm, sõrmejälje lisamine, lisa sõrmejälg, näoga avamine, nägu"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privaatsus"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Juhtpaneel, load, juhtelemendid"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Privaatsuse juhtpaneel"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Vaadake, millised rakendused hiljuti lube kasutasid"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Privaatsus, privaatsuse juhtpaneel"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Lubade haldur"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Rakenduste puhul andmetele juurdepääsu haldamine"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Load, lubade haldur, lubade haldamine"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Privaatsuse seaded"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Seadme juurdepääsu haldamine mikrofonile, kaamerale ja muule"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privaatsus, privaatsuse seaded"</string>
<string name="advanced_title" msgid="8745436380690561172">"Rohkem seadeid"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Rohkem turvaseadeid"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Krüpteerimine, mandaadid ja muu"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Rohkem privaatsusseadeid"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Automaattäide, kontotegevuste haldus ja muu"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-eu-v34/strings.xml b/SafetyCenter/Resources/res/values-eu-v34/strings.xml
new file mode 100644
index 000000000..dae0daaab
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-eu-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Gailua desblokeatzea"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Laneko aplikazioetarako sistema biometrikoak"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-eu/strings.xml
index 9e4cf1a7b..78d067d8d 100644
--- a/SafetyCenter/Resources/res/values-eu/strings.xml
+++ b/SafetyCenter/Resources/res/values-eu/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Pantailaren blokeoa"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Ez dago informaziorik oraindik"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Gailua blokeatzeko eginbidea, Pantailaren blokeoa, Pantaila blokeatua, Pasahitza, PINa, Eredua"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Sistema biometrikoak"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Hatz-marka, Hatza, Gehitu hatz-marka, Aurpegi bidez desblokeatzeko eginbidea, Aurpegia"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Pribatutasuna"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Panela, baimenak, kontrolatzeko aukerak"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Pribatutasun-panela"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Erakutsi zein aplikaziok erabili dituzten baimenak azkenaldian"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Pribatutasuna, Pribatutasun-panela"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Baimenen kudeatzailea"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Kontrolatu aplikazioek datuak atzitzeko duten baimena"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Baimenak, Baimenen kudeatzailea"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Pribatutasun-ezarpenak"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Kontrolatu gailuak mikrofonoa, kamera eta abar atzitzeko dituen baimenak"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Pribatutasuna, Pribatutasun-ezarpenak"</string>
<string name="advanced_title" msgid="8745436380690561172">"Ezarpen gehiago"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Segurtasun-ezarpen gehiago"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Enkriptatzea, kredentzialak eta abar"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Pribatutasun-ezarpen gehiago"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Betetze automatikoa, jarduerak kontrolatzeko aukerak eta abar"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-fa-v34/strings.xml b/SafetyCenter/Resources/res/values-fa-v34/strings.xml
new file mode 100644
index 000000000..d8bf2b762
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-fa-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-fa/strings.xml
index 5b87ebded..41a3121ea 100644
--- a/SafetyCenter/Resources/res/values-fa/strings.xml
+++ b/SafetyCenter/Resources/res/values-fa/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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="biometrics_title" msgid="5859504610285212938">"زیست‌سنجشی"</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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"حریم خصوصی، تنظیمات حریم خصوصی"</string>
<string name="advanced_title" msgid="8745436380690561172">"تنظیمات بیشتر"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"تنظیمات امنیتی بیشتر"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"رمزگذاری، اطلاعات اعتباری، و غیره"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"تنظیمات حریم خصوصی بیشتر"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"تکمیل خودکار، کنترل‌های فعالیت، و غیره"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-fi-v34/strings.xml b/SafetyCenter/Resources/res/values-fi-v34/strings.xml
new file mode 100644
index 000000000..3b0f8300b
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-fi-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Laitteen lukituksen avaus"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometriikka työsovelluksissa"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Luvat, hallintapaneeli, asetukset"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-fi/strings.xml
index a61617c10..de46fb233 100644
--- a/SafetyCenter/Resources/res/values-fi/strings.xml
+++ b/SafetyCenter/Resources/res/values-fi/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Näytön lukitus"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Ei vielä tietoja"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Laitteen lukitus, näytön lukitus, lukitusnäyttö, salasana, PIN, kuvio"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometriikka"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Sormenjälki, sormi, lisää sormenjälki, kasvojentunnistusavaus, kasvot"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Yksityisyys"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Hallintapaneeli, luvat ja asetukset"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Yksityisyydenhallintapaneeli"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Näytä, mitkä sovellukset ovat käyttäneet lupia äskettäin"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Yksityisyys, yksityisyydenhallintapaneeli"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Lupien ylläpito"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Päätä sovelluksen pääsystä dataasi"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Luvat, lupien hallinta"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Yksityisyysasetukset"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Hallinnoi laitteiden pääsyä mikrofoniin, kameraan ja muihin"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Yksityisyys, yksityisyysasetukset"</string>
<string name="advanced_title" msgid="8745436380690561172">"Lisää asetuksia"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Lisää tietoturva-asetuksia"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Salaus, kirjautumistiedot ja muuta"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Lisää yksityisyysasetuksia"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Automaattinen täyttö, toimintojen hallinta ja muuta"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-fr-rCA-v34/strings.xml b/SafetyCenter/Resources/res/values-fr-rCA-v34/strings.xml
new file mode 100644
index 000000000..f1a8ad068
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-fr-rCA-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Déverrouillage de l\'appareil"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Données biométriques pour le travail"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Autorisations, tableau de bord, commandes"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Connexion santé"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-fr-rCA/strings.xml
index 5bc5b72ed..a835c7139 100644
--- a/SafetyCenter/Resources/res/values-fr-rCA/strings.xml
+++ b/SafetyCenter/Resources/res/values-fr-rCA/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Verrouillage de l\'écran"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Aucune donnée pour le moment"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Verrouillage d\'appareil, Verrouillage de l\'écran, Verrouiller l\'écran, Écran de verrouillage, Mot de passe, Nip, Schéma"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Données biométriques"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Empreinte digitale, Doigt, Ajouter une empreinte digitale, Déverrouillage par reconnaissance faciale, Visage"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Confidentialité"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Tableau de bord, autorisations, commandes"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Tableau de bord de confidentialité"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Affichez les applications qui ont récemment utilisé les autorisations"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Confidentialité, Tableau de bord de confidentialité"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Gestionnaire des autorisations"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Gérez l\'accès des applications à vos données"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Autorisations, Gestionnaire des autorisations"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Paramètres de confidentialité"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Contrôlez l\'accès de l\'appareil au microphone, à l\'appareil photo, etc."</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Confidentialité, Paramètres de confidentialité"</string>
<string name="advanced_title" msgid="8745436380690561172">"Plus de paramètres"</string>
<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 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
new file mode 100644
index 000000000..92af5db49
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-fr-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Déverrouillage de l\'appareil"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biométrie pour applis pro"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Autorisations, tableau de bord, commandes"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Santé Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-fr/strings.xml
index 81e6a03c6..ef0d893ae 100644
--- a/SafetyCenter/Resources/res/values-fr/strings.xml
+++ b/SafetyCenter/Resources/res/values-fr/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Verrouillage de l\'écran"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Aucune info pour l\'instant"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"verrouillage de l\'appareil, verrouillage de l\'écran, écran de verrouillage, mot de passe, code, schéma"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biométrie"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"empreinte digitale, doigt, ajouter une empreinte, déverrouillage par reconnaissance faciale, visage"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Confidentialité"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Tableau de bord, autorisations, commandes"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Tableau de bord Confidentialité"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Afficher les applis qui ont récemment utilisé des autorisations"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"confidentialité, tableau de bord confidentialité"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Gestionnaire d\'autorisations"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Contrôler l\'accès des applis à vos données"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"autorisations, gestionnaire d\'autorisations"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Paramètres de confidentialité"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Contrôlez l\'accès de l\'appareil au micro, à l\'appareil photo et bien plus"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"confidentialité, paramètres de confidentialité"</string>
<string name="advanced_title" msgid="8745436380690561172">"Plus de paramètres"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Autres paramètres de sécurité"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Chiffrement, identifiants et plus"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Autres paramètres de confidentialité"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Saisie automatique, commandes relatives à l\'activité et bien plus"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-gl-v34/strings.xml b/SafetyCenter/Resources/res/values-gl-v34/strings.xml
new file mode 100644
index 000000000..16f9f9781
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-gl-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Desbloqueo do dispositivo"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Datos biométricos para o traballo"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Permisos, panel de control, controis"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Saúde conectada"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-gl/strings.xml
index 598996550..7ae87b9f3 100644
--- a/SafetyCenter/Resources/res/values-gl/strings.xml
+++ b/SafetyCenter/Resources/res/values-gl/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Bloqueo de pantalla"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Aínda non hai información"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Bloqueo do dispositivo, bloqueo de pantalla, pantalla de bloqueo, contrasinal, PIN, padrón"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Datos biométricos"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Impresión dixital, dedo, engadir impresión dixital, desbloqueo facial, cara"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privacidade"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Panel de control, permisos e controis"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Panel de privacidade"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Mostra as aplicacións que usaron permisos recentemente"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Privacidade, panel de privacidade"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Xestor de permisos"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Controla o acceso das aplicacións aos datos"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Permisos, xestor de permisos"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Controis de privacidade"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Controla o acceso dos dispositivos ao micrófono, á cámara e moito máis"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privacidade, controis de privacidade"</string>
<string name="advanced_title" msgid="8745436380690561172">"Máis opcións de configuración"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Máis opcións de configuración de seguranza"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Encriptación, credenciais e moito máis"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Máis opcións de configuración de privacidade"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Autocompletar, controis de actividade e moito máis"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-gu-v34/strings.xml b/SafetyCenter/Resources/res/values-gu-v34/strings.xml
new file mode 100644
index 000000000..0517fad28
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-gu-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-gu/strings.xml
index 14ef562cf..e44aa5bc8 100644
--- a/SafetyCenter/Resources/res/values-gu/strings.xml
+++ b/SafetyCenter/Resources/res/values-gu/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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="biometrics_title" msgid="5859504610285212938">"બાયોમેટ્રિક્સ"</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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"પ્રાઇવસી, પ્રાઇવસીને લગતાં નિયંત્રણ"</string>
<string name="advanced_title" msgid="8745436380690561172">"વધુ સેટિંગ"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"વધુ સુરક્ષા સેટિંગ"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"એન્ક્રિપ્શન, લૉગ ઇન વિગત અને વધુ"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"વધુ પ્રાઇવસી સેટિંગ"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"આપમેળે ભરવાની સુવિધા, ઍક્ટિવિટી કન્ટ્રોલ અને વધુ"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-hi-v34/strings.xml b/SafetyCenter/Resources/res/values-hi-v34/strings.xml
new file mode 100644
index 000000000..3a941dc97
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-hi-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="app_data_sharing_updates_title" msgid="7428862330643262588">"जगह की जानकारी शेयर करने के तरीके के बारे में अपडेट"</string>
+ <string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"डेटा, डेटा शेयर करना, डेटा शेयर करने के अपडेट, जगह की जानकारी शेयर करने के बारे में अपडेट, शेयर करना"</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/strings.xml b/SafetyCenter/Resources/res/values-hi/strings.xml
index 63c872b99..419f775d1 100644
--- a/SafetyCenter/Resources/res/values-hi/strings.xml
+++ b/SafetyCenter/Resources/res/values-hi/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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="biometrics_title" msgid="5859504610285212938">"बायोमेट्रिक्स"</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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"निजता, निजता सेटिंग"</string>
<string name="advanced_title" msgid="8745436380690561172">"अन्य सेटिंग"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"सुरक्षा से जुड़ी और सेटिंग"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"एन्क्रिप्शन, क्रेडेंशियल वगैरह"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"निजता से जुड़ी और सेटिंग"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"ऑटोमैटिक जानकारी भरना, गतिविधि कंट्रोल वगैरह"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-hr-v34/strings.xml b/SafetyCenter/Resources/res/values-hr-v34/strings.xml
new file mode 100644
index 000000000..ef467b89b
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-hr-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Otključavanje uređaja"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometrijski podaci za posao"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Dopuštenja, nadzorna ploča, kontrole"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-hr/strings.xml
index 86b1b3616..7306fcc76 100644
--- a/SafetyCenter/Resources/res/values-hr/strings.xml
+++ b/SafetyCenter/Resources/res/values-hr/strings.xml
@@ -22,17 +22,25 @@
<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č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">"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 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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privatnost, kontrole privatnosti"</string>
<string name="advanced_title" msgid="8745436380690561172">"Više postavki"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Više sigurnosnih postavki"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Šifriranje, vjerodajnice i ostalo"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Više postavki privatnosti"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Automatsko popunjavanje, kontrole aktivnosti i ostalo"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-hu-v34/strings.xml b/SafetyCenter/Resources/res/values-hu-v34/strings.xml
new file mode 100644
index 000000000..811e192cb
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-hu-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Eszköz feloldása"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometriai adatok munkahelyi alkalmazásoknál"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Engedélyek, irányítópult, vezérlők"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-hu/strings.xml
index e373663e3..e0a7087ef 100644
--- a/SafetyCenter/Resources/res/values-hu/strings.xml
+++ b/SafetyCenter/Resources/res/values-hu/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Képernyőzár"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Még nincsenek adatok"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Eszköz zárolása, Képernyőzár, Lezárási képernyő, Képernyő zárása, Jelszó, PIN-kód, Minta"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometria"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Ujjlenyomat, Ujj, Ujjlenyomat hozzáadása, Arcalapú feloldás, Arc"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Adatvédelem"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Irányítópult, engedélyek, vezérlők"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Adatvédelmi irányítópult"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Az engedélyeket a közelmúltban használó alkalmazások megjelenítése"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Adatvédelem, Adatvédelmi irányítópult"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Engedélykezelő"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Az adataihoz hozzáférő alkalmazások kezelése"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Engedély, Engedélykezelő"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Adatvédelmi beállítások"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Az eszköz mikrofonhoz, kamerához és egyebekhez való hozzáférésének vezérlése"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Adatvédelem, Adatvédelmi beállítások"</string>
<string name="advanced_title" msgid="8745436380690561172">"További beállítások"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"További biztonsági beállítások"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Titkosítás, hitelesítési adatok és egyebek"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"További adatvédelmi beállítások"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Automatikus kitöltés, tevékenységvezérlők és egyebek"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-hy-v34/strings.xml b/SafetyCenter/Resources/res/values-hy-v34/strings.xml
new file mode 100644
index 000000000..158cec7c0
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-hy-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="app_data_sharing_updates_title" msgid="7428862330643262588">"Տեղադրության մասին տվյալներով կիսվելու թույլտվության թարմացում"</string>
+ <string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Տվյալներ, Տվյալների փոխանցում, Տվյալներով կիսվելու եղանակի փոփոխություն, Տեղադրության մասին տվյալներով կիսվելու թույլտվության թարմացում, փոխանցում"</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/strings.xml b/SafetyCenter/Resources/res/values-hy/strings.xml
index 98f9f7955..426ebfa00 100644
--- a/SafetyCenter/Resources/res/values-hy/strings.xml
+++ b/SafetyCenter/Resources/res/values-hy/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Գաղտնիություն, Գաղտնիության կարգավորումներ"</string>
<string name="advanced_title" msgid="8745436380690561172">"Այլ կարգավորումներ"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Անվտանգության այլ կարգավորումներ"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Գաղտնագրում, մուտքի տվյալներ և ավելին"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Գաղտնիության այլ կարգավորումներ"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Ինքնալրացում, գործողությունների հետագծում և ավելին"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-in-v34/strings.xml b/SafetyCenter/Resources/res/values-in-v34/strings.xml
new file mode 100644
index 000000000..9d375e022
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-in-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Pembuka kunci perangkat"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometrik untuk aplikasi kerja"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Izin, dasbor, kontrol"</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">"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="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/strings.xml b/SafetyCenter/Resources/res/values-in/strings.xml
index 044476585..d5579aa32 100644
--- a/SafetyCenter/Resources/res/values-in/strings.xml
+++ b/SafetyCenter/Resources/res/values-in/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Kunci layar"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Belum ada info"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Penguncian perangkat, Kunci layar, Layar kunci, Layar saat dikunci, Sandi, PIN, Pola"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometrik"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Sidik jari, Jari, Tambahkan sidik jari, Buka dengan wajah, Wajah"</string>
<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">"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">"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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privasi, Kontrol privasi"</string>
<string name="advanced_title" msgid="8745436380690561172">"Setelan lainnya"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Setelan keamanan lainnya"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Enkripsi, kredensial, dan lainnya"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Setelan privasi lainnya"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Isi otomatis, kontrol aktivitas, dan lainnya"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-is-v34/strings.xml b/SafetyCenter/Resources/res/values-is-v34/strings.xml
new file mode 100644
index 000000000..6533a7ac3
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-is-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Taka tæki úr lás"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Lífkenni fyrir vinnu"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Heimildir, stjórnborð, stýringar"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Heilsutenging"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-is/strings.xml
index 39a788096..c462e5c15 100644
--- a/SafetyCenter/Resources/res/values-is/strings.xml
+++ b/SafetyCenter/Resources/res/values-is/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Skjálás"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Engar upplýsingar ennþá"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Tækjalás, Skjálás, Læsa skjá, Lásskjár, Aðgangsorð, PIN-númer, Mynstur"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Lífkenni"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Fingrafar, Fingur, Bæta við fingrafari, Andlitskenni, Andlit"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Persónuvernd"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Stjórnborð, heimildir, stýringar"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Persónuverndarstjórnborð"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Sýna hvaða forrit notuðu heimildir nýlega"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Persónuvernd, Persónuverndarstjórnborð"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Heimildastjóri"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Stjórna aðgangi forrita að gögnunum þínum"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Heimildir, Heimildastjóri"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Persónuverndarstillingar"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Stjórna tækjaaðgangi að hljóðnema, myndavél og fleiru"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Persónuvernd, Persónuverndarstillingar"</string>
<string name="advanced_title" msgid="8745436380690561172">"Fleiri stillingar"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Fleiri öryggisstillingar"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Dulkóðun, skilríki og fleira"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Fleiri persónuverndarstillingar"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Sjálfvirk útfylling, virknistýringar og fleira"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-it-v34/strings.xml b/SafetyCenter/Resources/res/values-it-v34/strings.xml
new file mode 100644
index 000000000..ffbb82c41
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-it-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Sblocco dispositivo"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometria per il lavoro"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Autorizzazioni, dashboard e controlli"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Connessione Salute"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-it/strings.xml
index 02798c09e..b3ff1668c 100644
--- a/SafetyCenter/Resources/res/values-it/strings.xml
+++ b/SafetyCenter/Resources/res/values-it/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Blocco schermo"</string>
<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="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>
<string name="permission_usage_summary" msgid="5323079206029964468">"Mostra quali app hanno usato le autorizzazioni di recente"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Privacy, Dashboard della privacy"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Gestione autorizzazioni"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Controlla l\'accesso delle app ai tuoi dati"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Autorizzazioni, Gestore autorizzazioni"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Controlli per la privacy"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Controlla l\'accesso del dispositivo a microfono, fotocamera e altro"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privacy, Controlli per la privacy"</string>
<string name="advanced_title" msgid="8745436380690561172">"Altre impostazioni"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Altre impostazioni di sicurezza"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Crittografia, credenziali e altro"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Altre impostazioni della privacy"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Compilazione automatica, Gestione attività e altro"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-iw-v34/strings.xml b/SafetyCenter/Resources/res/values-iw-v34/strings.xml
new file mode 100644
index 000000000..43296d1bf
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-iw-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-iw/strings.xml
index 103edd5d1..bde0d294b 100644
--- a/SafetyCenter/Resources/res/values-iw/strings.xml
+++ b/SafetyCenter/Resources/res/values-iw/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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, קוד PIN, קו ביטול נעילה, קו ביטול, דפוס"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"מידע ביומטרי"</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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"פרטיות, אמצעי בקרה על פרטיות"</string>
<string name="advanced_title" msgid="8745436380690561172">"הגדרות נוספות"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"הגדרות אבטחה נוספות"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"הצפנה, פרטי כניסה ועוד"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"הגדרות פרטיות נוספות"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"מילוי אוטומטי, בקרת הפעילות בחשבון ועוד"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ja-v34/strings.xml b/SafetyCenter/Resources/res/values-ja-v34/strings.xml
new file mode 100644
index 000000000..8a49d1667
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ja-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="biometrics_title_for_work" msgid="1842284049407771568">"仕事用の生体認証"</string>
+ <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_search_terms" msgid="8414777373734245398">"データ, データ 共有, データ 共有 更新, データ 共有 更新 位置情報, 共有"</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/strings.xml b/SafetyCenter/Resources/res/values-ja/strings.xml
index db40b4f9a..6e67998f4 100644
--- a/SafetyCenter/Resources/res/values-ja/strings.xml
+++ b/SafetyCenter/Resources/res/values-ja/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"プライバシー, プライバシー管理"</string>
<string name="advanced_title" msgid="8745436380690561172">"詳細設定"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"セキュリティの詳細設定"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"暗号化、認証情報など"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"プライバシーの詳細設定"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"自動入力、アクティビティ管理など"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ka-v34/strings.xml b/SafetyCenter/Resources/res/values-ka-v34/strings.xml
new file mode 100644
index 000000000..97e2afc2d
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ka-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="app_data_sharing_updates_title" msgid="7428862330643262588">"მონაცემების გაზიარების განახლებები მდებარეობისთვის"</string>
+ <string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"მონაცემები, მონაცემების გაზიარება, მონაცემების გაზიარების განახლებები, მონაცემების გაზიარების განახლებები მდებარეობისთვის, გაზიარება"</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/strings.xml b/SafetyCenter/Resources/res/values-ka/strings.xml
index 6c5a12a50..af3e7cd29 100644
--- a/SafetyCenter/Resources/res/values-ka/strings.xml
+++ b/SafetyCenter/Resources/res/values-ka/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"კონფიდენციალურობა, კონფიდენციალურობის მართვის პარამეტრები"</string>
<string name="advanced_title" msgid="8745436380690561172">"დამატებითი პარამეტრები"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"უსაფრთხოების დამატებითი პარამეტრები"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"დაშიფვრა, ავტორიზაციის მონაცემები და სხვა"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"კონფიდენციალურობის დამატებითი პარამეტრები"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"ავტომატური შევსება, აქტივობის მართვის საშუალებები და სხვა"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-kk-v34/strings.xml b/SafetyCenter/Resources/res/values-kk-v34/strings.xml
new file mode 100644
index 000000000..1efaa3f6b
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-kk-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-kk/strings.xml
index 95ab8e67c..79b5204fa 100644
--- a/SafetyCenter/Resources/res/values-kk/strings.xml
+++ b/SafetyCenter/Resources/res/values-kk/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Құпиялық, құпиялық параметрлері"</string>
<string name="advanced_title" msgid="8745436380690561172">"Қосымша параметрлер"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Қосымша қауіпсіздік параметрлері"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Шифрлау, тіркелу деректері және т. б."</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Қосымша құпиялық параметрлері"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Автотолтыру, іс-әрекетті басқару элементтері және т. б."</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-km-v34/strings.xml b/SafetyCenter/Resources/res/values-km-v34/strings.xml
new file mode 100644
index 000000000..df7009b2e
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-km-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-km/strings.xml
index f0a6b1a86..be8b2369d 100644
--- a/SafetyCenter/Resources/res/values-km/strings.xml
+++ b/SafetyCenter/Resources/res/values-km/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"ឯកជនភាព, ការគ្រប់គ្រង​ឯកជនភាព"</string>
<string name="advanced_title" msgid="8745436380690561172">"ការកំណត់ច្រើនទៀត"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"ការកំណត់សុវត្ថិភាពច្រើនទៀត"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"ការអ៊ីនគ្រីប ព័ត៌មានផ្ទៀងផ្ទាត់ និងអ្វីៗជាច្រើនទៀត"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"ការកំណត់ឯកជនភាព​ច្រើនទៀត"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"បំពេញស្វ័យប្រវត្តិ ការត្រួតពិនិត្យសកម្មភាព និងអ្វីៗជាច្រើនទៀត"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-kn-v34/strings.xml b/SafetyCenter/Resources/res/values-kn-v34/strings.xml
new file mode 100644
index 000000000..19dcdad15
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-kn-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-kn/strings.xml
index 7d5f81a0b..2e912b475 100644
--- a/SafetyCenter/Resources/res/values-kn/strings.xml
+++ b/SafetyCenter/Resources/res/values-kn/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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="biometrics_title" msgid="5859504610285212938">"ಬಯೋಮೆಟ್ರಿಕ್ಸ್"</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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"ಗೌಪ್ಯತೆ, ಗೌಪ್ಯತೆ ನಿಯಂತ್ರಣಗಳು"</string>
<string name="advanced_title" msgid="8745436380690561172">"ಇನ್ನಷ್ಟು ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"ಇನ್ನಷ್ಟು ಭದ್ರತಾ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"ಎನ್‌ಕ್ರಿಪ್ಶನ್, ರುಜುವಾತುಗಳು ಹಾಗೂ ಇನ್ನಷ್ಟು"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"ಇನ್ನಷ್ಟು ಗೌಪ್ಯತೆ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"ಸ್ವಯಂ ಭರ್ತಿ, ಚಟುವಟಿಕೆ ನಿಯಂತ್ರಣಗಳು ಹಾಗೂ ಇನ್ನಷ್ಟು"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ko-v34/strings.xml b/SafetyCenter/Resources/res/values-ko-v34/strings.xml
new file mode 100644
index 000000000..347b46bdb
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ko-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="biometrics_title_for_work" msgid="1842284049407771568">"직장 앱용 생체 인식"</string>
+ <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_search_terms" msgid="8414777373734245398">"데이터, 데이터 공유, 데이터 공유 업데이트, 위치 관련 데이터 공유 업데이트, 공유"</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/strings.xml b/SafetyCenter/Resources/res/values-ko/strings.xml
index 868d71e3d..307f69d11 100644
--- a/SafetyCenter/Resources/res/values-ko/strings.xml
+++ b/SafetyCenter/Resources/res/values-ko/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"개인 정보, 개인 정보 보호 설정"</string>
<string name="advanced_title" msgid="8745436380690561172">"기타 설정"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"기타 보안 설정"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"암호화, 사용자 인증 정보 등"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"기타 개인 정보 보호 설정"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"자동 완성, 활동 제어 등"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ky-v34/strings.xml b/SafetyCenter/Resources/res/values-ky-v34/strings.xml
new file mode 100644
index 000000000..9d4a1ede9
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ky-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-ky/strings.xml
index 9f36043b5..ca605b018 100644
--- a/SafetyCenter/Resources/res/values-ky/strings.xml
+++ b/SafetyCenter/Resources/res/values-ky/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Купуялык, Купуялыкты көзөмөлдөө каражаттары"</string>
<string name="advanced_title" msgid="8745436380690561172">"Дагы параметрлер"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Кошумча коопсуздук параметрлери"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Шифрлөө, аккаунтка байланыштуу нерселер жана башкалар"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Кошумча купуялык параметрлери"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Автотолтуруу, аракеттерге көз салуу жана башкалар"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-lo-v34/strings.xml b/SafetyCenter/Resources/res/values-lo-v34/strings.xml
new file mode 100644
index 000000000..fe18b3024
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-lo-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-lo/strings.xml
index 11c3eda29..44f09d49a 100644
--- a/SafetyCenter/Resources/res/values-lo/strings.xml
+++ b/SafetyCenter/Resources/res/values-lo/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"ຄວາມເປັນສ່ວນຕົວ, ການຄວບຄຸມຄວາມເປັນສ່ວນຕົວ"</string>
<string name="advanced_title" msgid="8745436380690561172">"ການຕັ້ງຄ່າເພີ່ມເຕີມ"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"ການຕັ້ງຄ່າຄວາມປອດໄພເພີ່ມເຕີມ"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"ການເຂົ້າລະຫັດ, ຂໍ້ມູນການເຂົ້າສູ່ລະບົບ ແລະ ອື່ນໆ"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"ການຕັ້ງຄ່າຄວາມເປັນສ່ວນຕົວເພີ່ມເຕີມ"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"ການຕື່ມຂໍ້ມູນອັດຕະໂນມັດ, ການຄວບຄຸມການເຄື່ອນໄຫວ ແລະ ອື່ນໆ"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-lt-v34/strings.xml b/SafetyCenter/Resources/res/values-lt-v34/strings.xml
new file mode 100644
index 000000000..ffe1d55e0
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-lt-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Įrenginio atrakinimo funkcija"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Darbo biometrinės sistemos"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Leidimai, informacijos suvestinė, valdikliai"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-lt/strings.xml
index 7740fe428..349ee745c 100644
--- a/SafetyCenter/Resources/res/values-lt/strings.xml
+++ b/SafetyCenter/Resources/res/values-lt/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Ekrano užraktas"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Kol kas informacijos nėra"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Įrenginio užraktas, ekrano užraktas, užrakinimo ekranas, užrakinti ekraną, slaptažodis, PIN kodas, atrakinimo piešinys"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometrinės sistemos"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Kontrolinis kodas, pirštas, pridėti kontrolinį kodą, atrakinimas pagal veidą, veidas"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privatumas"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Informacijos suvestinė, leidimai, valdikliai"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Privatumo informacijos suvestinė"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Rodyti, kurios programos neseniai naudojo leidimus"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Privatumas, privatumo informacijos suvestinė"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Leidimų tvarkytuvė"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Valdykite programų prieigą prie duomenų"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Leidimai, leidimų tvarkytuvė"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Privatumo valdikliai"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Valdykite įrenginio prieigą prie mikrofono, kameros ir kt."</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privatumas, privatumo valdikliai"</string>
<string name="advanced_title" msgid="8745436380690561172">"Daugiau nustatymų"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Daugiau saugos nustatymų"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Šifruotė, prisijungimo duomenys ir kt."</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Daugiau privatumo nustatymų"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Automatinis pildymas, veiklos valdikliai ir kt."</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-lv-v34/strings.xml b/SafetyCenter/Resources/res/values-lv-v34/strings.xml
new file mode 100644
index 000000000..b6f5238c2
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-lv-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Ierīces atbloķēšana"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometrijas dati darba lietotnēm"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Atļaujas, informācijas panelis, vadīklas"</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">"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="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/strings.xml b/SafetyCenter/Resources/res/values-lv/strings.xml
index 222333a42..b6e7a3274 100644
--- a/SafetyCenter/Resources/res/values-lv/strings.xml
+++ b/SafetyCenter/Resources/res/values-lv/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Ekrāna bloķēšana"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Vēl nav informācijas"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Ierīces bloķēšana, ekrāna bloķēšana, bloķēšanas ekrāns, parole, PIN, kombinācija"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometrija"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Pirksta nospiedums, pirksts, pievienot pirksta nospiedumu, autorizācija pēc sejas, seja"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Konfidencialitāte"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Informācijas panelis, atļaujas, vadīklas"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Konfidencialitātes informācijas panelis"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Skatiet, kuras lietotnes nesen izmantoja atļaujas"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Konfidencialitāte, konfidencialitātes informācijas panelis"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Atļauju pārvaldnieks"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Pārvaldiet lietotņu piekļuvi jūsu datiem"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Atļaujas, atļauju pārvaldnieks"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Konfidencialitātes vadīklas"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Kontrolējiet ierīces piekļuvi mikrofonam, kamerai un citām funkcijām"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Konfidencialitāte, konfidencialitātes vadīklas"</string>
<string name="advanced_title" msgid="8745436380690561172">"Citi iestatījumi"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Citi drošības iestatījumi"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Šifrēšana, akreditācijas dati un citi iestatījumi"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Citi konfidencialitātes iestatījumi"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Automātiskā aizpilde, aktivitātes vadīklas un citas iestatījumi"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-mk-v34/strings.xml b/SafetyCenter/Resources/res/values-mk-v34/strings.xml
new file mode 100644
index 000000000..b3c1db290
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-mk-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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-mk/strings.xml b/SafetyCenter/Resources/res/values-mk/strings.xml
index 62814260b..2b2414d0d 100644
--- a/SafetyCenter/Resources/res/values-mk/strings.xml
+++ b/SafetyCenter/Resources/res/values-mk/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Приватност, Контроли на приватноста"</string>
<string name="advanced_title" msgid="8745436380690561172">"Повеќе поставки"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Повеќе поставки за безбедност"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Шифрирање, акредитиви и друго"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Повеќе поставки за приватност"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Автоматско пополнување, контроли на активноста и друго"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ml-v34/strings.xml b/SafetyCenter/Resources/res/values-ml-v34/strings.xml
new file mode 100644
index 000000000..a53898e00
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ml-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="app_data_sharing_updates_title" msgid="7428862330643262588">"ലൊക്കേഷൻ ഡാറ്റ പങ്കിടുന്നത് സംബന്ധിച്ച അപ്‌ഡേറ്റുകൾ"</string>
+ <string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"ഡാറ്റ, ഡാറ്റ പങ്കിടൽ, ഡാറ്റ പങ്കിടൽ അപ്‌ഡേറ്റുകൾ, ലൊക്കേഷനുമായി ബന്ധപ്പെട്ട ഡാറ്റ പങ്കിടൽ അപ്ഡേറ്റുകൾ, പങ്കിടൽ"</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/strings.xml b/SafetyCenter/Resources/res/values-ml/strings.xml
index 8a38606d3..cec33026f 100644
--- a/SafetyCenter/Resources/res/values-ml/strings.xml
+++ b/SafetyCenter/Resources/res/values-ml/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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="biometrics_title" msgid="5859504610285212938">"ബയോമെട്രിക്‌സ്"</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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"സ്വകാര്യത, സ്വകാര്യതാ നിയന്ത്രണങ്ങൾ"</string>
<string name="advanced_title" msgid="8745436380690561172">"കൂടുതൽ ക്രമീകരണം"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"കൂടുതൽ സുരക്ഷാ ക്രമീകരണം"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"എൻക്രിപ്ഷൻ, ക്രെഡൻഷ്യലുകൾ എന്നിവയും മറ്റും"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"കൂടുതൽ സ്വകാര്യതാ ക്രമീകരണം"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"സ്വയമേവ പൂരിപ്പിക്കൽ, ആക്റ്റിവിറ്റി നിയന്ത്രണങ്ങൾ എന്നിവയും മറ്റും"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-mn-v34/strings.xml b/SafetyCenter/Resources/res/values-mn-v34/strings.xml
new file mode 100644
index 000000000..2f498893b
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-mn-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="app_data_sharing_updates_title" msgid="7428862330643262588">"Байршлын өгөгдөл хуваалцах шинэчлэлт"</string>
+ <string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"Өгөгдөл, өгөгдөл хуваалцах, өгөгдөл хуваалцах шинэчлэлт, байршлын өгөгдөл хуваалцах шинэчлэлт, хуваалцах"</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/strings.xml b/SafetyCenter/Resources/res/values-mn/strings.xml
index a2e2497fd..e7c9516e6 100644
--- a/SafetyCenter/Resources/res/values-mn/strings.xml
+++ b/SafetyCenter/Resources/res/values-mn/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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="biometrics_title" msgid="5859504610285212938">"Биометр"</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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Нууцлал, Нууцлалын тохиргоо"</string>
<string name="advanced_title" msgid="8745436380690561172">"Бусад тохиргоо"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Аюулгүй байдлын бусад тохиргоо"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Шифрлэлт, мандат үнэмлэх болон бусад"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Нууцлалын бусад тохиргоо"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Автоматаар бөглөх хэсэг, үйл ажиллагааны хяналт болон бусад"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-mr-v34/strings.xml b/SafetyCenter/Resources/res/values-mr-v34/strings.xml
new file mode 100644
index 000000000..f2d620adc
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-mr-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="app_data_sharing_updates_title" msgid="7428862330643262588">"स्थानासाठी डेटा शेअरिंगसंबंधित अपडेट"</string>
+ <string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"डेटा, डेटा शेअरिंग, डेटा शेअरिंगसंबंधित अपडेट, स्थानासाठी डेटा शेअरिंगसंबंधित अपडेट, शेअरिंग"</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/strings.xml b/SafetyCenter/Resources/res/values-mr/strings.xml
index 9ac58c0f7..4b495bddd 100644
--- a/SafetyCenter/Resources/res/values-mr/strings.xml
+++ b/SafetyCenter/Resources/res/values-mr/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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="biometrics_title" msgid="5859504610285212938">"बायोमेट्रिक"</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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"गोपनीयता, गोपनीयता नियंत्रणे"</string>
<string name="advanced_title" msgid="8745436380690561172">"आणखी सेटिंग्ज"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"आणखी सुरक्षा सेटिंग्ज"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"एंक्रिप्शन, क्रेडेंशियल आणि आणखी बरेच काही"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"आणखी गोपनीयता सेटिंग्ज"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"ऑटोफिल, अ‍ॅक्टिव्हिटी कंट्रोल आणि आणखी बरेच काही"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ms-v34/strings.xml b/SafetyCenter/Resources/res/values-ms-v34/strings.xml
new file mode 100644
index 000000000..68102f138
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ms-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Buka kunci peranti"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometrik untuk kerja"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Kebenaran, papan pemuka, kawalan"</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">"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="advanced_title" msgid="6259362998269627310">"Tetapan lain"</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/strings.xml b/SafetyCenter/Resources/res/values-ms/strings.xml
index f256950d2..a1058031e 100644
--- a/SafetyCenter/Resources/res/values-ms/strings.xml
+++ b/SafetyCenter/Resources/res/values-ms/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Kunci skrin"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Belum ada maklumat lagi"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Kunci peranti, Kunci skrin, Skrin kunci, Skrin kunci, Kata laluan, Pin, Corak"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometrik"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Cap jari, Jari, Tambah cap jari, Buka kunci wajah, Wajah"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privasi"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Papan pemuka, kebenaran, kawalan"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Papan pemuka privasi"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Tunjukkan apl yang menggunakan kebenaran baru-baru ini"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Privasi, Papan pemuka privasi"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Pengurus kebenaran"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Kawal akses apl kepada data anda"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Kebenaran, Pengurus kebenaran"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Kawalan privasi"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Kawal akses peranti kepada mikrofon, kamera dan banyak lagi"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privasi, Kawalan privasi"</string>
<string name="advanced_title" msgid="8745436380690561172">"Lagi tetapan"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Lagi tetapan keselamatan"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Penyulitan, bukti kelayakan dan banyak lagi"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Lagi tetapan privasi"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Autolengkap, kawalan aktiviti dan banyak lagi"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-my-v34/strings.xml b/SafetyCenter/Resources/res/values-my-v34/strings.xml
new file mode 100644
index 000000000..9b2b27707
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-my-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-my/strings.xml
index b81c6869c..d0d895ddb 100644
--- a/SafetyCenter/Resources/res/values-my/strings.xml
+++ b/SafetyCenter/Resources/res/values-my/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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="biometrics_title" msgid="5859504610285212938">"ဇီဝမက်ထရစ် အချက်အလက်များ"</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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"ကိုယ်ရေးအချက်အလက်လုံခြုံမှု၊ ကန့်သတ်ရန် ဆက်တင်များ"</string>
<string name="advanced_title" msgid="8745436380690561172">"နောက်ထပ်ဆက်တင်များ"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"နောက်ထပ် လုံခြုံရေးဆက်တင်များ"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"အသွင်ဝှက်ခြင်း၊ အထောက်အထားများ စသည်"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"နောက်ထပ် ကိုယ်ရေးအချက်အလက်လုံခြုံမှု ဆက်တင်များ"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"အော်တိုဖြည့်၊ လုပ်ဆောင်ချက် ထိန်းချုပ်မှုများ စသည်"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-nb-v34/strings.xml b/SafetyCenter/Resources/res/values-nb-v34/strings.xml
new file mode 100644
index 000000000..6ccbb06bd
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-nb-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Enhetsopplåsing"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometri for jobb"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Tillatelser, oversikt, innstillinger"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-nb/strings.xml
index 752417db3..15c311f63 100644
--- a/SafetyCenter/Resources/res/values-nb/strings.xml
+++ b/SafetyCenter/Resources/res/values-nb/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Skjermlås"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Ingen informasjon ennå"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Enhetslås, skjermlås, låseskjerm, passord, PIN-kode, mønster"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometri"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Fingeravtrykk, finger, legg til fingeravtrykk, ansiktslås, ansikt"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Personvern"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Oversikt, tillatelser, kontroller"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Personvernoversikt"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Vis hvilke apper som nylig har brukt tillatelser"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Personvern, personvernoversikt"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Tillatelseskontroll"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Kontroller apptilgang til dataene dine"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Tillatelser, tillatelsesadministrator"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Personverninnstillinger"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Kontroller enhetstilgang til mikrofon, kamera med mer"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Personvern, personverninnstillinger"</string>
<string name="advanced_title" msgid="8745436380690561172">"Flere innstillinger"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Flere sikkerhetsinnstillinger"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Kryptering, legitimasjon med mer"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Flere personverninnstillinger"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Autofyll, aktivitetslagring med mer"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ne-v34/strings.xml b/SafetyCenter/Resources/res/values-ne-v34/strings.xml
new file mode 100644
index 000000000..4a90e99b6
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ne-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="app_data_sharing_updates_title" msgid="7428862330643262588">"लोकेसन डेटा सेयर गर्नेसम्बन्धी अभ्यासका बारेमा अद्यावधिक जानकारी"</string>
+ <string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"जानकारी, जानकारी सेयर गर्नेसम्बन्धी अभ्यास, जानकारी सेयर गर्नेसम्बन्धी अभ्यासका बारेमा अद्यावधिक जानकारी, लोकेसन डेटा सेयर गर्नेसम्बन्धी अभ्यासका बारेमा अद्यावधिक जानकारी, सेयरिङ"</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/strings.xml b/SafetyCenter/Resources/res/values-ne/strings.xml
index da866290a..4ef5c9609 100644
--- a/SafetyCenter/Resources/res/values-ne/strings.xml
+++ b/SafetyCenter/Resources/res/values-ne/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
<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_summary" msgid="6172253327022425123">"इन्क्रिप्सन, युजरनेम, पासवर्ड र अन्य कुराहरू"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"गोपनीयतासम्बन्धी थप सेटिङ"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"अटोफिल, गतिविधिसम्बन्धी सेटिङ र अन्य कुराहरू"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-nl-v34/strings.xml b/SafetyCenter/Resources/res/values-nl-v34/strings.xml
new file mode 100644
index 000000000..e5a446c52
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-nl-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"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="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/strings.xml b/SafetyCenter/Resources/res/values-nl/strings.xml
index 52cf62b62..5232c280b 100644
--- a/SafetyCenter/Resources/res/values-nl/strings.xml
+++ b/SafetyCenter/Resources/res/values-nl/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Schermvergrendeling"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Nog geen informatie"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Apparaatvergrendeling, Schermvergrendeling, Vergrendelscherm, Scherm vergrendelen, Wachtwoord, Pincode, Patroon"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometrische gegevens"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Vingerafdruk, Vinger, Vingerafdruk toevoegen, Ontgrendelen via gezichtsherkenning, Gezicht"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privacy"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Dashboard, rechten, bedieningselementen"</string>
<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">"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>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Beheer apparaattoegang tot de microfoon, camera en meer"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privacy, Privacyopties"</string>
<string name="advanced_title" msgid="8745436380690561172">"Meer instellingen"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Meer beveiligingsinstellingen"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Versleuteling, inloggegevens en meer"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Meer privacyinstellingen"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Automatisch invullen, activiteitsopties en meer"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-or-v34/strings.xml b/SafetyCenter/Resources/res/values-or-v34/strings.xml
new file mode 100644
index 000000000..df4d07e17
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-or-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-or/strings.xml
index d53214764..d4d8d1a4a 100644
--- a/SafetyCenter/Resources/res/values-or/strings.xml
+++ b/SafetyCenter/Resources/res/values-or/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
<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_summary" msgid="6172253327022425123">"ଏନକ୍ରିପ୍ସନ, କ୍ରେଡେନ୍ସିଆଲ ଏବଂ ଆହୁରି ଅନେକ କିଛି"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"ଅଧିକ ଗୋପନୀୟତା ସେଟିଂସ"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"ଅଟୋଫିଲ, କାର୍ଯ୍ୟକଳାପ ନିୟନ୍ତ୍ରଣ ଏବଂ ଆହୁରି ଅନେକ କିଛି"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-pa-v34/strings.xml b/SafetyCenter/Resources/res/values-pa-v34/strings.xml
new file mode 100644
index 000000000..b30bcce37
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-pa-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-pa/strings.xml
index 519a725d2..4a381c15e 100644
--- a/SafetyCenter/Resources/res/values-pa/strings.xml
+++ b/SafetyCenter/Resources/res/values-pa/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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="biometrics_title" msgid="5859504610285212938">"ਬਾਇਓਮੈਟ੍ਰਿਕ"</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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"ਪਰਦੇਦਾਰੀ, ਪਰਦੇਦਾਰੀ ਕੰਟਰੋਲ"</string>
<string name="advanced_title" msgid="8745436380690561172">"ਹੋਰ ਸੈਟਿੰਗਾਂ"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"ਹੋਰ ਸੁਰੱਖਿਆ ਸੈਟਿੰਗਾਂ"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"ਇਨਕ੍ਰਿਪਸ਼ਨ, ਕ੍ਰੀਡੈਂਸ਼ੀਅਲ ਅਤੇ ਹੋਰ ਬਹੁਤ ਕੁਝ"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"ਹੋਰ ਪਰਦੇਦਾਰੀ ਸੈਟਿੰਗਾਂ"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"ਆਟੋਫਿਲ, ਸਰਗਰਮੀ ਕੰਟਰੋਲ ਅਤੇ ਹੋਰ ਬਹੁਤ ਕੁਝ"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-pl-v34/strings.xml b/SafetyCenter/Resources/res/values-pl-v34/strings.xml
new file mode 100644
index 000000000..7ee39b539
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-pl-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Odblokowywanie urządzenia"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometria na urządzeniach służbowych"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Uprawnienia, panel, elementy sterujące"</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">"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="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/strings.xml b/SafetyCenter/Resources/res/values-pl/strings.xml
index d66153740..6d5bf43c4 100644
--- a/SafetyCenter/Resources/res/values-pl/strings.xml
+++ b/SafetyCenter/Resources/res/values-pl/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Blokada ekranu"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Nie ma jeszcze informacji"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Blokowanie urządzenia, Ekran blokady, Zablokuj ekran, Blokowanie ekranu, Hasło, PIN, Wzór"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometria"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Odcisk palca, Palec, Dodaj palec, Rozpoznawanie twarzy, Twarz"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Prywatność"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Panel, uprawnienia, elementy sterujące"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Panel prywatności"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Pokaż aplikacje, które ostatnio używały uprawnień"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Prywatność, Panel prywatności"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Menedżer uprawnień"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Kontroluj dostęp aplikacji do danych"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Uprawnienia, Menedżer uprawnień"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Ustawienia prywatności"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Steruj dostępem urządzenia do mikrofonu, aparatu i innych funkcji"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Prywatność, Ustawienia prywatności"</string>
<string name="advanced_title" msgid="8745436380690561172">"Więcej ustawień"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Więcej ustawień bezpieczeństwa"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Szyfrowanie, dane logowania i inne"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Więcej ustawień prywatności"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Autouzupełnianie, zarządzanie aktywnością i inne"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-pt-rBR-v34/strings.xml b/SafetyCenter/Resources/res/values-pt-rBR-v34/strings.xml
new file mode 100644
index 000000000..a69cf32ca
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-pt-rBR-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Desbloqueio do dispositivo"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometria para o trabalho"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Permissões, painel, controles"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Conexão Saúde"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-pt-rBR/strings.xml
index 3e51f7231..ea356263a 100644
--- a/SafetyCenter/Resources/res/values-pt-rBR/strings.xml
+++ b/SafetyCenter/Resources/res/values-pt-rBR/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Bloqueio de tela"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Ainda não há informações"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Bloqueio do dispositivo, Bloqueio de tela, Tela de bloqueio, Senha, PIN, Padrão"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometria"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Impressão digital, Dedo, Adicionar impressão digital, Desbloqueio facial, Rosto"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privacidade"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Painel, permissões, controles"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Painel de privacidade"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Mostra quais apps usaram as permissões recentemente"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Privacidade, Painel de privacidade"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Gestão de permissões"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Controlar o acesso de apps aos seus dados"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Permissões, Gerenciador de permissões"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Controles de privacidade"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Controlar o acesso do dispositivo ao microfone, à câmera e muito mais"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privacidade, Controles de privacidade"</string>
<string name="advanced_title" msgid="8745436380690561172">"Mais configurações"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Mais configurações de segurança"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Criptografia, credenciais e muito mais"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Mais configurações de privacidade"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Preenchimento automático, controles de atividade e muito mais"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-pt-rPT-v34/strings.xml b/SafetyCenter/Resources/res/values-pt-rPT-v34/strings.xml
new file mode 100644
index 000000000..643fa469d
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-pt-rPT-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Desbloqueio do dispositivo"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometria para trabalho"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Autorizações, painel de controlo e controlos"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Saúde Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-pt-rPT/strings.xml
index a03b36f73..5773d657b 100644
--- a/SafetyCenter/Resources/res/values-pt-rPT/strings.xml
+++ b/SafetyCenter/Resources/res/values-pt-rPT/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Bloqueio de ecrã"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Ainda sem informações"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Bloqueio do dispositivo, bloqueio de ecrã, ecrã de bloqueio, palavra-passe, PIN, padrão"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometria"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Impressão digital, dedo, adicionar impressão digital, Desbloqueio facial, cara"</string>
<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">"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>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Autorizações, gestor de autorizações"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Controlos de privacidade"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Controle o acesso do dispositivo ao microfone, câmara e muito mais"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privacidade, controlos de privacidade"</string>
<string name="advanced_title" msgid="8745436380690561172">"Mais definições"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Mais definições de segurança"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Encriptação, credenciais e mais"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Mais definições de privacidade"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Preenchimento automático, controlos da atividade e mais"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-pt-v34/strings.xml b/SafetyCenter/Resources/res/values-pt-v34/strings.xml
new file mode 100644
index 000000000..a69cf32ca
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-pt-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Desbloqueio do dispositivo"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometria para o trabalho"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Permissões, painel, controles"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Conexão Saúde"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-pt/strings.xml
index 3e51f7231..ea356263a 100644
--- a/SafetyCenter/Resources/res/values-pt/strings.xml
+++ b/SafetyCenter/Resources/res/values-pt/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Bloqueio de tela"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Ainda não há informações"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Bloqueio do dispositivo, Bloqueio de tela, Tela de bloqueio, Senha, PIN, Padrão"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometria"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Impressão digital, Dedo, Adicionar impressão digital, Desbloqueio facial, Rosto"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privacidade"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Painel, permissões, controles"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Painel de privacidade"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Mostra quais apps usaram as permissões recentemente"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Privacidade, Painel de privacidade"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Gestão de permissões"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Controlar o acesso de apps aos seus dados"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Permissões, Gerenciador de permissões"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Controles de privacidade"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Controlar o acesso do dispositivo ao microfone, à câmera e muito mais"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privacidade, Controles de privacidade"</string>
<string name="advanced_title" msgid="8745436380690561172">"Mais configurações"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Mais configurações de segurança"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Criptografia, credenciais e muito mais"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Mais configurações de privacidade"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Preenchimento automático, controles de atividade e muito mais"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ro-v34/strings.xml b/SafetyCenter/Resources/res/values-ro-v34/strings.xml
new file mode 100644
index 000000000..9292c43d3
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ro-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Deblocarea dispozitivului"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Sisteme biometrice pentru aplicații de serviciu"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Permisiuni, tablou de bord, comenzi"</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">"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="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/strings.xml b/SafetyCenter/Resources/res/values-ro/strings.xml
index 7f825d188..20bf92321 100644
--- a/SafetyCenter/Resources/res/values-ro/strings.xml
+++ b/SafetyCenter/Resources/res/values-ro/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Blocarea ecranului"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Nu există informații încă"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Blocarea dispozitivului, Ecran de blocare, Parolă, PIN, Model"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Sisteme biometrice"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Amprentă, Deget, Adaugă o amprentă, Deblocare facială, Față"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Confidențialitate"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Tablou de bord, permisiuni, comenzi"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Tablou de bord de confidențialitate"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Arată aplicațiile care au folosit recent permisiuni"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Confidențialitate, Tablou de bord de confidențialitate"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Manager de permisiuni"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Controlează accesul aplicațiilor la date"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Permisiuni, Manager de permisiuni"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Opțiuni de confidențialitate"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Controlează accesul dispozitivului la microfon, camera foto și altele"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Confidențialitate, Opțiuni de confidențialitate"</string>
<string name="advanced_title" msgid="8745436380690561172">"Mai multe setări"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Mai multe setări de securitate"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Criptarea, datele de conectare și altele"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Mai multe setări de confidențialitate"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Completare automată, opțiuni privind activitatea și altele"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ru-v34/strings.xml b/SafetyCenter/Resources/res/values-ru-v34/strings.xml
new file mode 100644
index 000000000..b8a78d5ed
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ru-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="biometrics_title_for_work" msgid="1842284049407771568">"Биометрия для рабочих приложений"</string>
+ <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_search_terms" msgid="8414777373734245398">"Данные, Передача данных, Обновления передачи данных, Обновление доступа к данным, Обновление доступа к данным о местоположении"</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/strings.xml b/SafetyCenter/Resources/res/values-ru/strings.xml
index 66faa8d2f..715e7ebb4 100644
--- a/SafetyCenter/Resources/res/values-ru/strings.xml
+++ b/SafetyCenter/Resources/res/values-ru/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Конфиденциальность, настройки конфиденциальности"</string>
<string name="advanced_title" msgid="8745436380690561172">"Дополнительные настройки"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Дополнительные настройки безопасности"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Шифрование, учетные данные и прочее"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Дополнительные настройки конфиденциальности"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Автозаполнение, отслеживание действий и прочее"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-si-v34/strings.xml b/SafetyCenter/Resources/res/values-si-v34/strings.xml
new file mode 100644
index 000000000..b2b291351
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-si-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-si/strings.xml
index 466c134a6..a8d8ee0a2 100644
--- a/SafetyCenter/Resources/res/values-si/strings.xml
+++ b/SafetyCenter/Resources/res/values-si/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"පෞද්ගලිකත්වය, පෞද්ගලිකත්ව පාලන"</string>
<string name="advanced_title" msgid="8745436380690561172">"තව සැකසීම්"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"තවත් ආරක්ෂක සැකසීම්"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"සංකේතනය, අක්තපත්‍ර සහ තවත් දේ"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"තවත් පෞද්ගලිකත්ව සැකසීම්"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"ස්වයං පිරවුම, ක්‍රියාකාරකම් පාලන සහ තවත් දේ"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-sk-v34/strings.xml b/SafetyCenter/Resources/res/values-sk-v34/strings.xml
new file mode 100644
index 000000000..c3cdab5d2
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-sk-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Odomknutie zariadenia"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometria pre pracovné aplikácie"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Povolenia, hlavný panel, ovládanie"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Dáta o zdraví"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-sk/strings.xml
index e4d54c4e8..6357114cd 100644
--- a/SafetyCenter/Resources/res/values-sk/strings.xml
+++ b/SafetyCenter/Resources/res/values-sk/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Zámka obrazovky"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Zatiaľ nie sú dostupné žiadne informácie"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Zámka zariadenia, zámka obrazovky, zamknúť obrazovku, uzamknutá obrazovka, heslo, PIN, vzor"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometria"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Odtlačok prsta, prst, pridať odtlačok prsta, odomknutie tvárou, tvár"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Ochrana súkromia"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Hlavný panel, povolenia, ovládanie"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Panel ochrany súkromia"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Zobraziť, ktoré aplikácie nedávno použili povolenia"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Ochrana súkromia, panel ochrany súkromia"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Správca povolení"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Ovládanie prístupu aplikácií k vašim údajom"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Povolenia, správca povolení"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Nastavenia ochrany súkromia"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Ovládanie prístupu k mikrofónu, kamere a ďalším zariadeniam"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Ochrana súkromia, nastavenia ochrany súkromia"</string>
<string name="advanced_title" msgid="8745436380690561172">"Ďalšie nastavenia"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Ďalšie nastavenia zabezpečenia"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Šifrovanie, prihlasovacie údaje a ďalšie"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Ďalšie nastavenia ochrany súkromia"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Automatické dopĺňanie, Riadenie aktivity a ďalšie"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-sl-v34/strings.xml b/SafetyCenter/Resources/res/values-sl-v34/strings.xml
new file mode 100644
index 000000000..9898c2f0a
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-sl-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Odklepanje naprave"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometrika za delo"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Dovoljenja, nadzorna plošča, kontrolniki"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-sl/strings.xml
index b278067e5..d7b1c5c70 100644
--- a/SafetyCenter/Resources/res/values-sl/strings.xml
+++ b/SafetyCenter/Resources/res/values-sl/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Zaklepanje zaslona"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Ni še nobenega podatka."</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"zaklepanje naprave, zaklepanje zaslona, zaklenjen zaslon, geslo, koda PIN, vzorec"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometrika"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"prstni odtis, prst, dodajanje prstnega odtisa, odklepanje z obrazom, obraz"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Zasebnost"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Nadzorna plošča, dovoljenja, kontrolniki"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Nadzorna plošča za zasebnost"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Prikažite aplikacije, ki so pred kratkim uporabile dovoljenja."</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"zasebnost, nadzorna plošča za zasebnost"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Upravitelj dovoljenj"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Nadzorujte dostop aplikacij do podatkov."</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"dovoljenja, upravitelj dovoljenj"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Nastavitve zasebnosti"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Upravljajte dostop naprav do mikrofona, fotoaparata in drugega."</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"zasebnost, nastavitve zasebnosti"</string>
<string name="advanced_title" msgid="8745436380690561172">"Več nastavitev"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Več varnostnih nastavitev"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Šifriranje, poverilnice in drugo"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Več nastavitev zasebnosti"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Samodejno izpolnjevanje, kontrolniki za dejavnost in drugo"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-sq-v34/strings.xml b/SafetyCenter/Resources/res/values-sq-v34/strings.xml
new file mode 100644
index 000000000..64d7f4a4e
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-sq-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Shkyçja e pajisjes"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Sisteme biometrike për punë"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Lejet, paneli, kontrollet"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-sq/strings.xml
index bec754982..8671f53fd 100644
--- a/SafetyCenter/Resources/res/values-sq/strings.xml
+++ b/SafetyCenter/Resources/res/values-sq/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Kyçja e ekranit"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Nuk ka ende informacione"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Kyçja e pajisjes, Kyçja e ekranit, Kyçja e ekranit, Ekrani i kyçjes, Fjalëkalimi, Kodi PIN, Motivi"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Sistemet biometrike"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Gjurma e gishtit, Gishti, Shto gjurmë gishti, Shkyçja me fytyrë, Fytyra"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privatësia"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Paneli, lejet, kontrollet"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Paneli i privatësisë"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Shfaq se cilat aplikacione i kanë përdorur së fundi lejet"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Privatësia, Paneli i privatësisë"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Menaxheri i lejeve"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Kontrollo qasjen e aplikacioneve te të dhënat e tua"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Lejet, Menaxheri i lejeve"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Kontrollet e privatësisë"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Kontrollo qasjen e pajisjes te mikrofoni, kamera dhe të tjera"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privatësia, Kontrollet e privatësisë"</string>
<string name="advanced_title" msgid="8745436380690561172">"Cilësime të tjera"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Cilësime të tjera të sigurisë"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Enkriptimi, kredencialet dhe të tjera"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Cilësime të tjera të privatësisë"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Plotësimi automatik, kontrollet e aktivitetit dhe të tjera"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-sr-v34/strings.xml b/SafetyCenter/Resources/res/values-sr-v34/strings.xml
new file mode 100644
index 000000000..9c69c8fad
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-sr-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="biometrics_title_for_work" msgid="1842284049407771568">"Биометрија за посао"</string>
+ <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_search_terms" msgid="8414777373734245398">"подаци, дељење података, ажурирања дељења података, ажурирања дељења података за локацију, дељење"</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/strings.xml b/SafetyCenter/Resources/res/values-sr/strings.xml
index 66b967e16..2cd42d24c 100644
--- a/SafetyCenter/Resources/res/values-sr/strings.xml
+++ b/SafetyCenter/Resources/res/values-sr/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"приватност, контроле приватности"</string>
<string name="advanced_title" msgid="8745436380690561172">"Још подешавања"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Још безбедносних подешавања"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Шифровање, акредитиви и друго"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Још подешавања приватности"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Аутоматско попуњавање, контроле активности и друго"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-sv-v34/strings.xml b/SafetyCenter/Resources/res/values-sv-v34/strings.xml
new file mode 100644
index 000000000..ef7de6322
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-sv-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Enhetsupplåsning"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometri för jobbet"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Behörigheter, översikt, inställningar"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-sv/strings.xml
index 4daa58e4f..e10abbf40 100644
--- a/SafetyCenter/Resources/res/values-sv/strings.xml
+++ b/SafetyCenter/Resources/res/values-sv/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Skärmlås"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Ingen information än"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Enhetslås, skärmlås, låsskärm, lösenord, PIN-kod, mönster"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometri"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Fingeravtryck, finger, lägg till fingeravtryck, ansiktslås, ansikte"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Integritet"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Översikt, behörigheter, inställningar"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Integritetsöversikt"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Visa vilka appar som nyligen har använt behörigheter"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Integritet, integritetsöversikt"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Behörighetshantering"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Styr appåtkomst till din data"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Behörigheter, behörighetshanterare"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Integritetsinställningar"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Styr enhetsåtkomst till mikrofon, kamera med mera"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Integritet, integritetsinställningar"</string>
<string name="advanced_title" msgid="8745436380690561172">"Fler inställningar"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Fler säkerhetsinställningar"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Kryptering, användaruppgifter med mera"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Fler integritetsinställningar"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Autofyll, aktivitetsinställningar med mera"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-sw-v34/strings.xml b/SafetyCenter/Resources/res/values-sw-v34/strings.xml
new file mode 100644
index 000000000..d065e2e03
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-sw-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Kufungua kifaa"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Bayometriki ya programu za kazini"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Ruhusa, dashibodi, vidhibiti"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-sw/strings.xml
index c7150ca43..5b1bd8131 100644
--- a/SafetyCenter/Resources/res/values-sw/strings.xml
+++ b/SafetyCenter/Resources/res/values-sw/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Kufunga skrini"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Bado hakuna maelezo"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Kufunga kifaa, Kufunga skrini, Skrini iliyofungwa, Skrini iliyofungwa, Nenosiri, PIN, Mchoro"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Bayometriki"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Alama ya kidole, Kidole, Weka alama ya kidole, Kufungua kwa uso, Uso"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Faragha"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Dashibodi, ruhusa, vidhibiti"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Dashibodi ya faragha"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Onyesha programu zilizotumia ruhusa hivi majuzi"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Faragha, Dashibodi ya faragha"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Kidhibiti cha ruhusa"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Dhibiti uwezo wa programu kufikia data yako"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Ruhusa, Kidhibiti cha ruhusa"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Vidhibiti vya faragha"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Dhibiti ufikiaji wa maikrofoni, kamera na zaidi kwenye kifaa"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Faragha, Vidhibiti vya faragha"</string>
<string name="advanced_title" msgid="8745436380690561172">"Mipangilio zaidi"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Mipangilio zaidi ya usalama"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Usimbaji fiche, vitambulisho na zaidi"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Mipangilio zaidi ya faragha"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Kujaza kiotomatiki, vidhibiti vya shughuli na zaidi"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ta-v34/strings.xml b/SafetyCenter/Resources/res/values-ta-v34/strings.xml
new file mode 100644
index 000000000..b9f2a0b4e
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ta-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="app_data_sharing_updates_title" msgid="7428862330643262588">"இருப்பிடத்திற்கான தரவுப் பகிர்வு குறித்த அறிவிப்புகள்"</string>
+ <string name="app_data_sharing_updates_search_terms" msgid="8414777373734245398">"தரவு, தரவுப் பகிர்வு, தரவுப் பகிர்வு குறித்த அறிவிப்புகள், இருப்பிடத்திற்கான தரவுப் பகிர்வு குறித்த அறிவிப்புகள், பகிர்வு"</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/strings.xml b/SafetyCenter/Resources/res/values-ta/strings.xml
index f0b2bc8a0..3586280e2 100644
--- a/SafetyCenter/Resources/res/values-ta/strings.xml
+++ b/SafetyCenter/Resources/res/values-ta/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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="biometrics_title" msgid="5859504610285212938">"பயோமெட்ரிக்ஸ்"</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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"தனியுரிமை, தனியுரிமைக் கட்டுப்பாடுகள்"</string>
<string name="advanced_title" msgid="8745436380690561172">"கூடுதல் அமைப்புகள்"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"கூடுதல் பாதுகாப்பு அமைப்புகள்"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"என்க்ரிப்ஷன், அனுமதிச் சான்றுகள் மற்றும் பல"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"கூடுதல் தனியுரிமை அமைப்புகள்"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"தன்னிரப்பி, செயல்பாட்டுக் கட்டுப்பாடுகள் மற்றும் பல"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-te-v34/strings.xml b/SafetyCenter/Resources/res/values-te-v34/strings.xml
new file mode 100644
index 000000000..9ca7bea5f
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-te-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-te/strings.xml
index 041853521..11c181a9c 100644
--- a/SafetyCenter/Resources/res/values-te/strings.xml
+++ b/SafetyCenter/Resources/res/values-te/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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="biometrics_title" msgid="5859504610285212938">"బయోమెట్రిక్స్"</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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"గోప్యత, గోప్యతా కంట్రోల్స్"</string>
<string name="advanced_title" msgid="8745436380690561172">"మరిన్ని సెట్టింగ్‌లు"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"మరిన్ని సెక్యూరిటీ సెట్టింగ్‌లు"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"ఎన్‌క్రిప్షన్, ఆధారాలు, మరిన్ని"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"మరిన్ని గోప్యతా సెట్టింగ్‌లు"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"ఆటోఫిల్, యాక్టీవిటీ కంట్రోల్స్, ఇంకా మరిన్ని"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-th-v34/strings.xml b/SafetyCenter/Resources/res/values-th-v34/strings.xml
new file mode 100644
index 000000000..e334d9b5e
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-th-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-th/strings.xml
index 94dcc046e..5a899048f 100644
--- a/SafetyCenter/Resources/res/values-th/strings.xml
+++ b/SafetyCenter/Resources/res/values-th/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"ความเป็นส่วนตัว, การควบคุมความเป็นส่วนตัว"</string>
<string name="advanced_title" msgid="8745436380690561172">"การตั้งค่าเพิ่มเติม"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"การตั้งค่าการรักษาความปลอดภัยเพิ่มเติม"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"การเข้ารหัส ข้อมูลเข้าสู่ระบบ และอื่นๆ"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"การตั้งค่าความเป็นส่วนตัวเพิ่มเติม"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"ป้อนข้อความอัตโนมัติ ส่วนควบคุมกิจกรรม และอื่นๆ"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-tl-v34/strings.xml b/SafetyCenter/Resources/res/values-tl-v34/strings.xml
new file mode 100644
index 000000000..dd3754f15
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-tl-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Pag-unlock ng device"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Biometrics para sa trabaho"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Mga pahintulot, dashboard, mga kontrol"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-tl/strings.xml
index 6eb3b0aa4..63b0abf96 100644
--- a/SafetyCenter/Resources/res/values-tl/strings.xml
+++ b/SafetyCenter/Resources/res/values-tl/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Lock ng screen"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Wala pang impormasyon"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Lock ng device, Lock ng screen, Lock screen, Lockscreen, Password, Pin, Pattern"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometrics"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Fingerprint, Daliri, Magdagdag ng fingerprint, Pag-unlock gamit ang mukha, Face"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Privacy"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Dashboard, mga pahintulot, mga kontrol"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Privacy dashboard"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Ipakita kung aling mga app ang gumamit kamakailan ng mga pahintulot"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Privacy, Privacy dashboard"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Manager ng pahintulot"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Kontrolin ang pag-access ng app sa iyong data"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Mga pahintulot, Manager ng mga pahintulot"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Mga kontrol sa privacy"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Kontrolin ang access ng device sa mikropono, camera, at higit pa"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Privacy, Mga kontrol sa privacy"</string>
<string name="advanced_title" msgid="8745436380690561172">"Higit pang setting"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Higit pang setting ng seguridad"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Pag-encrypt, mga kredensyal, at higit pa"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Higit pang setting ng privacy"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Autofill, mga kontrol ng aktibidad, at higit pa"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-tr-v34/strings.xml b/SafetyCenter/Resources/res/values-tr-v34/strings.xml
new file mode 100644
index 000000000..9d330c3ce
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-tr-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Cihazda kilit açma"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"İş için biyometri"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"İzinler, kontrol paneli, kontroller"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-tr/strings.xml
index f924cef19..111c35bfa 100644
--- a/SafetyCenter/Resources/res/values-tr/strings.xml
+++ b/SafetyCenter/Resources/res/values-tr/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Ekran kilidi"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Henüz bilgi yok"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Cihaz kilidi, Ekran kilidi, Kilit ekranı, Şifre, PIN, Desen"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biyometri"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Parmak izi, Parmak, Parmak izi ekle, Yüz tanıma kilidi, Yüz"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Gizlilik"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Kontrol paneli, izinler, kontroller"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Gizlilik kontrol paneli"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"İzinleri son kullanan uygulamaları göster"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Gizlilik, Gizlilik kontrol paneli"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"İzin yöneticisi"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Verilere uygulama erişimini denetleyin"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"İzinler, İzin yöneticisi"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Gizlilik denetimleri"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Cihazın mikrofona, kameraya ve daha fazlasına erişimini kontrol edin"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Gizlilik, Gizlilik denetimleri"</string>
<string name="advanced_title" msgid="8745436380690561172">"Diğer ayarlar"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Daha fazla güvenlik ayarı"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Şifreleme, kimlik bilgisi ve daha fazlası"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Daha fazla gizlilik ayarı"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Otomatik doldurma, etkinlik kontrolleri ve daha fazlası"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-uk-v34/strings.xml b/SafetyCenter/Resources/res/values-uk-v34/strings.xml
new file mode 100644
index 000000000..9d2ba565f
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-uk-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-uk/strings.xml
index 97dd12355..0c1e109a3 100644
--- a/SafetyCenter/Resources/res/values-uk/strings.xml
+++ b/SafetyCenter/Resources/res/values-uk/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"конфіденційність, налаштування конфіденційності"</string>
<string name="advanced_title" msgid="8745436380690561172">"Інші налаштування"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Інші налаштування безпеки"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Шифрування, облікові дані тощо"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Інші налаштування конфіденційності"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Автозаповнення, відстеження дій тощо"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-ur-v34/strings.xml b/SafetyCenter/Resources/res/values-ur-v34/strings.xml
new file mode 100644
index 000000000..eb6e1e407
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-ur-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-ur/strings.xml
index be59bef5e..d66a27c91 100644
--- a/SafetyCenter/Resources/res/values-ur/strings.xml
+++ b/SafetyCenter/Resources/res/values-ur/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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="biometrics_title" msgid="5859504610285212938">"بایو میٹرکس"</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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"رازداری، رازداری سے متعلق کنٹرولز"</string>
<string name="advanced_title" msgid="8745436380690561172">"مزید ترتیبات"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"مزید سیکیورٹی کی ترتیبات"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"مرموز کاری، اسنادات اور مزید"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"مزید رازداری کی ترتیبات"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"آٹو فل، سرگرمی کنٹرولز اور مزید"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-uz-v34/strings.xml b/SafetyCenter/Resources/res/values-uz-v34/strings.xml
new file mode 100644
index 000000000..1304a81f6
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-uz-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Qurilma qulfini ochish"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Ish uchun biometriya"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Ruxsatlar, boshqaruv paneli, parametrlar"</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">"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="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/strings.xml b/SafetyCenter/Resources/res/values-uz/strings.xml
index 9a4658531..f97bfa320 100644
--- a/SafetyCenter/Resources/res/values-uz/strings.xml
+++ b/SafetyCenter/Resources/res/values-uz/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Ekran qulfi"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Hali axborot olinmadi"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Qurilma qulfi, ekran qulfi, ekranni qulflash, ekranqulfi, parol, pin, grafik kalit"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Biometrik tizimlar"</string>
+ <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 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>
<string name="permission_manager_summary" msgid="8099852107340970790">"Ilovalarning maʼlumotlaringizga kirish ruxsatini boshqarish"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Ruxsatlar, ruxsatlar menejeri"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Maxfiylik sozlamalari"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Qurilmaning mikrofon, kamera va boshqa parametrlariga ruxsatini boshqarish"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Maxfiylik, maxfiylik boshqaruvlari"</string>
<string name="advanced_title" msgid="8745436380690561172">"Boshqa sozlamalar"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Boshqa xavfsizlik sozlamalari"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Shifrlash, hisob maʼlumotlari va boshqalar"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Boshqa maxfiylik sozlamalari"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Avtomatik kiritish, harakatlarni kuzatish va boshqalar"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-v34/config.xml b/SafetyCenter/Resources/res/values-v34/config.xml
new file mode 100644
index 000000000..db79e5924
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-v34/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,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>
+</resources>
diff --git a/SafetyCenter/Resources/res/values-v34/strings.xml b/SafetyCenter/Resources/res/values-v34/strings.xml
new file mode 100644
index 000000000..c7013cef5
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-v34/strings.xml
@@ -0,0 +1,39 @@
+<?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">
+ <!-- Device unlock -->
+ <string name="lock_screen_sources_title" description="The title of the group of safety settings relating to screen lock and biometrics">Device unlock</string>
+
+ <string name="biometrics_title_for_work" description="The default title of the setting for managing biometric options on the device for work apps">Biometrics for work</string>
+
+ <!-- Privacy -->
+ <string name="privacy_sources_summary" description="The summary of the group of safety settings relating to privacy, which describes the group contents">Permissions, dashboard, controls</string>
+
+ <string name="health_connect_title" description="Health connect title">Health&#160;Connect</string>
+ <string name="health_connect_search_terms" description="Health connect search words">Health, Health Connect</string>
+ <string name="app_data_sharing_updates_title" description="App data sharing updates title">Data sharing updates for location</string>
+ <string name="app_data_sharing_updates_search_terms" description="App data sharing updates search words">Data, Data sharing, Data sharing updates, Data sharing updates for location, sharing</string>
+
+ <!-- More settings -->
+ <string name="advanced_title" description="The title of the group of advanced settings">Other settings</string>
+ <string name="more_settings_title" description="The title of the entry for More Settings">More security &amp; privacy</string>
+ <string name="more_settings_summary" description="The summary of the entry for More Settings, which describes the page contents">Autofill, notifications, and more</string>
+ <string name="more_settings_search_terms" description="Search keywords of the entry for More Settings"><!-- Empty placeholder--></string>
+ <string name="work_policy_title" description="Title for the work policy entry under Other Settings in Safety Center, this is for managed devices">Your work policy info</string>
+
+</resources>
diff --git a/SafetyCenter/Resources/res/values-vi-v34/strings.xml b/SafetyCenter/Resources/res/values-vi-v34/strings.xml
new file mode 100644
index 000000000..c4b5ad44f
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-vi-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Mở khoá thiết bị"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"Hệ thống nhận dạng sinh trắc học dành cho công việc"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Quyền, trang tổng quan, chế độ cài đặt"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-vi/strings.xml
index f5634fdc8..e121cad41 100644
--- a/SafetyCenter/Resources/res/values-vi/strings.xml
+++ b/SafetyCenter/Resources/res/values-vi/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Phương thức khoá màn hình"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Chưa có thông tin"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Khóa thiết bị, Khóa màn hình, Màn hình khóa, Màn hình khóa, Mật khẩu, Mã Pin, Hình mở khóa"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"Sinh trắc học"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Vân tay, Ngón tay, Thêm vân tay, Mở khóa bằng khuôn mặt, Khuôn mặt"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Quyền riêng tư"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Trang tổng quan, quyền, quyền kiểm soát"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Bảng tổng quan về quyền riêng tư"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Cho biết ứng dụng nào sử dụng quyền trong thời gian gần đây"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Quyền riêng tư, Bảng tổng quan về quyền riêng tư"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Trình quản lý quyền"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Kiểm soát quyền truy cập của ứng dụng vào dữ liệu"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Quyền truy cập, Trình quản lý quyền truy cập"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Chế độ kiểm soát quyền riêng tư"</string>
<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>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Các chế độ cài đặt tự động điền, kiểm soát hoạt động và nhiều chế độ khác"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-zh-rCN-v34/strings.xml b/SafetyCenter/Resources/res/values-zh-rCN-v34/strings.xml
new file mode 100644
index 000000000..5b8a8fe8d
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-zh-rCN-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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="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-rCN/strings.xml b/SafetyCenter/Resources/res/values-zh-rCN/strings.xml
index 3e8d086f7..4348fb708 100644
--- a/SafetyCenter/Resources/res/values-zh-rCN/strings.xml
+++ b/SafetyCenter/Resources/res/values-zh-rCN/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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 码, 图案, Device lock, Screen lock, Lock screen, Lockscreen, Password, Pin, Pattern"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"生物识别"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"指纹, 手指, 添加指纹, 人脸解锁, 人脸, Fingerprint, Finger, Add fingerprint, Face unlock, Face"</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">"隐私权, 隐私信息中心, Privacy, Privacy dashboard"</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">"权限, 权限管理器, Permissions, Permissions manager"</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">"隐私权, 隐私控制, Privacy, Privacy controls"</string>
<string name="advanced_title" msgid="8745436380690561172">"更多设置"</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>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"自动填充、活动控件等"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-zh-rHK-v34/strings.xml b/SafetyCenter/Resources/res/values-zh-rHK-v34/strings.xml
new file mode 100644
index 000000000..a11abbde1
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-zh-rHK-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-zh-rHK/strings.xml
index c786f798b..0e18f30dd 100644
--- a/SafetyCenter/Resources/res/values-zh-rHK/strings.xml
+++ b/SafetyCenter/Resources/res/values-zh-rHK/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"私隱, 私隱權設定"</string>
<string name="advanced_title" msgid="8745436380690561172">"更多設定"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"更多安全性設定"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"加密、憑證等等"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"更多私隱權設定"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"自動填入、活動控制項等等"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-zh-rTW-v34/strings.xml b/SafetyCenter/Resources/res/values-zh-rTW-v34/strings.xml
new file mode 100644
index 000000000..288a0566c
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-zh-rTW-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="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="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/strings.xml b/SafetyCenter/Resources/res/values-zh-rTW/strings.xml
index eb70ea220..5c44eb33a 100644
--- a/SafetyCenter/Resources/res/values-zh-rTW/strings.xml
+++ b/SafetyCenter/Resources/res/values-zh-rTW/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></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>
+ <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_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>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"隱私,隱私權控制項"</string>
<string name="advanced_title" msgid="8745436380690561172">"其他設定"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"其他安全性設定"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"加密、憑證等等"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"其他隱私權設定"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"自動填入、活動控制項等等"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values-zu-v34/strings.xml b/SafetyCenter/Resources/res/values-zu-v34/strings.xml
new file mode 100644
index 000000000..d5c86c668
--- /dev/null
+++ b/SafetyCenter/Resources/res/values-zu-v34/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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">"Ukuvula idivayisi"</string>
+ <string name="biometrics_title_for_work" msgid="1842284049407771568">"I-Biometrics yomsebenzi"</string>
+ <string name="privacy_sources_summary" msgid="4083646673569677049">"Izimvume, ideshibhodi, izilawuli"</string>
+ <string name="health_connect_title" msgid="8318152190040327804">"Health Connect"</string>
+ <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="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/strings.xml b/SafetyCenter/Resources/res/values-zu/strings.xml
index e07bb1188..1362d0944 100644
--- a/SafetyCenter/Resources/res/values-zu/strings.xml
+++ b/SafetyCenter/Resources/res/values-zu/strings.xml
@@ -22,17 +22,25 @@
<string name="lock_screen_sources_summary" msgid="7220439741282516496"></string>
<string name="lock_screen_title" msgid="4069104894527169877">"Ukukhiya isikrini"</string>
<string name="lock_screen_summary_disabled" msgid="354071230916616692">"Alukho ulwazi okwamanje"</string>
+ <string name="lock_screen_search_terms" msgid="2678486357779794826">"Ukukhiya kwedivayisi, Ukukhiya isikrini, Khiya isikrini, Khiya isikrini, Iphasiwedi, Iphinikhodi, Iphethini"</string>
+ <string name="biometrics_title" msgid="5859504610285212938">"I-biometrics"</string>
+ <string name="biometrics_search_terms" msgid="6040319118762671981">"Isigxivizo somunwe, Umunwe, Engeza isigxivizo somunwe, Ukuvula ngobuso, Ubuso"</string>
<string name="privacy_sources_title" msgid="4061110826457365957">"Ubumfihlo"</string>
<string name="privacy_sources_summary" msgid="4089719981155120864">"Ideshibhodi, izimvume, izilawuli"</string>
<string name="permission_usage_title" msgid="3633779688945350407">"Ideshibhodi yobumfihlo"</string>
<string name="permission_usage_summary" msgid="5323079206029964468">"Bonisa ukuthi yimaphi ama-app asebenzise izimvume muva nje"</string>
+ <string name="permission_usage_search_terms" msgid="3852343592870257104">"Ubumfihlo, Ideshibhodi yobumfihlo"</string>
<string name="permission_manager_title" msgid="5277347862821255015">"Isiphathi semvume"</string>
<string name="permission_manager_summary" msgid="8099852107340970790">"Lawula ukufinyelela kwi-app kudatha yakho"</string>
+ <string name="permission_manager_search_terms" msgid="2895147613099694722">"Izimvume, Umphathi wezimvume"</string>
<string name="privacy_controls_title" msgid="5322875777945432395">"Izilawuli zokwemfihlo"</string>
<string name="privacy_controls_summary" msgid="2402066941190435424">"Lawula ukufinyelela kwedivayisi kumakrofoni, ikhamera, nokunye"</string>
+ <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Ubumfihlo, Izilawuli zokwemfihlo"</string>
<string name="advanced_title" msgid="8745436380690561172">"Amanye amasethingi"</string>
<string name="advanced_security_title" msgid="1126833338772188155">"Amasethingi okuvikeleka engeziwe"</string>
<string name="advanced_security_summary" msgid="6172253327022425123">"Ukubethela, izimfanelo, nokunye"</string>
+ <string name="advanced_security_search_terms" msgid="3350609555814362075"></string>
<string name="advanced_privacy_title" msgid="1117725225706176643">"Amasethingi obumfihlo engeziwe"</string>
<string name="advanced_privacy_summary" msgid="2281203390575069543">"Ukugcwalisa okuzenzakalelayo, izilawuli zomsebenzi, kanye nokunye"</string>
+ <string name="advanced_privacy_search_terms" msgid="5044404599789175222"></string>
</resources>
diff --git a/SafetyCenter/Resources/res/values/config.xml b/SafetyCenter/Resources/res/values/config.xml
new file mode 100644
index 000000000..6b20b69b4
--- /dev/null
+++ b/SafetyCenter/Resources/res/values/config.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: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,AndroidAdvancedPrivacy,AndroidAdvancedSecurity,AndroidBackgroundLocation,AndroidBiometrics,AndroidLockScreen,AndroidNotificationListener,AndroidPermissionAutoRevoke,AndroidPermissionManager,AndroidPermissionUsage,AndroidPrivacyControls,AndroidWorkPolicyInfo</string>
+ <!-- Comma separated list of packages that are pregranted to enable a notification listener service. For T- platforms.-->
+ <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>
+</resources>
diff --git a/SafetyCenter/Resources/res/values/strings.xml b/SafetyCenter/Resources/res/values/strings.xml
index 2b6c5b18a..7621f46cf 100644
--- a/SafetyCenter/Resources/res/values/strings.xml
+++ b/SafetyCenter/Resources/res/values/strings.xml
@@ -26,21 +26,29 @@
<string name="lock_screen_sources_summary" description="The summary of the group of safety settings relating to screen lock and biometrics, which describes the group contents"></string>
<string name="lock_screen_title" description="The default title of the setting for managing the screen lock on the device">Screen lock</string>
<string name="lock_screen_summary_disabled" description="The default summary of the setting for managing screen lock on the device before the current state is known to safety center">No info yet</string>
+ <string name="lock_screen_search_terms" description="Search keywords of the setting for managing the screen lock on the device">Device lock, Screen lock, Lock screen, Lockscreen, Password, Pin, Pattern</string>
+ <string name="biometrics_title" description="The default title of the setting for managing biometric options on the device">Biometrics</string>
+ <string name="biometrics_search_terms" description="Search keywords of the setting for managing biometric options on the device">Fingerprint, Finger, Add fingerprint, Face unlock, Face</string>
<!-- Privacy -->
<string name="privacy_sources_title" description="The title of the group of safety settings relating to privacy">Privacy</string>
<string name="privacy_sources_summary" description="The summary of the group of safety settings relating to privacy, which describes the group contents">Dashboard, permissions, controls</string>
<string name="permission_usage_title" description="Permission usage title">Privacy dashboard</string>
<string name="permission_usage_summary" description="Permission usage summary, which describes what the permissions usage does">Show which apps recently used permissions</string>
+ <string name="permission_usage_search_terms" description="Permission usage search keywords">Privacy, Privacy dashboard</string>
<string name="permission_manager_title" description="Permission manager title">Permission manager</string>
<string name="permission_manager_summary" description="Permission manager summary, which describes what the permission manager does">Control app access to your data</string>
+ <string name="permission_manager_search_terms" description="Permission manager search keywords">Permissions, Permissions manager</string>
<string name="privacy_controls_title" description="Privacy controls title">Privacy controls</string>
<string name="privacy_controls_summary" description="Privacy controls summary, which describes what the privacy controls are">Control device access to microphone, camera, and more</string>
+ <string name="privacy_controls_search_terms" description="Privacy controls search keywords">Privacy, Privacy controls</string>
<!-- Advanced -->
<string name="advanced_title" description="The title of the group of advanced settings">More settings</string>
<string name="advanced_security_title" description="The title of the entry for advanced security settings">More security settings</string>
<string name="advanced_security_summary" description="The summary of the entry for advanced security settings, which describes the page contents">Encryption, credentials, and more</string>
+ <string name="advanced_security_search_terms" description="Search keywords of the entry for advanced security settings"></string>
<string name="advanced_privacy_title" description="The title of the entry for advanced privacy settings">More privacy settings</string>
<string name="advanced_privacy_summary" description="The summary of the entry for advanced privacy settings, which describes the page contents">Autofill, activity controls, and more</string>
+ <string name="advanced_privacy_search_terms" description="Search keywords of the entry for advanced privacy settings"></string>
</resources>
diff --git a/SafetyCenter/Resources/shared_res/drawable-v33/ic_notification_badge_critical.xml b/SafetyCenter/Resources/shared_res/drawable-v33/ic_notification_badge_critical.xml
new file mode 100644
index 000000000..a2cb3eb0e
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/drawable-v33/ic_notification_badge_critical.xml
@@ -0,0 +1,18 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <path
+ android:pathData="m2,3.924v4.394c0.015,0.742 0.073,1.482 0.173,2.218 0.474,3.182 2.271,6.786 7.194,9.311 0.196,0.1 0.413,0.153 0.633,0.153 0.22,0 0.437,-0.052 0.633,-0.153 4.924,-2.526 6.72,-6.13 7.194,-9.312 0.1,-0.735 0.158,-1.475 0.173,-2.217L18,3.924c0,-0.336 -0.104,-0.664 -0.298,-0.94 -0.194,-0.275 -0.469,-0.484 -0.787,-0.599l-6.354,-2.288c-0.362,-0.13 -0.759,-0.13 -1.121,0L3.085,2.385c-0.318,0.115 -0.593,0.324 -0.787,0.599 -0.194,0.275 -0.298,0.603 -0.298,0.94zM16,8.297L16,4.181l-6,-2.16 -6,2.16v4.116c0.014,0.654 0.065,1.307 0.153,1.956 0.38,2.527 1.759,5.473 5.847,7.667 4.089,-2.195 5.468,-5.14 5.847,-7.668 0.088,-0.649 0.139,-1.301 0.153,-1.956zM9.883,1.979 L9.883,1.979z"
+ android:fillColor="#000000"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M8.751,10.233V4.353h2.5v5.88z"
+ android:fillColor="#000000"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="m8.751,14.941v-2.65h2.5v2.65z"
+ android:fillColor="#000000"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/SafetyCenter/Resources/shared_res/drawable-v33/ic_notification_badge_general.xml b/SafetyCenter/Resources/shared_res/drawable-v33/ic_notification_badge_general.xml
new file mode 100644
index 000000000..04fabfca6
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/drawable-v33/ic_notification_badge_general.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <path
+ android:pathData="M16.929,2.4L10.565,0.1C10.385,0.03 10.195,0 10.005,0C9.815,0 9.625,0.03 9.445,0.1L3.081,2.4C2.43,2.63 2,3.25 2,3.94V8.32C2.02,9.07 2.07,9.79 2.17,10.54C2.64,13.72 4.442,17.33 9.375,19.85C9.575,19.95 9.785,20 10.005,20C10.225,20 10.435,19.95 10.635,19.85C11.086,19.62 11.506,19.37 11.906,19.12C12.046,19.05 12.186,18.96 12.326,18.86C15.989,16.43 17.42,13.32 17.83,10.54C17.93,9.8 17.99,9.07 18,8.32V3.94C18,3.25 17.57,2.64 16.919,2.4H16.929ZM10.255,17.78C10.105,17.87 9.905,17.87 9.745,17.78C6.503,15.97 4.622,13.43 4.151,10.27C4.061,9.59 4.011,8.94 4.001,8.32V4.55C4.001,4.34 4.131,4.15 4.331,4.08L6.263,3.38C6.113,3.89 6.033,4.44 6.033,5.04C6.043,6.91 7.033,8.68 8.704,9.8C9.154,10.08 10.395,10.89 10.785,11.19C11.276,11.57 11.956,12.21 12.266,12.74C13.297,14.52 12.266,16.46 11.106,17.27C10.835,17.45 10.555,17.62 10.255,17.79V17.78ZM15.859,10.24C15.668,11.49 15.268,12.63 14.658,13.68C14.578,13.04 14.378,12.38 13.998,11.74C13.427,10.75 12.337,9.86 12.016,9.61C11.476,9.19 9.945,8.22 9.795,8.12C8.694,7.39 8.044,6.23 8.034,4.99C8.034,3.01 9.255,2.34 9.985,2.12C10.085,2.09 10.195,2.1 10.295,2.13L15.689,4.08C15.889,4.15 16.019,4.34 16.019,4.55V8.28C16.009,8.94 15.959,9.59 15.869,10.24H15.859Z"
+ android:fillColor="#000000"/>
+</vector>
diff --git a/SafetyCenter/Resources/shared_res/values-af/strings.xml b/SafetyCenter/Resources/shared_res/values-af/strings.xml
new file mode 100644
index 000000000..9ab860ecf
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-af/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Toestel is dalk in gevaar"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Toestel is in gevaar"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Jou data is dalk in gevaar"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Jou data is in gevaar"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Wagwoorde is gekompromitteer (oud)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Wagwoorde is gekompromitteer (nuut)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Jy is dalk in gevaar"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Jy is in gevaar"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Sekuriteit en privaatheid"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Aanbevelings"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Waarskuwings"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Noodsaaklike waarskuwings"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-am/strings.xml b/SafetyCenter/Resources/shared_res/values-am/strings.xml
new file mode 100644
index 000000000..093dda2f2
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-am/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <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>
+ <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_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="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>
+ <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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-ar/strings.xml b/SafetyCenter/Resources/shared_res/values-ar/strings.xml
new file mode 100644
index 000000000..ce0b1c10d
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-ar/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <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>
+ <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_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="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>
+ <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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-as/strings.xml b/SafetyCenter/Resources/shared_res/values-as/strings.xml
new file mode 100644
index 000000000..473003f59
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-as/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <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>
+ <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_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="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>
+ <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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-az/strings.xml b/SafetyCenter/Resources/shared_res/values-az/strings.xml
new file mode 100644
index 000000000..e3c31a178
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-az/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Cihaz risk altında ola bilər"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Cihaz risk altındadır"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Datanız risk altında ola bilər"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Datanız risk altındadır"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Parollar oğurlanıb (köhnə)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Parollar oğurlanıb (yeni)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Risk altında ola bilərsiniz"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Risk altındasınız"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Güvənlik və məxfilik"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Tövsiyələr"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Xəbərdarlıqlar"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Kritik xəbərdarlıqlar"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-b+sr+Latn/strings.xml b/SafetyCenter/Resources/shared_res/values-b+sr+Latn/strings.xml
new file mode 100644
index 000000000..5233edc91
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Uređaj je možda ugrožen"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Uređaj je ugrožen"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Podaci su možda ugroženi"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Podaci su ugroženi"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Lozinke su ugrožene (stare)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Lozinke su ugrožene (nove)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Možda ste ugroženi"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Ugroženi ste"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Bezbednost i privatnost"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Preporuke"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Upozorenja"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Ozbiljna upozorenja"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-be/strings.xml b/SafetyCenter/Resources/shared_res/values-be/strings.xml
new file mode 100644
index 000000000..2b386f3e6
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-be/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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>
+ <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_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="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>
+ <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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-bg/strings.xml b/SafetyCenter/Resources/shared_res/values-bg/strings.xml
new file mode 100644
index 000000000..85833f145
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-bg/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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_name_information" msgid="2966444432152990166">"Препоръки"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Предупреждения"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Критични предупреждения"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-bn/strings.xml b/SafetyCenter/Resources/shared_res/values-bn/strings.xml
new file mode 100644
index 000000000..30904c97e
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-bn/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <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>
+ <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_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="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>
+ <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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-bs/strings.xml b/SafetyCenter/Resources/shared_res/values-bs/strings.xml
new file mode 100644
index 000000000..93cfcf8fa
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-bs/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Uređaj bi mogao biti izložen riziku"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Uređaj je izložen riziku"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Vaši podaci bi mogli biti izloženi riziku"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Vaši podaci su izloženi riziku"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Lozinke su ugrožene (stare)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Lozinke su ugrožene (nove)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Možda ste izloženi riziku"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Izloženi ste riziku"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Sigurnost i privatnost"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Preporuke"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Upozorenja"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Kritična upozorenja"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-ca/strings.xml b/SafetyCenter/Resources/shared_res/values-ca/strings.xml
new file mode 100644
index 000000000..ae998b815
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-ca/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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 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">"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>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Contrasenyes en perill (noves)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Pot ser que estiguis en perill"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Estàs en perill"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Seguretat i privadesa"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Recomanacions"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Advertiments"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Advertiments importants"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-cs/strings.xml b/SafetyCenter/Resources/shared_res/values-cs/strings.xml
new file mode 100644
index 000000000..9d90b05aa
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-cs/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Zařízení může být ohroženo"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Zařízení je ohroženo"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Data mohou být ohrožena"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Data jsou ohrožena"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Prolomená hesla (staré)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Prolomená hesla (nové)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Můžete být ohroženi"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Jste v ohrožení"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Zabezpečení a ochrana soukromí"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Doporučení"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Upozornění"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Kritická upozornění"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-da/strings.xml b/SafetyCenter/Resources/shared_res/values-da/strings.xml
new file mode 100644
index 000000000..bce5898fa
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-da/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Enheden kan være sårbar"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Enheden er sårbar"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Dine data kan være sårbare"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Dine data er sårbare"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Kompromitterede adgangskoder (gamle)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Kompromitterede adgangskoder (nye)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Din konto er muligvis sårbar"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Din konto er sårbar"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Sikkerhed og privatliv"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Anbefalinger"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Advarsler"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Kritiske advarsler"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-de/strings.xml b/SafetyCenter/Resources/shared_res/values-de/strings.xml
new file mode 100644
index 000000000..0a1bf2a45
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-de/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Gerät ist eventuell gefährdet"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Gerät ist gefährdet"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Daten eventuell gefährdet"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Daten gefährdet"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"(Alte) Passwörter gefährdet"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"(Neue) Passwörter gefährdet"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Du bist möglicherweise gefährdet"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Du bist gefährdet"</string>
+ <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="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_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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-el/strings.xml b/SafetyCenter/Resources/shared_res/values-el/strings.xml
new file mode 100644
index 000000000..ac93dedd8
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-el/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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_name_information" msgid="2966444432152990166">"Προτάσεις"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Ειδοποιήσεις"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Σημαντικές ειδοποιήσεις"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-en-rAU/strings.xml b/SafetyCenter/Resources/shared_res/values-en-rAU/strings.xml
new file mode 100644
index 000000000..7e0312660
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-en-rAU/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Device may be at risk"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Device is at risk"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Your data may be at risk"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Your data is at risk"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Passwords compromised (old)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Passwords compromised (new)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"You may be at risk"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"You are at risk"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Security and privacy"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Recommendations"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Warnings"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Critical warnings"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-en-rCA/strings.xml b/SafetyCenter/Resources/shared_res/values-en-rCA/strings.xml
new file mode 100644
index 000000000..f63228247
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-en-rCA/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Device may be at risk"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Device is at risk"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Your data may be at risk"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Your data is at risk"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Passwords compromised (old)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Passwords compromised (new)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"You may be at risk"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"You are at risk"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Security and privacy"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Recommendations"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Warnings"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Critical warnings"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-en-rGB/strings.xml b/SafetyCenter/Resources/shared_res/values-en-rGB/strings.xml
new file mode 100644
index 000000000..7e0312660
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-en-rGB/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Device may be at risk"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Device is at risk"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Your data may be at risk"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Your data is at risk"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Passwords compromised (old)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Passwords compromised (new)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"You may be at risk"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"You are at risk"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Security and privacy"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Recommendations"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Warnings"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Critical warnings"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-en-rIN/strings.xml b/SafetyCenter/Resources/shared_res/values-en-rIN/strings.xml
new file mode 100644
index 000000000..7e0312660
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-en-rIN/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Device may be at risk"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Device is at risk"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Your data may be at risk"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Your data is at risk"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Passwords compromised (old)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Passwords compromised (new)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"You may be at risk"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"You are at risk"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Security and privacy"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Recommendations"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Warnings"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Critical warnings"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-en-rXC/strings.xml b/SafetyCenter/Resources/shared_res/values-en-rXC/strings.xml
new file mode 100644
index 000000000..d1cd45d43
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-en-rXC/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‏‏‏‎‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‏‎‎‏‏‎‏‏‎‏‏‏‏‏‎‎‎‎‏‏‎Device may be at risk‎‏‎‎‏‎"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‏‏‎‎‏‎‏‏‎‎‎‏‎‏‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‎Device is at risk‎‏‎‎‏‎"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‏‏‎‎‎‏‎‎‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‏‏‏‎‎‏‎‏‎‏‎‏‏‎‏‎‎‎‎‎‏‎‏‎‎‎‎‎‏‏‎‎Your data may be at risk‎‏‎‎‏‎"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‏‏‎‏‏‏‎‏‏‎‎‏‎‎‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‎‏‎‎‎‏‎‎‎‏‎‎‏‏‏‎‏‏‎‏‏‎‎‎Your data is at risk‎‏‎‎‏‎"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‏‏‎‎‏‎‎‏‏‏‎‏‎‎‏‎‏‎‎‏‎‏‏‏‎Passwords compromised (old)‎‏‎‎‏‎"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‎‎‎‏‏‏‏‎‎‏‎‏‎‎‎‎‎‎‏‏‎‏‏‎‏‎‎‎‎‏‎‏‎‎‏‏‎‏‏‎‏‏‏‎‎‎‏‎‎‎‏‎Passwords compromised (new)‎‏‎‎‏‎"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‎‏‏‎‏‏‏‏‎‏‏‎‎‏‎‏‏‎‏‎‎‎‎‎‎‎‎‎‏‎‎‎‏‏‎You may be at risk‎‏‎‎‏‎"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‎‎‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‏‏‎‎‎‎‎‎‏‎‎‎‎‎‎‏‏‏‏‏‎‎You are at risk‎‏‎‎‏‎"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‎‏‎‏‎‏‏‏‎‎‎‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‎‎‏‏‏‎‏‏‎Security &amp; privacy‎‏‎‎‏‎"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‏‎‏‎‏‏‏‎‏‏‎‏‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‏‏‎‏‎‏‎‎‎‎‏‎‎‎‏‏‏‎‏‎‏‏‎‎Recommendations‎‏‎‎‏‎"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‏‏‏‏‎‎‏‏‎‎‎‎‏‎‎‎‎‏‎‎‏‏‎‎‎‎‏‎‎‎‏‎‎‏‎‎‎‎‏‏‎‎‎‎‏‎‎‎‎‏‎‎Warnings‎‏‎‎‏‎"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‎‎‎‎‎‏‏‎‏‎‏‎‎‏‎‎‏‎‏‏‎‏‏‏‎‏‎‎‏‎‏‏‎‎‎‏‏‎‎‏‎‏‎‎‎‏‏‎‎‏‎Critical warnings‎‏‎‎‏‎"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-es-rUS/strings.xml b/SafetyCenter/Resources/shared_res/values-es-rUS/strings.xml
new file mode 100644
index 000000000..b94198674
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-es-rUS/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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">"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>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Tus datos podrían estar en riesgo"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Tus datos están en riesgo"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Contraseñas comprometidas (viejas)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Contraseñas comprometidas (nuevas)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Es posible que estés en peligro"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Estás en peligro"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Seguridad y privacidad"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Recomendaciones"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Advertencias"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Advertencias críticas"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-es/strings.xml b/SafetyCenter/Resources/shared_res/values-es/strings.xml
new file mode 100644
index 000000000..245d3394c
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-es/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"El dispositivo puede estar en riesgo"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"El dispositivo está en riesgo"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Tus datos pueden estar en riesgo"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Tus datos están en riesgo"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Contraseñas vulneradas (antiguas)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Contraseñas vulneradas (nuevas)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Puedes estar en riesgo"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Estás en riesgo"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Seguridad y privacidad"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Recomendaciones"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Advertencias"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Advertencias críticas"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-et/strings.xml b/SafetyCenter/Resources/shared_res/values-et/strings.xml
new file mode 100644
index 000000000..0aab37815
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-et/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Seade võib olla ohus"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Seade on ohus"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Teie andmed võivad ohus olla"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Teie andmed on ohus"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Paroolid on ohus (vana)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Paroolid on ohus (uus)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Võite olla ohus"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Olete ohus"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Turvalisus ja privaatsus"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Soovitused"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Hoiatused"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Kriitilised hoiatused"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-eu/strings.xml b/SafetyCenter/Resources/shared_res/values-eu/strings.xml
new file mode 100644
index 000000000..88942a47b
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-eu/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Baliteke gailua arriskuan egotea"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Gailua arriskuan dago"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Baliteke datuak arriskuan egotea"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Datuak arriskuan daude"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Pasahitz zaharrak arriskuan daude"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Pasahitz berriak arriskuan daude"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Baliteke arriskuan egotea"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Arriskuan zaude"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Segurtasuna eta pribatutasuna"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Gomendioak"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Abisuak"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Abisu larriak"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-fa/strings.xml b/SafetyCenter/Resources/shared_res/values-fa/strings.xml
new file mode 100644
index 000000000..df11d470f
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-fa/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <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>
+ <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_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="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>
+ <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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-fi/strings.xml b/SafetyCenter/Resources/shared_res/values-fi/strings.xml
new file mode 100644
index 000000000..bad542e6d
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-fi/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Laite saattaa olla vaarantunut"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Laite on vaarantunut"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Data voi olla vaarantunut"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Data on vaarantunut"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"(Vanhat) salasanat vaarantuneet"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"(Uudet) salasanat vaarantuneet"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Turvallisuutesi on voinut vaarantua"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Turvallisuutesi on vaarantanut"</string>
+ <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="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">"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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-fr-rCA/strings.xml b/SafetyCenter/Resources/shared_res/values-fr-rCA/strings.xml
new file mode 100644
index 000000000..c1530b2cb
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-fr-rCA/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"L\'appareil pourrait être en danger"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"L\'appareil est en danger"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Vos données pourraient être en danger"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Vos données sont en danger"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Mots de passe compromis (ancien)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Mots de passe compromis (nouveau)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Vous pourriez être en danger"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Vous êtes en danger"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Sécurité et confidentialité"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Recommandations"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Avertissements"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Avertissements critiques"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-fr/strings.xml b/SafetyCenter/Resources/shared_res/values-fr/strings.xml
new file mode 100644
index 000000000..d7bf215a0
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-fr/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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">"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>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Mots de passe compromis (nouveaux)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Risque potentiel"</string>
+ <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">"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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Sécurité et confidentialité"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Recommandations"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Avertissements"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Avertissements critiques"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-gl/strings.xml b/SafetyCenter/Resources/shared_res/values-gl/strings.xml
new file mode 100644
index 000000000..ea934a37b
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-gl/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"O dispositivo pode estar en risco"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"O dispositivo está en risco"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Os teus datos poden estar en risco"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Os teus datos están en risco"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Contrasinais vulnerados (antigos)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Contrasinais vulnerados (novos)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Pode que a túa conta estea en risco"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"A túa conta está en risco"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Seguranza e privacidade"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Recomendacións"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Advertencias"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Advertencias importantes"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-gu/strings.xml b/SafetyCenter/Resources/shared_res/values-gu/strings.xml
new file mode 100644
index 000000000..0894b304b
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-gu/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <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>
+ <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_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="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>
+ <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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-hi/strings.xml b/SafetyCenter/Resources/shared_res/values-hi/strings.xml
new file mode 100644
index 000000000..c9a80e7f0
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-hi/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <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>
+ <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_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="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>
+ <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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-hr/strings.xml b/SafetyCenter/Resources/shared_res/values-hr/strings.xml
new file mode 100644
index 000000000..ed02bc991
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-hr/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Uređaj je možda ugrožen"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Uređaj je ugrožen"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Podaci mogu biti ugroženi"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Podaci su ugroženi"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Zaporke su ugrožene (staro)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Zaporke su ugrožene (novo)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Vaša je sigurnost možda ugrožena"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Vaša je sigurnost ugrožena"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Sigurnost i privatnost"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Preporuke"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Upozorenja"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Kritična upozorenja"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-hu/strings.xml b/SafetyCenter/Resources/shared_res/values-hu/strings.xml
new file mode 100644
index 000000000..5f97845bc
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-hu/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Az eszközhasználat kockázatos lehet"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Az eszköz használata kockázatos"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Adatai veszélyben lehetnek"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Adatai veszélyben vannak"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Feltört jelszavak (régi)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Feltört jelszavak (új)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Veszélyben lehet"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Veszélyben van"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Biztonság és adatvédelem"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Javaslatok"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Figyelmeztetések"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Fontos figyelmeztetések"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-hy/strings.xml b/SafetyCenter/Resources/shared_res/values-hy/strings.xml
new file mode 100644
index 000000000..befaeb8e5
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-hy/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <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>
+ <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_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="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>
+ <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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-in/strings.xml b/SafetyCenter/Resources/shared_res/values-in/strings.xml
new file mode 100644
index 000000000..cd584dbab
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-in/strings.xml
@@ -0,0 +1,51 @@
+<?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="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">"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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Perangkat mungkin berisiko"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Perangkat berisiko"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Data Anda mungkin berisiko"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Data Anda berisiko"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Sandi disusupi (lama)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Sandi disusupi (baru)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Anda mungkin berisiko"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Anda berisiko"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Keamanan &amp; privasi"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Rekomendasi"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Peringatan"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Peringatan penting"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-is/strings.xml b/SafetyCenter/Resources/shared_res/values-is/strings.xml
new file mode 100644
index 000000000..3e36f81f1
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-is/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Tækið er hugsanlega í hættu"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Tækið er í hættu"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Gögnin þín gætu verið í hættu"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Gögnin þín eru í hættu"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Aðgangsorð í hættu (gömul)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Aðgangsorð í hættu (ný)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Þú gætir verið í hættu"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Þú ert í hættu"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Öryggi og persónuvernd"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Tillögur"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Viðvaranir"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Alvarlegar viðvaranir"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-it/strings.xml b/SafetyCenter/Resources/shared_res/values-it/strings.xml
new file mode 100644
index 000000000..68aa4eab3
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-it/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Il dispositivo potrebbe essere a rischio"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Il dispositivo è a rischio"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"I dati potrebbero essere a rischio"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"I dati sono a rischio"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Password compromesse (precedenti)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Password compromesse (nuove)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Potresti essere a rischio"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Sei a rischio"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Sicurezza e privacy"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Consigli"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Avvisi"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Avvisi critici"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-iw/strings.xml b/SafetyCenter/Resources/shared_res/values-iw/strings.xml
new file mode 100644
index 000000000..05cb0cd18
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-iw/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <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>
+ <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_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="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>
+ <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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-ja/strings.xml b/SafetyCenter/Resources/shared_res/values-ja/strings.xml
new file mode 100644
index 000000000..aa760e5d7
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-ja/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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_name_information" msgid="2966444432152990166">"推奨事項"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"警告"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"重大な警告"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-ka/strings.xml b/SafetyCenter/Resources/shared_res/values-ka/strings.xml
new file mode 100644
index 000000000..4dda15927
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-ka/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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_name_information" msgid="2966444432152990166">"რეკომენდაციები"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"შენიშვნები"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"კრიტიკულად მნიშვნელ. გაფრთხილებები"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-kk/strings.xml b/SafetyCenter/Resources/shared_res/values-kk/strings.xml
new file mode 100644
index 000000000..5ea3fa3e1
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-kk/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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">"Параметрлерді тексер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>
+ <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_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="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_name_information" msgid="2966444432152990166">"Ұсыныстар"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Хабарландырулар"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Маңызды хабарландырулар"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-km/strings.xml b/SafetyCenter/Resources/shared_res/values-km/strings.xml
new file mode 100644
index 000000000..d2bf8fc48
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-km/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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_name_information" msgid="2966444432152990166">"ការណែនាំ"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"សារប្រុងប្រយ័ត្ន"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"សារប្រុងប្រយ័ត្នសំខាន់ៗ"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-kn/strings.xml b/SafetyCenter/Resources/shared_res/values-kn/strings.xml
new file mode 100644
index 000000000..9c3cb9dca
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-kn/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <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>
+ <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_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="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>
+ <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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-ko/strings.xml b/SafetyCenter/Resources/shared_res/values-ko/strings.xml
new file mode 100644
index 000000000..295fe4992
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-ko/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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_name_information" msgid="2966444432152990166">"권장사항"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"경고"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"심각한 경고"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-ky/strings.xml b/SafetyCenter/Resources/shared_res/values-ky/strings.xml
new file mode 100644
index 000000000..2da0e82e4
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-ky/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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_name_information" msgid="2966444432152990166">"Cунуштар"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Эскертүүлөр"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Олуттуу эскертүүлөр"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-lo/strings.xml b/SafetyCenter/Resources/shared_res/values-lo/strings.xml
new file mode 100644
index 000000000..724411879
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-lo/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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_name_information" msgid="2966444432152990166">"ການແນະນຳ"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"ຄໍາເຕືອນ"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"ຄຳເຕືອນວິກິດ"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-lt/strings.xml b/SafetyCenter/Resources/shared_res/values-lt/strings.xml
new file mode 100644
index 000000000..fc1704c13
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-lt/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Įrenginiui gali grėsti pavojus"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Įrenginiui gresia pavojus"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Jūsų duomenims galėjo kilti pavojus"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Jūsų duomenims kilo pavojus"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Slaptažodžiai pažeisti (seni)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Slaptažodžiai pažeisti (nauji)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Jums gali kilti pavojus"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Jums iškilo pavojus"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Sauga ir privatumas"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Rekomendacijos"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Perspėjimai"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Kritiniai perspėjimai"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-lv/strings.xml b/SafetyCenter/Resources/shared_res/values-lv/strings.xml
new file mode 100644
index 000000000..c27624603
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-lv/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Iespējams, ierīce ir apdraudēta"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Ierīce ir apdraudēta"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Jūsu dati var būt apdraudēti"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Jūsu dati ir apdraudēti"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Uzlauztas paroles (vecas)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Uzlauztas paroles (jaunas)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Iespējams, jūs esat apdraudēts"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Jūs esat apdraudēts"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Drošība un konfidencialitāte"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Ieteikumi"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Brīdinājumi"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Kritiski brīdinājumi"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-mk/strings.xml b/SafetyCenter/Resources/shared_res/values-mk/strings.xml
new file mode 100644
index 000000000..2ba7a1976
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-mk/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <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>
+ <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_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="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>
+ <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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-ml/strings.xml b/SafetyCenter/Resources/shared_res/values-ml/strings.xml
new file mode 100644
index 000000000..a05a7eed1
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-ml/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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_name_information" msgid="2966444432152990166">"നിർദ്ദേശങ്ങൾ"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"മുന്നറിയിപ്പുകൾ"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"പ്രധാനപ്പെട്ട മുന്നറിയിപ്പുകൾ"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-mn/strings.xml b/SafetyCenter/Resources/shared_res/values-mn/strings.xml
new file mode 100644
index 000000000..8b2f17f37
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-mn/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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">"Аюулгүй байдал &amp; нууцлал"</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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-mr/strings.xml b/SafetyCenter/Resources/shared_res/values-mr/strings.xml
new file mode 100644
index 000000000..f406a2931
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-mr/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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_name_information" msgid="2966444432152990166">"शिफारशी"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"चेतावण्या"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"महत्त्वाच्या चेतावण्या"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-ms/strings.xml b/SafetyCenter/Resources/shared_res/values-ms/strings.xml
new file mode 100644
index 000000000..bb98c69d0
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-ms/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Peranti mungkin berisiko"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Peranti berisiko"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Data anda mungkin berisiko"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Data anda berisiko"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Kata laluan terjejas (lama)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Kata laluan terjejas (baharu)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Anda mungkin berisiko"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Anda berisiko"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Keselamatan &amp; privasi"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Syor"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Amaran"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Amaran kritikal"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-my/strings.xml b/SafetyCenter/Resources/shared_res/values-my/strings.xml
new file mode 100644
index 000000000..af7f71a34
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-my/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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_name_information" msgid="2966444432152990166">"အကြံပြုချက်များ"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"သတိပေးချက်များ"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"အရေးကြီးသော သတိပေးချက်များ"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-nb/strings.xml b/SafetyCenter/Resources/shared_res/values-nb/strings.xml
new file mode 100644
index 000000000..8365aaea8
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-nb/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Enheten kan være i faresonen"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Enheten er i faresonen"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Dataene dine kan være i faresonen"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Dataene dine er i faresonen"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Passord har sikkerhetsbrudd (gamle)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Passord har sikkerhetsbrudd (nye)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Du kan være utsatt for risiko"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Du er utsatt for risiko"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Sikkerhet og personvern"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Anbefalinger"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Advarsler"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Kritiske advarsler"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-ne/strings.xml b/SafetyCenter/Resources/shared_res/values-ne/strings.xml
new file mode 100644
index 000000000..4e55d23f1
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-ne/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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_name_information" msgid="2966444432152990166">"सिफारिसहरू"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"चेतावनीहरू"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"महत्त्वपूर्ण चेतावनीहरू"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-night/colors.xml b/SafetyCenter/Resources/shared_res/values-night/colors.xml
new file mode 100644
index 000000000..be7a96628
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-night/colors.xml
@@ -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.
+ -->
+
+<resources>
+ <color name="notification_tint_critical">#EE675C</color>
+ <color name="notification_tint_normal">#8AB4F8</color>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-nl/strings.xml b/SafetyCenter/Resources/shared_res/values-nl/strings.xml
new file mode 100644
index 000000000..b916f37bc
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-nl/strings.xml
@@ -0,0 +1,51 @@
+<?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="scanning_title" msgid="5424849039854311398">"Scannen"</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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Apparaat loopt misschien gevaar"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Apparaat loopt gevaar"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Je gegevens lopen misschien gevaar"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Je gegevens lopen risico"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Wachtwoorden gehackt (oud)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Wachtwoorden gehackt (nieuw)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Je loopt misschien gevaar"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Je account loopt gevaar"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Beveiliging en privacy"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Aanbevelingen"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Waarschuwingen"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Kritieke waarschuwingen"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-or/strings.xml b/SafetyCenter/Resources/shared_res/values-or/strings.xml
new file mode 100644
index 000000000..cf550456f
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-or/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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_name_information" msgid="2966444432152990166">"ସୁପାରିଶଗୁଡ଼ିକ"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"ଚେତାବନୀଗୁଡ଼ିକ"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"ଗୁରୁତ୍ୱପୂର୍ଣ୍ଣ ଚେତାବନୀଗୁଡ଼ିକ"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-pa/strings.xml b/SafetyCenter/Resources/shared_res/values-pa/strings.xml
new file mode 100644
index 000000000..e13d6327f
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-pa/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <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>
+ <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_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="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>
+ <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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-pl/strings.xml b/SafetyCenter/Resources/shared_res/values-pl/strings.xml
new file mode 100644
index 000000000..23a331b7f
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-pl/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Urządzenie może być zagrożone"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Urządzenie jest zagrożone"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Dane mogą być zagrożone"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Dane są zagrożone"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Przejęte hasła (stare)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Przejęte hasła (nowe)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Twoje bezpieczeństwo może być zagrożone"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Twoje bezpieczeństwo jest zagrożone"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Bezpieczeństwo i prywatność"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Rekomendacje"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Ostrzeżenia"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Ostrzeżenia o znaczeniu krytycznym"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-pt-rBR/strings.xml b/SafetyCenter/Resources/shared_res/values-pt-rBR/strings.xml
new file mode 100644
index 000000000..b9d887f78
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-pt-rBR/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <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>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Seus dados podem estar em risco"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Seus dados estão em risco"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Senhas comprometidas (antigas)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Senhas comprometidas (novas)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Você pode estar em risco"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Você está em risco"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Segurança e privacidade"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Recomendações"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Avisos"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Avisos críticos"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-pt-rPT/strings.xml b/SafetyCenter/Resources/shared_res/values-pt-rPT/strings.xml
new file mode 100644
index 000000000..592e1b60a
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-pt-rPT/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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">"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>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Os seus dados podem estar em risco"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Os seus dados estão em risco"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Pal.-passe antigas comprometidas"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Palavras-passe novas comprometidas"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Pode estar em risco"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Está em risco"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Segurança e privacidade"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Recomendações"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Avisos"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Avisos críticos"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-pt/strings.xml b/SafetyCenter/Resources/shared_res/values-pt/strings.xml
new file mode 100644
index 000000000..b9d887f78
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-pt/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <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>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Seus dados podem estar em risco"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Seus dados estão em risco"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Senhas comprometidas (antigas)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Senhas comprometidas (novas)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Você pode estar em risco"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Você está em risco"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Segurança e privacidade"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Recomendações"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Avisos"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Avisos críticos"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-ro/strings.xml b/SafetyCenter/Resources/shared_res/values-ro/strings.xml
new file mode 100644
index 000000000..e64b8b497
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-ro/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Dispozitivul poate fi expus la risc"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Dispozitivul este expus riscului"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Datele tale pot fi în pericol"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Datele tale sunt în pericol"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Parole compromise (vechi)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Parole compromise (noi)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"E posibil să fii expus(ă) la risc"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Ești expus(ă) la risc"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Securitate și confidențialitate"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Recomandări"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Avertismente"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Avertismente critice"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-ru/strings.xml b/SafetyCenter/Resources/shared_res/values-ru/strings.xml
new file mode 100644
index 000000000..832dd396c
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-ru/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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>
+ <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_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="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>
+ <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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-si/strings.xml b/SafetyCenter/Resources/shared_res/values-si/strings.xml
new file mode 100644
index 000000000..08e6787cc
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-si/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <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>
+ <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_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="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>
+ <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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-sk/strings.xml b/SafetyCenter/Resources/shared_res/values-sk/strings.xml
new file mode 100644
index 000000000..0c6da9c5b
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-sk/strings.xml
@@ -0,0 +1,51 @@
+<?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="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">"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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Zariadenie môže byť ohrozené"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Zariadenie je ohrozené"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Vaše údaje môžu byť ohrozené"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Vaše údaje sú ohrozené"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Odhalené heslá (staré)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Odhalené heslá (nové)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Vaše zabezpečenie môže byť ohrozené"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Vaše zabezpečenie je ohrozené"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Zabezpečenie a ochrana súkromia"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Odporúčania"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Varovania"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Dôležité varovania"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-sl/strings.xml b/SafetyCenter/Resources/shared_res/values-sl/strings.xml
new file mode 100644
index 000000000..c8b0d7d00
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-sl/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Naprava je morda ogrožena"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Naprava je ogrožena"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Podatki so morda ogroženi"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Podatki so ogroženi"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Gesla so ogrožena (stara)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Gesla so ogrožena (nova)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Morda ste ogroženi"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Ste ogroženi"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Varnost in zasebnost"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Priporočila"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Opozorila"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Nujna opozorila"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-sq/strings.xml b/SafetyCenter/Resources/shared_res/values-sq/strings.xml
new file mode 100644
index 000000000..68a9d3e1b
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-sq/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Pajisja mund të jetë në rrezik"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Pajisja është në rrezik"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Të dhënat e tua mund të jenë në rrezik"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Të dhënat e tua janë në rrezik"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Fjalëkalime të komprometuara (të vjetra)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Fjalëkalime të komprometuara (të reja)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Mund të jesh në rrezik"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Je në rrezik"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Siguria dhe privatësia"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Rekomandime"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Paralajmërime"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Paralajmërime kritike"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-sr/strings.xml b/SafetyCenter/Resources/shared_res/values-sr/strings.xml
new file mode 100644
index 000000000..e258d138b
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-sr/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <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>
+ <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_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="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>
+ <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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-sv/strings.xml b/SafetyCenter/Resources/shared_res/values-sv/strings.xml
new file mode 100644
index 000000000..a14fd7c8b
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-sv/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Enheten kan vara i fara"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Enheten är i fara"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Din data kan vara i fara"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Din data är i fara"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Utsatta lösenord (gamla)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Utsatta lösenord (nya)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Du kan vara i riskzonen"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Du är i riskzonen"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Säkerhet och integritet"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Rekommendationer"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Varningar"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Viktiga varningar"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-sw/strings.xml b/SafetyCenter/Resources/shared_res/values-sw/strings.xml
new file mode 100644
index 000000000..aaea33e79
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-sw/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Huenda kifaa kiko hatarini"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Kifaa kiko hatarini"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Huenda data yako iko hatarini"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Data yako iko hatarini"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Manenosiri yameathiriwa (ya zamani)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Manenosiri yameathiriwa (mapya)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Huenda uko hatarini"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Uko hatarini"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Usalama na faragha"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Mapendekezo"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Maonyo"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Maonyo muhimu"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-ta/strings.xml b/SafetyCenter/Resources/shared_res/values-ta/strings.xml
new file mode 100644
index 000000000..05eb793e9
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-ta/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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">"பாதுகாப்பு &amp; தனியுரிமை"</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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-te/strings.xml b/SafetyCenter/Resources/shared_res/values-te/strings.xml
new file mode 100644
index 000000000..1fc82228d
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-te/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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">"సెక్యూరిటీ &amp; గోప్యత"</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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-th/strings.xml b/SafetyCenter/Resources/shared_res/values-th/strings.xml
new file mode 100644
index 000000000..37f345214
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-th/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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_name_information" msgid="2966444432152990166">"คำแนะนำ"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"คำเตือน"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"คำเตือนที่สำคัญ"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-tl/strings.xml b/SafetyCenter/Resources/shared_res/values-tl/strings.xml
new file mode 100644
index 000000000..ee7210dc2
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-tl/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Posibleng nanganganib ang device"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Nanganganib ang device"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Posibleng nanganganib ang data mo"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Nanganganib ang iyong data"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Nakompromiso ang password (luma)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Nakompromiso ang password (bago)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Posibleng nanganganib ka"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Nanganganib ka"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Seguridad at privacy"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Mga Rekomendasyon"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Mga Babala"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Mga kritikal na babala"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-tr/strings.xml b/SafetyCenter/Resources/shared_res/values-tr/strings.xml
new file mode 100644
index 000000000..5a32bcfac
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-tr/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Cihaz risk altında olabilir"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Cihaz risk altında"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Verileriniz risk altında olabilir"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Verileriniz risk altında"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Şifrelerin güvenliği ihlal edildi (eski)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Şifrelerin güvenliği ihlal edildi (yeni)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Risk altında olabilirsiniz"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Risk altındasınız"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Güvenlik ve gizlilik"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Öneriler"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Uyarılar"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Kritik uyarılar"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-uk/strings.xml b/SafetyCenter/Resources/shared_res/values-uk/strings.xml
new file mode 100644
index 000000000..f103d5a4f
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-uk/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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>
+ <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_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="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>
+ <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>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-ur/strings.xml b/SafetyCenter/Resources/shared_res/values-ur/strings.xml
new file mode 100644
index 000000000..df25d9ac2
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-ur/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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_name_information" msgid="2966444432152990166">"تجاویز"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"وارننگز"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"اہم وارننگز"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-uz/strings.xml b/SafetyCenter/Resources/shared_res/values-uz/strings.xml
new file mode 100644
index 000000000..5965fb760
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-uz/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Qurilma xavf ostida boʻlishi mumkin"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Qurilma xavf ostida"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Maʼlumotlar xavf ostida shekilli"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Maʼlumotlaringiz xavf ostida"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Parollar oshkor qilindi (eski)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Parollar oshkor qilindi (yangi)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Xavf ostida boʻlishingiz mumkin"</string>
+ <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 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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Xavfsizlik va maxfiylik"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Tavsiyalar"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Ogohlantirishlar"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Jiddiy ogohlantirishlar"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-vi/strings.xml b/SafetyCenter/Resources/shared_res/values-vi/strings.xml
new file mode 100644
index 000000000..b697186e0
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-vi/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Thiết bị có thể gặp rủi ro"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Thiết bị đang gặp rủi ro"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Dữ liệu của bạn có thể gặp rủi ro"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Dữ liệu của bạn đang gặp rủi ro"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Mật khẩu bị lộ (mật khẩu cũ)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Mật khẩu bị lộ (mật khẩu mới)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Bạn có thể gặp rủi ro"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Bạn đang gặp rủi ro"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Bảo mật và quyền riêng tư"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Đề xuất"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Cảnh báo"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Cảnh báo quan trọng"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-zh-rCN/strings.xml b/SafetyCenter/Resources/shared_res/values-zh-rCN/strings.xml
new file mode 100644
index 000000000..d705612ea
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-zh-rCN/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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_name_information" msgid="2966444432152990166">"建议"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"警告"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"严重警告"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-zh-rHK/strings.xml b/SafetyCenter/Resources/shared_res/values-zh-rHK/strings.xml
new file mode 100644
index 000000000..0222a0acc
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-zh-rHK/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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_name_information" msgid="2966444432152990166">"建議"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"警告"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"嚴重警告"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-zh-rTW/strings.xml b/SafetyCenter/Resources/shared_res/values-zh-rTW/strings.xml
new file mode 100644
index 000000000..1be6fa621
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-zh-rTW/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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_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_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="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_name_information" msgid="2966444432152990166">"建議"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"警告"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"嚴重警告"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values-zu/strings.xml b/SafetyCenter/Resources/shared_res/values-zu/strings.xml
new file mode 100644
index 000000000..61096c234
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values-zu/strings.xml
@@ -0,0 +1,51 @@
+<?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="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="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>
+ <string name="overall_severity_level_device_recommendation_title" msgid="5250040236433061827">"Idivayisi ingaba sengozini"</string>
+ <string name="overall_severity_level_critical_device_warning_title" msgid="5901771721834272596">"Idivayisi isengozini"</string>
+ <string name="overall_severity_level_data_recommendation_title" msgid="1424269714861655302">"Idatha yakho isengozini"</string>
+ <string name="overall_severity_level_critical_data_warning_title" msgid="1012704126634698604">"Idatha yakho isengozini"</string>
+ <string name="overall_severity_level_passwords_recommendation_title" msgid="8625105570296877719">"Amaphasiwedi onakalisiwe (amadala)"</string>
+ <string name="overall_severity_level_critical_passwords_warning_title" msgid="7859047988648851217">"Amaphasiwedi onakalisiwe (amasha)"</string>
+ <string name="overall_severity_level_personal_recommendation_title" msgid="5493814377982623779">"Kungenzeka usengozini"</string>
+ <string name="overall_severity_level_critical_personal_warning_title" msgid="5070434468955164734">"Usengozini"</string>
+ <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="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>
+ <string name="notification_channel_group_name" msgid="7155072032524876859">"Ukuvikeleka nobumfihlo"</string>
+ <string name="notification_channel_name_information" msgid="2966444432152990166">"Izincomo"</string>
+ <string name="notification_channel_name_recommendation" msgid="7847408286580217922">"Izexwayiso"</string>
+ <string name="notification_channel_name_critical_warning" msgid="5994320322108351769">"Izixwayiso ezibucayi"</string>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values/colors.xml b/SafetyCenter/Resources/shared_res/values/colors.xml
new file mode 100644
index 000000000..ce5e97b40
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values/colors.xml
@@ -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.
+ -->
+
+<resources>
+ <color name="notification_tint_critical">#D93025</color>
+ <color name="notification_tint_normal">#1A73E8</color>
+</resources>
diff --git a/SafetyCenter/Resources/shared_res/values/strings.xml b/SafetyCenter/Resources/shared_res/values/strings.xml
new file mode 100644
index 000000000..f4f1b0201
--- /dev/null
+++ b/SafetyCenter/Resources/shared_res/values/strings.xml
@@ -0,0 +1,127 @@
+<?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">
+ <!-- Title for the overall Safety Center status when the user has requested a rescan of their security and privacy signals [CHAR LIMIT=35] -->
+ <string name="scanning_title">Scanning</string>
+
+ <!-- Summary for the overall Safety Center status when we're loading the user security and privacy signals [CHAR LIMIT=60] -->
+ <string name="loading_summary">Checking device settings…</string>
+
+ <!-- Title for the overall Safety Center status when the user security and privacy signals are deemed to be safe [CHAR LIMIT=35] -->
+ <string name="overall_severity_level_ok_title">Looks good</string>
+
+ <!-- Summary for the overall Safety Center status when the user security and privacy signals are deemed to be safe [CHAR LIMIT=60] -->
+ <string name="overall_severity_level_ok_summary">No issues found</string>
+
+ <!-- Summary for the overall Safety Center status when the user security and privacy signals are deemed to be safe, but there are some tip(s) for the user [CHAR LIMIT=60] -->
+ <string name="overall_severity_level_tip_summary">{count, plural,
+ =1 {See recommendation}
+ other {See recommendations}
+ }</string>
+
+ <!-- Summary for the overall Safety Center status when the user security and privacy signals are deemed to be safe, but some action(s) have been taken on behalf of the user [CHAR LIMIT=60] -->
+ <string name="overall_severity_level_action_taken_summary">{count, plural,
+ =1 {Action taken}
+ other {Actions taken}
+ }</string>
+
+ <!-- Title for the overall Safety Center status when the user security and privacy signals are deemed to be safe, but the user has settings that may need their review [CHAR LIMIT=35] -->
+ <string name="overall_severity_level_ok_review_title">Review settings</string>
+
+ <!-- Summary for the overall Safety Center status when the user security and privacy signals are deemed to be safe, but the user has settings that may need their review [CHAR LIMIT=60] -->
+ <string name="overall_severity_level_ok_review_summary">Check settings list</string>
+
+ <!-- Title for the overall Safety Center status when the user security and privacy signals could potentially put them at risk [CHAR LIMIT=35] -->
+ <string name="overall_severity_level_device_recommendation_title">Device may be at risk</string>
+
+ <!-- Title for the overall Safety Center status when the user security and privacy signals are putting them at risk [CHAR LIMIT=35] -->
+ <string name="overall_severity_level_critical_device_warning_title">Device is at risk</string>
+
+ <!-- Title for the overall Safety Center status when the user's data could potentially be at risk [CHAR LIMIT=35] -->
+ <string name="overall_severity_level_data_recommendation_title">Your data may be at risk</string>
+
+ <!-- Title for the overall Safety Center status when the user's data is at risk [CHAR LIMIT=35] -->
+ <string name="overall_severity_level_critical_data_warning_title">Your data is at risk</string>
+
+ <!-- Title for the overall Safety Center status when the user's passwords could potentially be at risk (old or unused passwords) [CHAR LIMIT=35] -->
+ <string name="overall_severity_level_passwords_recommendation_title">Passwords compromised (old)</string>
+
+ <!-- Title for the overall Safety Center status when the user's passwords are at risk (new passwords) [CHAR LIMIT=35] -->
+ <string name="overall_severity_level_critical_passwords_warning_title">Passwords compromised (new)</string>
+
+ <!-- Title for the overall Safety Center status when the user's personal safety could potentially be at risk [CHAR LIMIT=35] -->
+ <string name="overall_severity_level_personal_recommendation_title">You may be at risk</string>
+
+ <!-- Title for the overall Safety Center status when the user's personal safety is at risk [CHAR LIMIT=35] -->
+ <string name="overall_severity_level_critical_personal_warning_title">You are at risk</string>
+
+ <!-- Title for the overall Safety Center status when the user security and privacy signals could potentially put their general safety at risk [CHAR LIMIT=35] -->
+ <string name="overall_severity_level_safety_recommendation_title">Potential risks found</string>
+
+ <!-- Title for the overall Safety Center status when the user security and privacy signals are putting their general safety at risk [CHAR LIMIT=35] -->
+ <string name="overall_severity_level_critical_safety_warning_title">Risks found</string>
+
+ <!-- Title for the overall Safety Center status when the user security and privacy signals could potentially put their account at risk [CHAR LIMIT=35] -->
+ <string name="overall_severity_level_account_recommendation_title">Account may be at risk</string>
+
+ <!-- Title for the overall Safety Center status when the user security and privacy signals are putting their account at risk [CHAR LIMIT=35] -->
+ <string name="overall_severity_level_critical_account_warning_title">Account at risk</string>
+
+ <!-- Summary for the overall Safety Center status when the user security and privacy signals contain alerts that could range from minor suggestions to warnings or critical issues. The number of alerts is given as a parameter [CHAR LIMIT=60] -->
+ <string name="overall_severity_n_alerts_summary">{count, plural,
+ =1 {See alert}
+ other {See alerts}
+ }</string>
+
+ <!-- An error shown to the user when we failed to navigate to a specific page [CHAR LIMIT=50] -->
+ <string name="redirecting_error">Couldn\’t open page</string>
+
+ <!-- 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}
+ other {Couldn\’t check settings}
+ }</string>
+
+ <!-- The summary for sources supporting work profile shown to the user in quiet mode. [CHAR LIMIT=NONE] -->
+ <string name="work_profile_paused">Work profile is paused</string>
+
+ <!-- The summary shown to the user when a group of related sources in Safety Center all have an unknown status. We expect the status of the sources to eventually update and the summary will change [CHAR LIMIT=NONE] -->
+ <string name="group_unknown_summary">No info yet</string>
+
+ <!-- The name of the group of notification channels where Security and Privacy notifications are posted. [CHAR LIMIT=35] -->
+ <string name="notification_channel_group_name">Security &amp; privacy</string>
+
+ <!-- The name of the notification channel where lower-severity Security and Privacy notifications are posted. These are typically informational notifications and not warnings. [CHAR LIMIT=35] -->
+ <string name="notification_channel_name_information">Recommendations</string>
+
+ <!-- The name of the notification channel where medium-severity Security and Privacy notifications are posted. These notifications are typically warnings. [CHAR LIMIT=35] -->
+ <string name="notification_channel_name_recommendation">Warnings</string>
+
+ <!-- The name of the notification channel where high-severity Security and Privacy notifications are posted. These notifications are typically critical warnings of the highest severity. [CHAR LIMIT=35] -->
+ <string name="notification_channel_name_critical_warning">Critical warnings</string>
+
+ <!-- Summary of the subpage footer used for Safety Center UI tests -->
+ <string name="test_single_source_group_id_footer" translatable="false">Summary text for the footer</string>
+</resources>
+
diff --git a/SafetyCenter/ResourcesLib/Android.bp b/SafetyCenter/ResourcesLib/Android.bp
index 274386b22..ebc7aa017 100644
--- a/SafetyCenter/ResourcesLib/Android.bp
+++ b/SafetyCenter/ResourcesLib/Android.bp
@@ -25,7 +25,8 @@ java_library {
"java/**/*.java",
],
libs: [
- "framework-annotations-lib",
+ "androidx.annotation_annotation",
+ "safety-center-annotations",
],
apex_available: [
"com.android.permission",
@@ -33,5 +34,9 @@ java_library {
],
installable: false,
min_sdk_version: "30",
- sdk_version: "module_current",
+ sdk_version: "system_current",
+ visibility: [
+ "//packages/modules/Permission:__subpackages__",
+ "//vendor:__subpackages__",
+ ],
}
diff --git a/SafetyCenter/ResourcesLib/TEST_MAPPING b/SafetyCenter/ResourcesLib/TEST_MAPPING
new file mode 100644
index 000000000..2023d252b
--- /dev/null
+++ b/SafetyCenter/ResourcesLib/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "SafetyCenterResourcesLibTests"
+ }
+ ]
+}
diff --git a/SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/SafetyCenterResourcesContext.java b/SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/SafetyCenterResourcesContext.java
index 2fa6a1c28..9a77296e2 100644
--- a/SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/SafetyCenterResourcesContext.java
+++ b/SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/SafetyCenterResourcesContext.java
@@ -18,8 +18,6 @@ package com.android.safetycenter.resources;
import static java.util.Objects.requireNonNull;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
@@ -27,9 +25,14 @@ 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 com.android.internal.annotations.VisibleForTesting;
+import androidx.annotation.ColorInt;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+import androidx.annotation.VisibleForTesting;
import java.io.File;
import java.io.InputStream;
@@ -50,8 +53,7 @@ public class SafetyCenterResourcesContext extends ContextWrapper {
private static final String APEX_MODULE_NAME = "com.android.permission";
/**
- * The path where the Permission apex is mounted.
- * Current value = "/apex/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();
@@ -60,45 +62,80 @@ public class SafetyCenterResourcesContext extends ContextWrapper {
private static final String CONFIG_NAME = "safety_center_config";
/** Intent action that is used to identify the Safety Center resources APK */
- @NonNull
private final String mResourcesApkAction;
/** The path where the Safety Center resources APK is expected to be installed */
- @Nullable
- private final String mResourcesApkPath;
+ @Nullable private final String mResourcesApkPath;
/** Raw XML config resource name */
- @NonNull
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;
+ @Nullable private String mResourcesApkPkgName;
+ @Nullable private AssetManager mAssetsFromApk;
+ @Nullable private Resources mResourcesFromApk;
+ @Nullable private Resources.Theme mThemeFromApk;
- public SafetyCenterResourcesContext(@NonNull Context contextBase) {
- super(contextBase);
- mResourcesApkAction = RESOURCES_APK_ACTION;
- mResourcesApkPath = APEX_MODULE_PATH;
- mConfigName = CONFIG_NAME;
- mFlags = PackageManager.MATCH_SYSTEM_ONLY;
+ 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);
}
- SafetyCenterResourcesContext(@NonNull Context contextBase, @NonNull String resourcesApkAction,
- @Nullable String resourcesApkPath, @NonNull String configName, int flags) {
+ @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. */
@@ -109,8 +146,8 @@ public class SafetyCenterResourcesContext extends ContextWrapper {
return mResourcesApkPkgName;
}
- List<ResolveInfo> resolveInfos = getPackageManager().queryIntentActivities(
- new Intent(mResourcesApkAction), mFlags);
+ List<ResolveInfo> resolveInfos =
+ getPackageManager().queryIntentActivities(new Intent(mResourcesApkAction), mFlags);
if (resolveInfos.size() > 1) {
// multiple apps found, log a warning, but continue
@@ -118,9 +155,12 @@ public class SafetyCenterResourcesContext extends ContextWrapper {
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));
+ Log.w(
+ TAG,
+ String.format(
+ "- pkg:%s at:%s",
+ resolveInfo.activityInfo.applicationInfo.packageName,
+ resolveInfo.activityInfo.applicationInfo.sourceDir));
}
}
@@ -131,7 +171,7 @@ public class SafetyCenterResourcesContext extends ContextWrapper {
ResolveInfo resolveInfo = resolveInfos.get(i);
if (mResourcesApkPath != null
&& !resolveInfo.activityInfo.applicationInfo.sourceDir.startsWith(
- mResourcesApkPath)) {
+ mResourcesApkPath)) {
// skip apps that don't live in the Permission apex
continue;
}
@@ -141,7 +181,8 @@ public class SafetyCenterResourcesContext extends ContextWrapper {
if (info == null) {
// Resource APK not loaded yet, print a stack trace to see where this is called from
- Log.e(TAG,
+ Log.e(
+ TAG,
"Attempted to fetch resources before Safety Center resources APK is loaded!",
new IllegalStateException());
return null;
@@ -153,7 +194,7 @@ public class SafetyCenterResourcesContext extends ContextWrapper {
}
/**
- * Get the raw XML resource representing the Safety Center configuration from the Safety Center
+ * Gets the raw XML resource representing the Safety Center configuration from the Safety Center
* resources APK.
*/
@Nullable
@@ -173,6 +214,81 @@ public class SafetyCenterResourcesContext extends ContextWrapper {
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();
@@ -189,6 +305,7 @@ public class SafetyCenterResourcesContext extends ContextWrapper {
/** Retrieve assets held in the Safety Center resources APK. */
@Override
+ @Nullable
public AssetManager getAssets() {
if (mAssetsFromApk == null) {
Context resourcesApkContext = getResourcesApkContext();
@@ -201,6 +318,7 @@ public class SafetyCenterResourcesContext extends ContextWrapper {
/** Retrieve resources held in the Safety Center resources APK. */
@Override
+ @Nullable
public Resources getResources() {
if (mResourcesFromApk == null) {
Context resourcesApkContext = getResourcesApkContext();
@@ -213,6 +331,7 @@ public class SafetyCenterResourcesContext extends ContextWrapper {
/** Retrieve theme held in the Safety Center resources APK. */
@Override
+ @Nullable
public Resources.Theme getTheme() {
if (mThemeFromApk == null) {
Context resourcesApkContext = getResourcesApkContext();
@@ -222,4 +341,63 @@ public class SafetyCenterResourcesContext extends ContextWrapper {
}
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/java/com/android/safetycenter/resources/package-info.java b/SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/package-info.java
new file mode 100644
index 000000000..605b5ce71
--- /dev/null
+++ b/SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@NonNullByDefault
+package com.android.safetycenter.resources;
+
+import com.android.safetycenter.annotations.NonNullByDefault;
diff --git a/SafetyCenter/ResourcesLib/tests/Android.bp b/SafetyCenter/ResourcesLib/tests/Android.bp
index 37770eb61..75fead776 100644
--- a/SafetyCenter/ResourcesLib/tests/Android.bp
+++ b/SafetyCenter/ResourcesLib/tests/Android.bp
@@ -25,8 +25,9 @@ android_test {
"java/**/*.kt",
],
static_libs: [
- "safety-center-resources-lib",
"compatibility-device-util-axt",
+ "kotlin-test",
+ "safety-center-resources-lib",
],
data: [
":SafetyCenterResourcesLibTestResources",
diff --git a/SafetyCenter/ResourcesLib/tests/AndroidManifest.xml b/SafetyCenter/ResourcesLib/tests/AndroidManifest.xml
index 471af8d28..659a6735b 100644
--- a/SafetyCenter/ResourcesLib/tests/AndroidManifest.xml
+++ b/SafetyCenter/ResourcesLib/tests/AndroidManifest.xml
@@ -20,6 +20,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.safetycenter.resourceslib.tests">
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+
<application android:label="Safety Center ResourcesLib Tests">
<uses-library android:name="android.test.runner" />
</application>
diff --git a/SafetyCenter/ResourcesLib/tests/AndroidTest.xml b/SafetyCenter/ResourcesLib/tests/AndroidTest.xml
index 75aff0812..6dcfb0362 100644
--- a/SafetyCenter/ResourcesLib/tests/AndroidTest.xml
+++ b/SafetyCenter/ResourcesLib/tests/AndroidTest.xml
@@ -20,10 +20,12 @@
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-instrumentation" />
<option name="test-tag" value="SafetyCenterConfigTests" />
- <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk33ModuleController" />
+
+ <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
<!-- Install test and resources -->
- <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="test-file-name" value="SafetyCenterResourcesLibTests.apk" />
<option name="test-file-name" value="SafetyCenterResourcesLibTestResources.apk" />
<option name="cleanup-apks" value="true" />
diff --git a/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/drawable/valid_drawable.xml b/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/drawable/valid_drawable.xml
new file mode 100644
index 000000000..81315789c
--- /dev/null
+++ b/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/drawable/valid_drawable.xml
@@ -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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="1dp"
+ android:height="1dp"
+ android:viewportWidth="1"
+ android:viewportHeight="1">
+ <path
+ android:pathData="M0,0Z"
+ android:fillColor="#ffffff"/>
+</vector> \ No newline at end of file
diff --git a/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/values/colors.xml b/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/values/colors.xml
new file mode 100644
index 000000000..709c842cd
--- /dev/null
+++ b/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/values/colors.xml
@@ -0,0 +1,19 @@
+<!--
+ ~ 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>
+ <color name="valid_color">#FFFFFF</color>
+</resources>
diff --git a/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/values/strings.xml b/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/values/strings.xml
new file mode 100644
index 000000000..1c1759b19
--- /dev/null
+++ b/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?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">
+ <!-- DO NOT TRANSLATE, for testing only -->
+ <string name="valid_string" translatable="false">I exist!</string>
+</resources>
+
diff --git a/SafetyCenter/ResourcesLib/tests/java/com/android/safetycenter/resources/SafetyCenterResourcesContextTest.kt b/SafetyCenter/ResourcesLib/tests/java/com/android/safetycenter/resources/SafetyCenterResourcesContextTest.kt
index b6fd732a6..1a82460d2 100644
--- a/SafetyCenter/ResourcesLib/tests/java/com/android/safetycenter/resources/SafetyCenterResourcesContextTest.kt
+++ b/SafetyCenter/ResourcesLib/tests/java/com/android/safetycenter/resources/SafetyCenterResourcesContextTest.kt
@@ -18,102 +18,203 @@ 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 org.junit.Assert.assertNotNull
-import org.junit.Assert.assertNull
+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 safetyCenterResourcesContext = SafetyCenterResourcesContext(
- context,
- RESOURCES_APK_ACTION,
- null,
- CONFIG_NAME,
- 0
- )
- assertThat(safetyCenterResourcesContext.resourcesApkPkgName).isEqualTo(
- RESOURCES_APK_PKG_NAME
- )
+ val resourcesContext =
+ SafetyCenterResourcesContext(context, RESOURCES_APK_ACTION, null, CONFIG_NAME, 0, false)
+
+ assertThat(resourcesContext.resourcesApkPkgName).isEqualTo(RESOURCES_APK_PKG_NAME)
+
val configContent =
- safetyCenterResourcesContext.safetyCenterConfig?.bufferedReader().use { it?.readText() }
+ resourcesContext.safetyCenterConfig?.bufferedReader().use { it?.readText() }
+
assertThat(configContent).isEqualTo(CONFIG_CONTENT)
- assertNotNull(safetyCenterResourcesContext.assets)
- assertNotNull(safetyCenterResourcesContext.resources)
- assertNotNull(safetyCenterResourcesContext.theme)
+ assertThat(resourcesContext.assets).isNotNull()
+ assertThat(resourcesContext.resources).isNotNull()
+ assertThat(resourcesContext.theme).isNotNull()
}
@Test
fun nullDataWithWrongAction() {
- val safetyCenterResourcesContext = SafetyCenterResourcesContext(
- context,
- "wrong",
- null,
- CONFIG_NAME,
- 0
- )
- assertNull(safetyCenterResourcesContext.resourcesApkPkgName)
- assertNull(safetyCenterResourcesContext.safetyCenterConfig)
- assertNull(safetyCenterResourcesContext.assets)
- assertNull(safetyCenterResourcesContext.resources)
- assertNull(safetyCenterResourcesContext.theme)
+ 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 safetyCenterResourcesContext = SafetyCenterResourcesContext(
- context,
- RESOURCES_APK_ACTION,
- "/apex/com.android.permission",
- CONFIG_NAME,
- 0
- )
- assertNull(safetyCenterResourcesContext.resourcesApkPkgName)
- assertNull(safetyCenterResourcesContext.safetyCenterConfig)
- assertNull(safetyCenterResourcesContext.assets)
- assertNull(safetyCenterResourcesContext.resources)
- assertNull(safetyCenterResourcesContext.theme)
+ 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 safetyCenterResourcesContext = SafetyCenterResourcesContext(
- context,
- RESOURCES_APK_ACTION,
- null,
- CONFIG_NAME,
- PackageManager.MATCH_SYSTEM_ONLY
- )
- assertNull(safetyCenterResourcesContext.resourcesApkPkgName)
- assertNull(safetyCenterResourcesContext.safetyCenterConfig)
- assertNull(safetyCenterResourcesContext.assets)
- assertNull(safetyCenterResourcesContext.resources)
- assertNull(safetyCenterResourcesContext.theme)
+ 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 safetyCenterResourcesContext = SafetyCenterResourcesContext(
- context,
- RESOURCES_APK_ACTION,
- null,
- "wrong",
- 0
- )
- assertNotNull(safetyCenterResourcesContext.resourcesApkPkgName)
- assertNull(safetyCenterResourcesContext.safetyCenterConfig)
- assertNotNull(safetyCenterResourcesContext.assets)
- assertNotNull(safetyCenterResourcesContext.resources)
- assertNotNull(safetyCenterResourcesContext.theme)
+ 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"
@@ -122,4 +223,4 @@ class SafetyCenterResourcesContextTest {
const val CONFIG_NAME = "test"
const val CONFIG_CONTENT = "TEST"
}
-} \ No newline at end of file
+}
diff --git a/SafetyCenter/TEST_MAPPING b/SafetyCenter/TEST_MAPPING
index 3985e563c..5bc6abbc7 100644
--- a/SafetyCenter/TEST_MAPPING
+++ b/SafetyCenter/TEST_MAPPING
@@ -1,7 +1,16 @@
{
- "presubmit": [
+ "imports": [
{
- "name": "CtsSafetyCenterTestCases"
+ "path": "packages/modules/Permission/tests/cts/safetycenter/"
+ },
+ {
+ "path": "packages/modules/Permission/tests/functional/safetycenter/multiusers/"
+ },
+ {
+ "path": "packages/modules/Permission/tests/functional/safetycenter/safetycenteractivity/"
+ },
+ {
+ "path": "packages/modules/Permission/tests/functional/safetycenter/singleuser/"
}
]
}
diff --git a/SafetyLabel/Android.bp b/SafetyLabel/Android.bp
new file mode 100644
index 000000000..119890d3f
--- /dev/null
+++ b/SafetyLabel/Android.bp
@@ -0,0 +1,49 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+filegroup {
+ name: "safety-label-java-sources",
+ srcs: [
+ "java/**/*.java",
+ ],
+ path: "java",
+ visibility: ["//visibility:private"],
+}
+
+java_library {
+ name: "safety-label",
+ sdk_version: "system_current",
+ min_sdk_version: "30",
+ target_sdk_version: "33",
+ srcs: [
+ ":safety-label-java-sources",
+ ],
+ libs: [
+ "androidx.annotation_annotation",
+ "framework-annotations-lib",
+ ],
+ apex_available: [
+ "com.android.permission",
+ "test_com.android.permission",
+ ],
+ installable: false,
+ visibility: [
+ "//packages/modules/Permission:__subpackages__",
+ ],
+}
+
diff --git a/SafetyLabel/TEST_MAPPING b/SafetyLabel/TEST_MAPPING
new file mode 100644
index 000000000..f2560add0
--- /dev/null
+++ b/SafetyLabel/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "postsubmit": [
+ {
+ "name" : "SafetyLabelTests"
+ }
+ ]
+} \ No newline at end of file
diff --git a/SafetyLabel/java/com/android/permission/safetylabel/DataCategory.java b/SafetyLabel/java/com/android/permission/safetylabel/DataCategory.java
new file mode 100644
index 000000000..395468c81
--- /dev/null
+++ b/SafetyLabel/java/com/android/permission/safetylabel/DataCategory.java
@@ -0,0 +1,100 @@
+/*
+ * 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.permission.safetylabel;
+
+import android.os.PersistableBundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.permission.safetylabel.DataLabelConstants.DataUsage;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Data usage category representation containing one or more {@link DataType}. Valid category keys
+ * are defined in {@link DataCategoryConstants}, each category has a valid set of types {@link
+ * DataType}, which are mapped in {@link DataTypeConstants}
+ */
+public class DataCategory {
+ private final Map<String, DataType> mDataTypes;
+
+ private DataCategory(@NonNull Map<String, DataType> dataTypes) {
+ this.mDataTypes = dataTypes;
+ }
+
+ /**
+ * Returns a {@link java.util.Collections.UnmodifiableMap} of {@link String} category to {@link
+ * DataCategory} created by parsing a {@link PersistableBundle}
+ */
+ @NonNull
+ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+ static Map<String, DataCategory> getDataCategoryMap(
+ @Nullable PersistableBundle dataLabelBundle, @DataUsage @NonNull String dataUsage) {
+ if (dataLabelBundle == null) {
+ return Collections.emptyMap();
+ }
+
+ PersistableBundle dataCategoryMapBundle = dataLabelBundle.getPersistableBundle(dataUsage);
+ if (dataCategoryMapBundle == null) {
+ return Collections.emptyMap();
+ }
+
+ Map<String, DataCategory> dataCategoryMap = new HashMap<>();
+ for (String category : DataCategoryConstants.VALID_CATEGORIES) {
+ DataCategory dataCategory = getDataCategory(dataCategoryMapBundle, dataUsage, category);
+ if (dataCategory != null) {
+ dataCategoryMap.put(category, dataCategory);
+ }
+ }
+ return Collections.unmodifiableMap(dataCategoryMap);
+ }
+
+ /**
+ * Returns a {@link DataCategory} created by parsing a {@link PersistableBundle}, or {@code
+ * null} if parsing results in an invalid or empty DataCategory
+ */
+ @Nullable
+ @VisibleForTesting
+ static DataCategory getDataCategory(
+ @Nullable PersistableBundle dataCategoryMapBundle,
+ @NonNull String dataUsage,
+ @NonNull String category) {
+ if (dataCategoryMapBundle == null) {
+ return null;
+ }
+
+ PersistableBundle dataCategoryBundle = dataCategoryMapBundle.getPersistableBundle(category);
+
+ Map<String, DataType> dataTypeMap =
+ DataType.getDataTypeMap(dataCategoryBundle, dataUsage, category);
+ if (dataTypeMap.isEmpty()) {
+ return null;
+ }
+
+ return new DataCategory(dataTypeMap);
+ }
+
+ /** Return the type {@link Map} of String type key to {@link DataType} */
+ @NonNull
+ public Map<String, DataType> getDataTypes() {
+ return mDataTypes;
+ }
+}
diff --git a/SafetyLabel/java/com/android/permission/safetylabel/DataCategoryConstants.java b/SafetyLabel/java/com/android/permission/safetylabel/DataCategoryConstants.java
new file mode 100644
index 000000000..af04220c0
--- /dev/null
+++ b/SafetyLabel/java/com/android/permission/safetylabel/DataCategoryConstants.java
@@ -0,0 +1,101 @@
+/*
+ * 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.permission.safetylabel;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.StringDef;
+
+import java.lang.annotation.Retention;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Constants for determining valid {@link String} data types for usage within {@link SafetyLabel},
+ * {@link DataCategory}, and {@link DataType}
+ */
+public class DataCategoryConstants {
+
+ /** List of valid Safety Label data collection/sharing categories */
+ @Retention(SOURCE)
+ @StringDef(
+ prefix = "CATEGORY_",
+ value = {
+ CATEGORY_PERSONAL,
+ CATEGORY_FINANCIAL,
+ CATEGORY_LOCATION,
+ CATEGORY_EMAIL_TEXT_MESSAGE,
+ CATEGORY_PHOTO_VIDEO,
+ CATEGORY_AUDIO,
+ CATEGORY_STORAGE,
+ CATEGORY_HEALTH_FITNESS,
+ CATEGORY_CONTACTS,
+ CATEGORY_CALENDAR,
+ CATEGORY_IDENTIFIERS,
+ CATEGORY_APP_PERFORMANCE,
+ CATEGORY_ACTIONS_IN_APP,
+ CATEGORY_SEARCH_AND_BROWSING,
+ })
+ public @interface Category {}
+
+ public static final String CATEGORY_PERSONAL = "personal";
+ public static final String CATEGORY_FINANCIAL = "financial";
+ public static final String CATEGORY_LOCATION = "location";
+ public static final String CATEGORY_EMAIL_TEXT_MESSAGE = "email_text_message";
+ public static final String CATEGORY_PHOTO_VIDEO = "photo_video";
+ public static final String CATEGORY_AUDIO = "audio";
+ public static final String CATEGORY_STORAGE = "storage";
+ public static final String CATEGORY_HEALTH_FITNESS = "health_fitness";
+ public static final String CATEGORY_CONTACTS = "contacts";
+ public static final String CATEGORY_CALENDAR = "calendar";
+ public static final String CATEGORY_IDENTIFIERS = "identifiers";
+ public static final String CATEGORY_APP_PERFORMANCE = "app_performance";
+ public static final String CATEGORY_ACTIONS_IN_APP = "actions_in_app";
+ public static final String CATEGORY_SEARCH_AND_BROWSING = "search_and_browsing";
+
+ /** Set of valid categories */
+ @DataCategoryConstants.Category
+ public static final Set<String> VALID_CATEGORIES =
+ Collections.unmodifiableSet(
+ new HashSet<>(
+ Arrays.asList(
+ CATEGORY_PERSONAL,
+ CATEGORY_FINANCIAL,
+ CATEGORY_LOCATION,
+ CATEGORY_EMAIL_TEXT_MESSAGE,
+ CATEGORY_PHOTO_VIDEO,
+ CATEGORY_AUDIO,
+ CATEGORY_STORAGE,
+ CATEGORY_HEALTH_FITNESS,
+ CATEGORY_CONTACTS,
+ CATEGORY_CALENDAR,
+ CATEGORY_IDENTIFIERS,
+ CATEGORY_APP_PERFORMANCE,
+ CATEGORY_ACTIONS_IN_APP,
+ CATEGORY_SEARCH_AND_BROWSING)));
+
+ /** Returns {@link Set} of valid {@link String} category keys */
+ public static Set<String> getValidDataCategories() {
+ return VALID_CATEGORIES;
+ }
+
+ private DataCategoryConstants() {
+ /* do nothing - hide constructor */
+ }
+}
diff --git a/SafetyLabel/java/com/android/permission/safetylabel/DataLabel.java b/SafetyLabel/java/com/android/permission/safetylabel/DataLabel.java
new file mode 100644
index 000000000..564d5479f
--- /dev/null
+++ b/SafetyLabel/java/com/android/permission/safetylabel/DataLabel.java
@@ -0,0 +1,83 @@
+/*
+ * 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.permission.safetylabel;
+
+import static com.android.permission.safetylabel.DataLabelConstants.DATA_USAGE_COLLECTED;
+import static com.android.permission.safetylabel.DataLabelConstants.DATA_USAGE_SHARED;
+
+import android.os.PersistableBundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import java.util.Map;
+
+/**
+ * Data label representation with data shared and data collected maps containing zero or more
+ * {@link DataCategory}
+ */
+public class DataLabel {
+ @VisibleForTesting static final String KEY_DATA_LABEL = "data_labels";
+ private final Map<String, DataCategory> mDataCollected;
+ private final Map<String, DataCategory> mDataShared;
+
+ public DataLabel(
+ @NonNull Map<String, DataCategory> dataCollected,
+ @NonNull Map<String, DataCategory> dataShared) {
+ mDataCollected = dataCollected;
+ mDataShared = dataShared;
+ }
+
+ /** Returns a {@link DataLabel} created by parsing a SafetyLabel {@link PersistableBundle} */
+ @NonNull
+ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+ public static DataLabel getDataLabel(@Nullable PersistableBundle safetyLabelBundle) {
+ if (safetyLabelBundle == null) {
+ return null;
+ }
+
+ PersistableBundle dataLabelBundle = safetyLabelBundle.getPersistableBundle(KEY_DATA_LABEL);
+ if (dataLabelBundle == null) {
+ return null;
+ }
+
+ Map<String, DataCategory> dataCollectedCategoryMap =
+ DataCategory.getDataCategoryMap(dataLabelBundle, DATA_USAGE_COLLECTED);
+ Map<String, DataCategory> dataSharedCategoryMap =
+ DataCategory.getDataCategoryMap(dataLabelBundle, DATA_USAGE_SHARED);
+ return new DataLabel(dataCollectedCategoryMap, dataSharedCategoryMap);
+ }
+
+ /**
+ * Returns the data collected {@link Map} of {@link
+ * com.android.permission.safetylabel.DataCategoryConstants.Category} to {@link DataCategory}
+ */
+ @NonNull
+ public Map<String, DataCategory> getDataCollected() {
+ return mDataCollected;
+ }
+
+ /**
+ * Returns the data shared {@link Map} of {@link
+ * com.android.permission.safetylabel.DataCategoryConstants.Category} to {@link DataCategory}
+ */
+ @NonNull
+ public Map<String, DataCategory> getDataShared() {
+ return mDataShared;
+ }
+}
diff --git a/SafetyLabel/java/com/android/permission/safetylabel/DataLabelConstants.java b/SafetyLabel/java/com/android/permission/safetylabel/DataLabelConstants.java
new file mode 100644
index 000000000..f592d9b0f
--- /dev/null
+++ b/SafetyLabel/java/com/android/permission/safetylabel/DataLabelConstants.java
@@ -0,0 +1,42 @@
+/*
+ * 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.permission.safetylabel;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.StringDef;
+
+import java.lang.annotation.Retention;
+
+/**
+ * Constants and util methods for determining valid {@link String} data types for usage within
+ * {@link SafetyLabel} and {@link DataLabel}
+ */
+public class DataLabelConstants {
+
+ /** List of valid Safety Label data usages. Shared vs Collected */
+ @Retention(SOURCE)
+ @StringDef(
+ prefix = "DATA_USAGE_",
+ value = {
+ DATA_USAGE_COLLECTED,
+ DATA_USAGE_SHARED,
+ })
+ public @interface DataUsage {}
+ public static final String DATA_USAGE_COLLECTED = "data_collected";
+ public static final String DATA_USAGE_SHARED = "data_shared";
+}
diff --git a/SafetyLabel/java/com/android/permission/safetylabel/DataPurposeConstants.java b/SafetyLabel/java/com/android/permission/safetylabel/DataPurposeConstants.java
new file mode 100644
index 000000000..0e1bb31ce
--- /dev/null
+++ b/SafetyLabel/java/com/android/permission/safetylabel/DataPurposeConstants.java
@@ -0,0 +1,79 @@
+/*
+ * 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.permission.safetylabel;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Constants for determining valid {@link Integer} data usage purposes for usage within
+ * {@link DataType}
+ */
+public class DataPurposeConstants {
+
+ /** List of valid data usage purposes */
+ @Retention(SOURCE)
+ @IntDef(
+ prefix = "PURPOSE_",
+ value = {
+ PURPOSE_APP_FUNCTIONALITY,
+ PURPOSE_ANALYTICS,
+ PURPOSE_DEVELOPER_COMMUNICATIONS,
+ PURPOSE_FRAUD_PREVENTION_SECURITY,
+ PURPOSE_ADVERTISING,
+ PURPOSE_PERSONALIZATION,
+ PURPOSE_ACCOUNT_MANAGEMENT,
+ })
+ public @interface Purpose {}
+
+ public static final int PURPOSE_APP_FUNCTIONALITY = 1;
+ public static final int PURPOSE_ANALYTICS = 2;
+ public static final int PURPOSE_DEVELOPER_COMMUNICATIONS = 3;
+ public static final int PURPOSE_FRAUD_PREVENTION_SECURITY = 4;
+ public static final int PURPOSE_ADVERTISING = 5;
+ public static final int PURPOSE_PERSONALIZATION = 6;
+ public static final int PURPOSE_ACCOUNT_MANAGEMENT = 7;
+ // RESERVED/DEPRECATED = 8
+ // RESERVED/DEPRECATED = 9
+
+ /** {@link Set} of valid {@link Integer} purposes */
+ @Purpose
+ public static final Set<Integer> VALID_PURPOSES =
+ Collections.unmodifiableSet(
+ new HashSet<>(
+ Arrays.asList(
+ PURPOSE_APP_FUNCTIONALITY,
+ PURPOSE_ANALYTICS,
+ PURPOSE_DEVELOPER_COMMUNICATIONS,
+ PURPOSE_FRAUD_PREVENTION_SECURITY,
+ PURPOSE_ADVERTISING,
+ PURPOSE_PERSONALIZATION,
+ PURPOSE_ACCOUNT_MANAGEMENT)));
+
+ /** Returns {@link Set} of valid {@link Integer} purpose */
+ @Purpose
+ public static Set<Integer> getValidPurposes() {
+ return VALID_PURPOSES;
+ }
+}
diff --git a/SafetyLabel/java/com/android/permission/safetylabel/DataType.java b/SafetyLabel/java/com/android/permission/safetylabel/DataType.java
new file mode 100644
index 000000000..68770f823
--- /dev/null
+++ b/SafetyLabel/java/com/android/permission/safetylabel/DataType.java
@@ -0,0 +1,154 @@
+/*
+ * 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.permission.safetylabel;
+
+import android.os.PersistableBundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.permission.safetylabel.DataPurposeConstants.Purpose;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Data usage type representation. Types are specific to a {@link DataCategory} and contains
+ * metadata related to the data usage purpose.
+ */
+public class DataType {
+ @VisibleForTesting static final String KEY_PURPOSES = "purposes";
+ @VisibleForTesting static final String KEY_IS_COLLECTION_OPTIONAL = "is_collection_optional";
+ @VisibleForTesting static final String KEY_EPHEMERAL = "ephemeral";
+
+ @Purpose private final Set<Integer> mPurposeSet;
+ private final Boolean mIsCollectionOptional;
+ private final Boolean mEphemeral;
+
+ private DataType(
+ @NonNull @Purpose Set<Integer> purposeSet,
+ @Nullable Boolean isCollectionOptional,
+ @Nullable Boolean ephemeral) {
+ this.mPurposeSet = purposeSet;
+ this.mIsCollectionOptional = isCollectionOptional;
+ this.mEphemeral = ephemeral;
+ }
+
+ /**
+ * Returns a {@link java.util.Collections.UnmodifiableMap} of String type key to {@link
+ * DataType} created by parsing a {@link PersistableBundle}
+ */
+ @NonNull
+ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+ static Map<String, DataType> getDataTypeMap(
+ @Nullable PersistableBundle dataCategoryBundle,
+ @NonNull String dataUsage,
+ @NonNull String category) {
+ if (dataCategoryBundle == null || dataCategoryBundle.isEmpty()) {
+ return Collections.emptyMap();
+ }
+
+ Map<String, DataType> dataTypeMap = new HashMap<>();
+ Set<String> validDataTypesForCategory =
+ DataTypeConstants.getValidDataTypesForCategory(category);
+ for (String type : validDataTypesForCategory) {
+ PersistableBundle dataTypeBundle = dataCategoryBundle.getPersistableBundle(type);
+ DataType dataType = getDataType(dataTypeBundle, dataUsage);
+ if (dataType != null) {
+ dataTypeMap.put(type, dataType);
+ }
+ }
+ return Collections.unmodifiableMap(dataTypeMap);
+ }
+
+ /**
+ * Returns {@link DataType} created by parsing the {@link android.os.PersistableBundle}
+ * representation of DataType
+ */
+ @Nullable
+ @VisibleForTesting
+ static DataType getDataType(
+ @Nullable PersistableBundle dataTypeBundle, @NonNull String dataUsage) {
+ if (dataTypeBundle == null || dataTypeBundle.isEmpty()) {
+ return null;
+ }
+
+ // purposes are required, if not present, treat as invalid
+ int[] purposeList = dataTypeBundle.getIntArray(KEY_PURPOSES);
+ if (purposeList == null || purposeList.length == 0) {
+ return null;
+ }
+
+ // Filter to set of valid purposes, and return invalid if empty
+ Set<Integer> purposeSet = new HashSet<>();
+ for (int purpose : purposeList) {
+ if (DataPurposeConstants.getValidPurposes().contains(purpose)) {
+ purposeSet.add(purpose);
+ }
+ }
+ if (purposeSet.isEmpty()) {
+ return null;
+ }
+
+ // Only set/expected for DATA COLLECTED. DATA SHARED should be null
+ Boolean isCollectionOptional = null;
+ Boolean ephemeral = null;
+ if (DataLabelConstants.DATA_USAGE_COLLECTED.equals(dataUsage)) {
+ isCollectionOptional =
+ dataTypeBundle.containsKey(KEY_IS_COLLECTION_OPTIONAL)
+ ? dataTypeBundle.getBoolean(KEY_IS_COLLECTION_OPTIONAL)
+ : null;
+ ephemeral =
+ dataTypeBundle.containsKey(KEY_EPHEMERAL)
+ ? dataTypeBundle.getBoolean(KEY_EPHEMERAL)
+ : null;
+ }
+
+ return new DataType(purposeSet, isCollectionOptional, ephemeral);
+ }
+
+ /**
+ * Returns {@link Set} of valid {@link Integer} purposes for using the associated data category
+ * and type
+ */
+ @NonNull
+ public Set<Integer> getPurposeSet() {
+ return mPurposeSet;
+ }
+
+ /**
+ * For data-collected, returns {@code true} if data usage is user optional and {@code false} if
+ * data usage is required. Should return {@code null} for data-shared.
+ */
+ @Nullable
+ public Boolean getIsCollectionOptional() {
+ return mIsCollectionOptional;
+ }
+
+ /**
+ * For data-collected, returns {@code true} if data usage is user optional and {@code false} if
+ * data usage is processed ephemerally. Should return {@code null} for data-shared.
+ */
+ @Nullable
+ public Boolean getEphemeral() {
+ return mEphemeral;
+ }
+}
diff --git a/SafetyLabel/java/com/android/permission/safetylabel/DataTypeConstants.java b/SafetyLabel/java/com/android/permission/safetylabel/DataTypeConstants.java
new file mode 100644
index 000000000..2154aceec
--- /dev/null
+++ b/SafetyLabel/java/com/android/permission/safetylabel/DataTypeConstants.java
@@ -0,0 +1,421 @@
+/*
+ * 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.permission.safetylabel;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.StringDef;
+import android.util.ArrayMap;
+
+import java.lang.annotation.Retention;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Constants and util methods for determining valid {@link String} data categories for usage within
+ * {@link SafetyLabel}, {@link DataCategory}, and {@link DataType}
+ */
+public class DataTypeConstants {
+
+ /**
+ * List of valid Safety Label data collection/sharing types for {@link
+ * DataCategoryConstants#CATEGORY_PERSONAL}
+ */
+ @Retention(SOURCE)
+ @StringDef(
+ prefix = "PERSONAL_",
+ value = {
+ PERSONAL_NAME,
+ PERSONAL_EMAIL_ADDRESS,
+ PERSONAL_PHYSICAL_ADDRESS,
+ PERSONAL_PHONE_NUMBER,
+ PERSONAL_RACE_ETHNICITY,
+ PERSONAL_POLITICAL_OR_RELIGIOUS_BELIEFS,
+ PERSONAL_SEXUAL_ORIENTATION_OR_GENDER_IDENTITY,
+ PERSONAL_IDENTIFIERS,
+ PERSONAL_OTHER,
+ })
+ public @interface PersonalType {}
+
+ public static final String PERSONAL_NAME = "name";
+ public static final String PERSONAL_EMAIL_ADDRESS = "email_address";
+ public static final String PERSONAL_PHYSICAL_ADDRESS = "physical_address";
+ public static final String PERSONAL_PHONE_NUMBER = "phone_number";
+ public static final String PERSONAL_RACE_ETHNICITY = "race_ethnicity";
+ public static final String PERSONAL_POLITICAL_OR_RELIGIOUS_BELIEFS =
+ "political_or_religious_beliefs";
+ public static final String PERSONAL_SEXUAL_ORIENTATION_OR_GENDER_IDENTITY =
+ "sexual_orientation_or_gender_identity";
+ public static final String PERSONAL_IDENTIFIERS = "personal_identifiers";
+ public static final String PERSONAL_OTHER = "other";
+
+ @PersonalType
+ private static final Set<String> VALID_TYPES_PERSONAL =
+ Collections.unmodifiableSet(
+ new HashSet<>(
+ Arrays.asList(
+ PERSONAL_NAME,
+ PERSONAL_EMAIL_ADDRESS,
+ PERSONAL_PHYSICAL_ADDRESS,
+ PERSONAL_PHONE_NUMBER,
+ PERSONAL_RACE_ETHNICITY,
+ PERSONAL_POLITICAL_OR_RELIGIOUS_BELIEFS,
+ PERSONAL_SEXUAL_ORIENTATION_OR_GENDER_IDENTITY,
+ PERSONAL_IDENTIFIERS,
+ PERSONAL_OTHER)));
+
+ /**
+ * List of valid Safety Label data collection/sharing types for {@link
+ * DataCategoryConstants#CATEGORY_FINANCIAL}
+ */
+ @Retention(SOURCE)
+ @StringDef(
+ prefix = "FINANCIAL_",
+ value = {
+ FINANCIAL_CARD_BANK_ACCOUNT,
+ FINANCIAL_PURCHASE_HISTORY,
+ FINANCIAL_CREDIT_SCORE,
+ FINANCIAL_OTHER,
+ })
+ public @interface FinancialType {}
+
+ public static final String FINANCIAL_CARD_BANK_ACCOUNT = "card_bank_account";
+ public static final String FINANCIAL_PURCHASE_HISTORY = "purchase_history";
+ public static final String FINANCIAL_CREDIT_SCORE = "credit_score";
+ public static final String FINANCIAL_OTHER = "other";
+
+ @FinancialType
+ private static final Set<String> VALID_TYPES_FINANCIAL =
+ Collections.unmodifiableSet(
+ new HashSet<>(
+ Arrays.asList(
+ FINANCIAL_CARD_BANK_ACCOUNT,
+ FINANCIAL_PURCHASE_HISTORY,
+ FINANCIAL_CREDIT_SCORE,
+ FINANCIAL_OTHER)));
+
+ /**
+ * List of valid Safety Label data collection/sharing types for {@link
+ * DataCategoryConstants#CATEGORY_LOCATION}
+ */
+ @Retention(SOURCE)
+ @StringDef(
+ prefix = "LOCATION_",
+ value = {
+ LOCATION_APPROX_LOCATION,
+ LOCATION_PRECISE_LOCATION,
+ })
+ public @interface LocationType {}
+
+ public static final String LOCATION_APPROX_LOCATION = "approx_location";
+ public static final String LOCATION_PRECISE_LOCATION = "precise_location";
+
+ @LocationType
+ private static final Set<String> VALID_TYPES_LOCATION =
+ Collections.unmodifiableSet(
+ new HashSet<>(
+ Arrays.asList(LOCATION_APPROX_LOCATION, LOCATION_PRECISE_LOCATION)));
+
+ /**
+ * List of valid Safety Label data collection/sharing types for {@link
+ * DataCategoryConstants#CATEGORY_EMAIL_TEXT_MESSAGE}
+ */
+ @Retention(SOURCE)
+ @StringDef(
+ prefix = "EMAIL_TEXT_MESSAGE_",
+ value = {
+ EMAIL_TEXT_MESSAGE_EMAILS,
+ EMAIL_TEXT_MESSAGE_TEXT_MESSAGES,
+ EMAIL_TEXT_MESSAGE_OTHER,
+ })
+ public @interface EmailTextMessageType {}
+
+ public static final String EMAIL_TEXT_MESSAGE_EMAILS = "emails";
+ public static final String EMAIL_TEXT_MESSAGE_TEXT_MESSAGES = "text_messages";
+ public static final String EMAIL_TEXT_MESSAGE_OTHER = "other";
+
+ @EmailTextMessageType
+ private static final Set<String> VALID_TYPES_EMAIL_TEXT_MESSAGE =
+ Collections.unmodifiableSet(
+ new HashSet<>(
+ Arrays.asList(
+ EMAIL_TEXT_MESSAGE_EMAILS,
+ EMAIL_TEXT_MESSAGE_TEXT_MESSAGES,
+ EMAIL_TEXT_MESSAGE_OTHER)));
+
+ /**
+ * List of valid Safety Label data collection/sharing types for {@link
+ * DataCategoryConstants#CATEGORY_PHOTO_VIDEO}
+ */
+ @Retention(SOURCE)
+ @StringDef(
+ prefix = "PHOTO_VIDEO_",
+ value = {
+ PHOTO_VIDEO_PHOTOS,
+ PHOTO_VIDEO_VIDEOS,
+ })
+ public @interface PhotoVideoType {}
+
+ public static final String PHOTO_VIDEO_PHOTOS = "photos";
+ public static final String PHOTO_VIDEO_VIDEOS = "videos";
+
+ @PhotoVideoType
+ private static final Set<String> VALID_TYPES_PHOTO_VIDEO =
+ Collections.unmodifiableSet(
+ new HashSet<>(Arrays.asList(PHOTO_VIDEO_PHOTOS, PHOTO_VIDEO_VIDEOS)));
+
+ /**
+ * List of valid Safety Label data collection/sharing types for {@link
+ * DataCategoryConstants#CATEGORY_AUDIO}
+ */
+ @Retention(SOURCE)
+ @StringDef(
+ prefix = "AUDIO_",
+ value = {AUDIO_SOUND_RECORDINGS, AUDIO_MUSIC_FILES, AUDIO_OTHER})
+ public @interface AudioType {}
+
+ public static final String AUDIO_SOUND_RECORDINGS = "sound_recordings";
+ public static final String AUDIO_MUSIC_FILES = "music_files";
+ public static final String AUDIO_OTHER = "other";
+
+ @AudioType
+ private static final Set<String> VALID_TYPES_AUDIO =
+ Collections.unmodifiableSet(
+ new HashSet<>(
+ Arrays.asList(AUDIO_SOUND_RECORDINGS, AUDIO_MUSIC_FILES, AUDIO_OTHER)));
+
+ /**
+ * List of valid Safety Label data collection/sharing types for {@link
+ * DataCategoryConstants#CATEGORY_STORAGE}
+ */
+ @Retention(SOURCE)
+ @StringDef(
+ prefix = "STORAGE_",
+ value = {
+ STORAGE_FILES_DOCS,
+ })
+ public @interface StorageType {}
+
+ public static final String STORAGE_FILES_DOCS = "files_docs";
+
+ @StorageType
+ private static final Set<String> VALID_TYPES_STORAGE =
+ Collections.unmodifiableSet(new HashSet<>(Arrays.asList(STORAGE_FILES_DOCS)));
+
+ /**
+ * List of valid Safety Label data collection/sharing types for {@link
+ * DataCategoryConstants#CATEGORY_HEALTH_FITNESS}
+ */
+ @Retention(SOURCE)
+ @StringDef(
+ prefix = "HEALTH_FITNESS_",
+ value = {
+ HEALTH_FITNESS_HEALTH,
+ HEALTH_FITNESS_FITNESS,
+ })
+ public @interface HealthFitnessType {}
+
+ public static final String HEALTH_FITNESS_HEALTH = "health";
+ public static final String HEALTH_FITNESS_FITNESS = "fitness";
+
+ @HealthFitnessType
+ private static final Set<String> VALID_TYPES_HEALTH_FITNESS =
+ Collections.unmodifiableSet(
+ new HashSet<>(Arrays.asList(HEALTH_FITNESS_HEALTH, HEALTH_FITNESS_FITNESS)));
+
+ /**
+ * List of valid Safety Label data collection/sharing types for {@link
+ * DataCategoryConstants#CATEGORY_CONTACTS}
+ */
+ @Retention(SOURCE)
+ @StringDef(
+ prefix = "CONTACTS_",
+ value = {
+ CONTACTS_CONTACTS,
+ })
+ public @interface ContactsType {}
+
+ public static final String CONTACTS_CONTACTS = "contacts";
+
+ @ContactsType
+ private static final Set<String> VALID_TYPES_CONTACTS =
+ Collections.unmodifiableSet(new HashSet<>(Arrays.asList(CONTACTS_CONTACTS)));
+
+ /**
+ * List of valid Safety Label data collection/sharing types for {@link
+ * DataCategoryConstants#CATEGORY_CALENDAR}
+ */
+ @Retention(SOURCE)
+ @StringDef(
+ prefix = "CALENDAR_",
+ value = {
+ CALENDAR_CALENDAR,
+ })
+ public @interface CalendarType {}
+
+ public static final String CALENDAR_CALENDAR = "calendar";
+
+ @CalendarType
+ private static final Set<String> VALID_TYPES_CALENDAR =
+ Collections.unmodifiableSet(new HashSet<>(Arrays.asList(CALENDAR_CALENDAR)));
+
+ /**
+ * List of valid Safety Label data collection/sharing types for {@link
+ * DataCategoryConstants#CATEGORY_IDENTIFIERS}
+ */
+ @Retention(SOURCE)
+ @StringDef(
+ prefix = "IDENTIFIERS_",
+ value = {
+ IDENTIFIERS_OTHER,
+ })
+ public @interface IdentifiersType {}
+
+ public static final String IDENTIFIERS_OTHER = "other";
+
+ @IdentifiersType
+ private static final Set<String> VALID_TYPES_IDENTIFIERS =
+ Collections.unmodifiableSet(new HashSet<>(Arrays.asList(IDENTIFIERS_OTHER)));
+
+ /**
+ * List of valid Safety Label data collection/sharing types for {@link
+ * DataCategoryConstants#CATEGORY_APP_PERFORMANCE}
+ */
+ @Retention(SOURCE)
+ @StringDef(
+ prefix = "APP_PERFORMANCE_",
+ value = {
+ APP_PERFORMANCE_CRASH_LOGS,
+ APP_PERFORMANCE_PERFORMANCE_DIAGNOSTICS,
+ APP_PERFORMANCE_OTHER,
+ })
+ public @interface AppPerformanceType {}
+
+ public static final String APP_PERFORMANCE_CRASH_LOGS = "crash_logs";
+ public static final String APP_PERFORMANCE_PERFORMANCE_DIAGNOSTICS = "performance_diagnostics";
+ public static final String APP_PERFORMANCE_OTHER = "other";
+
+ @AppPerformanceType
+ private static final Set<String> VALID_TYPES_APP_PERFORMANCE =
+ Collections.unmodifiableSet(
+ new HashSet<>(
+ Arrays.asList(
+ APP_PERFORMANCE_CRASH_LOGS,
+ APP_PERFORMANCE_PERFORMANCE_DIAGNOSTICS,
+ APP_PERFORMANCE_OTHER)));
+
+ /**
+ * List of valid Safety Label data collection/sharing types for {@link
+ * DataCategoryConstants#CATEGORY_ACTIONS_IN_APP}
+ */
+ @Retention(SOURCE)
+ @StringDef(
+ prefix = "ACTIONS_IN_APP_",
+ value = {
+ ACTIONS_IN_APP_USER_INTERACTION,
+ ACTIONS_IN_APP_IN_APP_SEARCH_HISTORY,
+ ACTIONS_IN_APP_INSTALLED_APPS,
+ ACTIONS_IN_APP_USER_GENERATED_CONTENT,
+ ACTIONS_IN_APP_OTHER,
+ })
+ public @interface ActionsInAppType {}
+
+ public static final String ACTIONS_IN_APP_USER_INTERACTION = "user_interaction";
+ public static final String ACTIONS_IN_APP_IN_APP_SEARCH_HISTORY = "in_app_search_history";
+ public static final String ACTIONS_IN_APP_INSTALLED_APPS = "installed_apps";
+ public static final String ACTIONS_IN_APP_USER_GENERATED_CONTENT = "user_generated_content";
+ public static final String ACTIONS_IN_APP_OTHER = "other";
+
+ @ActionsInAppType
+ private static final Set<String> VALID_TYPES_ACTIONS_IN_APP =
+ Collections.unmodifiableSet(
+ new HashSet<>(
+ Arrays.asList(
+ ACTIONS_IN_APP_USER_INTERACTION,
+ ACTIONS_IN_APP_IN_APP_SEARCH_HISTORY,
+ ACTIONS_IN_APP_INSTALLED_APPS,
+ ACTIONS_IN_APP_USER_GENERATED_CONTENT,
+ ACTIONS_IN_APP_OTHER)));
+
+ /**
+ * List of valid Safety Label data collection/sharing types for {@link
+ * DataCategoryConstants#CATEGORY_SEARCH_AND_BROWSING}
+ */
+ @Retention(SOURCE)
+ @StringDef(
+ prefix = "SEARCH_AND_BROWSING_",
+ value = {
+ SEARCH_AND_BROWSING_WEB_BROWSING_HISTORY,
+ })
+ public @interface SearchAndBrowsingType {}
+
+ public static final String SEARCH_AND_BROWSING_WEB_BROWSING_HISTORY = "web_browsing_history";
+
+ @SearchAndBrowsingType
+ private static final Set<String> VALID_TYPES_SEARCH_AND_BROWSING =
+ Collections.unmodifiableSet(
+ new HashSet<>(Arrays.asList(SEARCH_AND_BROWSING_WEB_BROWSING_HISTORY)));
+
+ private static final Map<String, Set<String>> VALID_TYPES_FOR_CATEGORY_MAP;
+
+ /** Returns {@link Set} of valid types for the specified {@link String} category key */
+ public static Set<String> getValidDataTypesForCategory(
+ @DataCategoryConstants.Category String category) {
+ return VALID_TYPES_FOR_CATEGORY_MAP.containsKey(category)
+ ? VALID_TYPES_FOR_CATEGORY_MAP.get(category)
+ : Collections.emptySet();
+ }
+
+ static {
+ VALID_TYPES_FOR_CATEGORY_MAP = new ArrayMap<>();
+ VALID_TYPES_FOR_CATEGORY_MAP.put(
+ DataCategoryConstants.CATEGORY_PERSONAL, VALID_TYPES_PERSONAL);
+ VALID_TYPES_FOR_CATEGORY_MAP.put(
+ DataCategoryConstants.CATEGORY_FINANCIAL, VALID_TYPES_FINANCIAL);
+ VALID_TYPES_FOR_CATEGORY_MAP.put(
+ DataCategoryConstants.CATEGORY_LOCATION, VALID_TYPES_LOCATION);
+ VALID_TYPES_FOR_CATEGORY_MAP.put(
+ DataCategoryConstants.CATEGORY_EMAIL_TEXT_MESSAGE, VALID_TYPES_EMAIL_TEXT_MESSAGE);
+ VALID_TYPES_FOR_CATEGORY_MAP.put(
+ DataCategoryConstants.CATEGORY_PHOTO_VIDEO, VALID_TYPES_PHOTO_VIDEO);
+ VALID_TYPES_FOR_CATEGORY_MAP.put(DataCategoryConstants.CATEGORY_AUDIO, VALID_TYPES_AUDIO);
+ VALID_TYPES_FOR_CATEGORY_MAP.put(
+ DataCategoryConstants.CATEGORY_STORAGE, VALID_TYPES_STORAGE);
+ VALID_TYPES_FOR_CATEGORY_MAP.put(
+ DataCategoryConstants.CATEGORY_HEALTH_FITNESS, VALID_TYPES_HEALTH_FITNESS);
+ VALID_TYPES_FOR_CATEGORY_MAP.put(
+ DataCategoryConstants.CATEGORY_CONTACTS, VALID_TYPES_CONTACTS);
+ VALID_TYPES_FOR_CATEGORY_MAP.put(
+ DataCategoryConstants.CATEGORY_CALENDAR, VALID_TYPES_CALENDAR);
+ VALID_TYPES_FOR_CATEGORY_MAP.put(
+ DataCategoryConstants.CATEGORY_IDENTIFIERS, VALID_TYPES_IDENTIFIERS);
+ VALID_TYPES_FOR_CATEGORY_MAP.put(
+ DataCategoryConstants.CATEGORY_APP_PERFORMANCE, VALID_TYPES_APP_PERFORMANCE);
+ VALID_TYPES_FOR_CATEGORY_MAP.put(
+ DataCategoryConstants.CATEGORY_ACTIONS_IN_APP, VALID_TYPES_ACTIONS_IN_APP);
+ VALID_TYPES_FOR_CATEGORY_MAP.put(
+ DataCategoryConstants.CATEGORY_SEARCH_AND_BROWSING,
+ VALID_TYPES_SEARCH_AND_BROWSING);
+ }
+
+ private DataTypeConstants() {
+ /* do nothing - hide constructor */
+ }
+}
diff --git a/SafetyLabel/java/com/android/permission/safetylabel/SafetyLabel.java b/SafetyLabel/java/com/android/permission/safetylabel/SafetyLabel.java
new file mode 100644
index 000000000..3eb8767b9
--- /dev/null
+++ b/SafetyLabel/java/com/android/permission/safetylabel/SafetyLabel.java
@@ -0,0 +1,77 @@
+/*
+ * 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.permission.safetylabel;
+
+import android.os.PersistableBundle;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import java.util.Locale;
+
+/** Safety Label representation containing zero or more {@link DataCategory} for data shared */
+public class SafetyLabel {
+ private static final String TAG = "SafetyLabel";
+ @VisibleForTesting static final String KEY_SAFETY_LABEL = "safety_labels";
+ public static final String KEY_VERSION = "version";
+ private final DataLabel mDataLabel;
+
+ private SafetyLabel(@NonNull DataLabel dataLabel) {
+ this.mDataLabel = dataLabel;
+ }
+
+ /** Returns {@link SafetyLabel} created by parsing a metadata {@link PersistableBundle} */
+ @Nullable
+ public static SafetyLabel getSafetyLabelFromMetadata(@Nullable PersistableBundle bundle) {
+ if (bundle == null || bundle.isEmpty()) {
+ return null;
+ }
+
+ if (bundle.getLong(KEY_VERSION, 0L) <= 0) {
+ Log.w(TAG, String.format(
+ Locale.US, "The top level metadata bundle have an invalid version %d",
+ bundle.getLong(KEY_VERSION, 0L)));
+ return null;
+ }
+
+ PersistableBundle safetyLabelBundle = bundle.getPersistableBundle(KEY_SAFETY_LABEL);
+ if (safetyLabelBundle == null) {
+ return null;
+ }
+
+ long safetyLabelsVersion = safetyLabelBundle.getLong(KEY_VERSION, 0L);
+ if (safetyLabelsVersion <= 0) {
+ Log.w(TAG, String.format(Locale.US,
+ "The safety labels have an invalid version %d", safetyLabelsVersion));
+ return null;
+ }
+
+ DataLabel dataLabel = DataLabel.getDataLabel(safetyLabelBundle);
+ if (dataLabel == null) {
+ return null;
+ }
+ return new SafetyLabel(dataLabel);
+ }
+
+ /** Returns the data label for the safety label */
+ @NonNull
+ public DataLabel getDataLabel() {
+ return mDataLabel;
+ }
+}
diff --git a/SafetyLabel/tests/Android.bp b/SafetyLabel/tests/Android.bp
new file mode 100644
index 000000000..2026a6ac8
--- /dev/null
+++ b/SafetyLabel/tests/Android.bp
@@ -0,0 +1,38 @@
+// 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: "SafetyLabelTests",
+ defaults: ["mts-target-sdk-version-current"],
+ sdk_version: "test_current",
+ min_sdk_version: "30",
+ target_sdk_version: "32",
+ srcs: [
+ "java/**/*.kt",
+ ],
+ per_testcase_directory: true,
+ static_libs: [
+ "compatibility-device-util-axt",
+ "kotlinx-coroutines-android",
+ "safety-label",
+ ],
+ test_suites: [
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/SafetyLabel/tests/AndroidManifest.xml b/SafetyLabel/tests/AndroidManifest.xml
new file mode 100644
index 000000000..4d1e62905
--- /dev/null
+++ b/SafetyLabel/tests/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="com.android.permission.safetylabel.tests">
+
+ <application android:label="Safety Label Tests">
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.permission.safetylabel.tests"
+ android:label="Tests for the Safety Label library"/>
+</manifest>
diff --git a/SafetyLabel/tests/AndroidTest.xml b/SafetyLabel/tests/AndroidTest.xml
new file mode 100644
index 000000000..ec16b9ef4
--- /dev/null
+++ b/SafetyLabel/tests/AndroidTest.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.
+ -->
+
+<configuration description="Runs unit tests for the Safety Label library.">
+ <option name="test-tag" value="SafetyLabelTests"/>
+ <object type="module_controller"
+ class="com.android.tradefed.testtype.suite.module.Sdk33ModuleController"/>
+
+ <!-- Install test -->
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="test-file-name" value="SafetyLabelTests.apk"/>
+ <option name="cleanup-apks" 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/safetylabel/tests/"/>
+ <option name="teardown-command" value="rm -rf /data/local/tmp/safetylabel/"/>
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.permission.safetylabel.tests"/>
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
+ </test>
+</configuration>
diff --git a/SafetyLabel/tests/java/com/android/permission/safetylabel/DataCategoryTest.kt b/SafetyLabel/tests/java/com/android/permission/safetylabel/DataCategoryTest.kt
new file mode 100644
index 000000000..8ed705064
--- /dev/null
+++ b/SafetyLabel/tests/java/com/android/permission/safetylabel/DataCategoryTest.kt
@@ -0,0 +1,261 @@
+/*
+ * 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.permission.safetylabel
+
+import android.os.PersistableBundle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.permission.safetylabel.DataCategoryConstants.CATEGORY_LOCATION
+import com.android.permission.safetylabel.DataCategoryConstants.VALID_CATEGORIES
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.INVALID_KEY
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createCategoryMapPersistableBundle
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createCategoryMapPersistableBundleWithInvalidTypes
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createDataLabelPersistableBundle
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createDataLabelPersistableBundleWithAdditonalInvalidCategory
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createInvalidCategoryMapPersistableBundle
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createInvalidDataLabelPersistableBundle
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createTypePersistableBundle
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** CTS tests for [DataCategory]. */
+@RunWith(AndroidJUnit4::class)
+class DataCategoryTest {
+ @Test
+ fun getDataCategoryMap_dataUsageCollected_nullPersistableBundle_emptyMap() {
+ val dataCategoryMap =
+ DataCategory.getDataCategoryMap(null, DataLabelConstants.DATA_USAGE_COLLECTED)
+
+ assertThat(dataCategoryMap).isNotNull()
+ assertThat(dataCategoryMap).isEmpty()
+ }
+
+ @Test
+ fun getDataCategoryMap_dataUsageCollected_emptyPersistableBundle_emptyMap() {
+ val dataCategoryMap =
+ DataCategory.getDataCategoryMap(
+ PersistableBundle.EMPTY, DataLabelConstants.DATA_USAGE_COLLECTED)
+
+ assertThat(dataCategoryMap).isNotNull()
+ assertThat(dataCategoryMap).isEmpty()
+ }
+
+ @Test
+ fun getDataCategoryMap_dataUsageCollected_invalidBundle_emptyMap() {
+ val dataCategoryMap =
+ DataCategory.getDataCategoryMap(
+ createInvalidDataLabelPersistableBundle(), DataLabelConstants.DATA_USAGE_COLLECTED)
+
+ assertThat(dataCategoryMap).isNotNull()
+ assertThat(dataCategoryMap).isEmpty()
+ }
+
+ @Test
+ fun getDataCategoryMap_dataUsageCollected_validBundle_hasAllValidCategories() {
+ val dataCategoryMap =
+ DataCategory.getDataCategoryMap(
+ createDataLabelPersistableBundle(), DataLabelConstants.DATA_USAGE_COLLECTED)
+
+ assertThat(dataCategoryMap).isNotNull()
+ assertThat(dataCategoryMap.keys).containsExactlyElementsIn(VALID_CATEGORIES)
+ }
+
+ @Test
+ fun getDataCategoryMap_dataUsageCollected_additionalInvalidCategory_hasOnlyValidCategories() {
+ // Create valid data label and put an additional invalid/unknown category key
+ val dataLabelBundle = createDataLabelPersistableBundleWithAdditonalInvalidCategory()
+
+ val dataCategoryMap =
+ DataCategory.getDataCategoryMap(
+ dataLabelBundle, DataLabelConstants.DATA_USAGE_COLLECTED)
+
+ assertThat(dataCategoryMap).isNotNull()
+ assertThat(dataCategoryMap.keys).containsExactlyElementsIn(VALID_CATEGORIES)
+ }
+
+ @Test
+ fun getDataCategoryMap_dataUsageShared_nullPersistableBundle_emptyMap() {
+ val dataCategoryMap =
+ DataCategory.getDataCategoryMap(null, DataLabelConstants.DATA_USAGE_SHARED)
+
+ assertThat(dataCategoryMap).isNotNull()
+ assertThat(dataCategoryMap).isEmpty()
+ }
+
+ @Test
+ fun getDataCategoryMap_dataUsageShared_emptyPersistableBundle_emptyMap() {
+ val dataCategoryMap =
+ DataCategory.getDataCategoryMap(
+ PersistableBundle.EMPTY, DataLabelConstants.DATA_USAGE_SHARED)
+
+ assertThat(dataCategoryMap).isNotNull()
+ assertThat(dataCategoryMap).isEmpty()
+ }
+
+ @Test
+ fun getDataCategoryMap_dataUsageShared_invalidBundle_emptyMap() {
+ val dataCategoryMap =
+ DataCategory.getDataCategoryMap(
+ createInvalidDataLabelPersistableBundle(), DataLabelConstants.DATA_USAGE_SHARED)
+
+ assertThat(dataCategoryMap).isNotNull()
+ assertThat(dataCategoryMap).isEmpty()
+ }
+
+ @Test
+ fun getDataCategoryMap_dataUsageShared_validBundle_hasAllValidCategories() {
+ val dataCategoryMap =
+ DataCategory.getDataCategoryMap(
+ createDataLabelPersistableBundle(), DataLabelConstants.DATA_USAGE_SHARED)
+
+ assertThat(dataCategoryMap).isNotNull()
+ assertThat(dataCategoryMap.keys).containsExactlyElementsIn(VALID_CATEGORIES)
+ }
+
+ @Test
+ fun getDataCategoryMap_dataUsageShared_additionalInvalidCategory_hasOnlyValidCategories() {
+ // Create valid data label and put an additional invalid/unknown category key
+ val dataLabelBundle = createDataLabelPersistableBundleWithAdditonalInvalidCategory()
+
+ val dataCategoryMap =
+ DataCategory.getDataCategoryMap(dataLabelBundle, DataLabelConstants.DATA_USAGE_SHARED)
+
+ assertThat(dataCategoryMap).isNotNull()
+ assertThat(dataCategoryMap.keys).containsExactlyElementsIn(VALID_CATEGORIES)
+ }
+
+ @Test
+ fun getDataCategoryMap_dataUsageInvalid_nullPersistableBundle_emptyMap() {
+ val dataCategoryMap = DataCategory.getDataCategoryMap(null, "invalid_datausage_key")
+
+ assertThat(dataCategoryMap).isNotNull()
+ assertThat(dataCategoryMap).isEmpty()
+ }
+
+ @Test
+ fun getDataCategoryMap_dataUsageInvalid_emptyPersistableBundle_emptyMap() {
+ val dataCategoryMap =
+ DataCategory.getDataCategoryMap(PersistableBundle.EMPTY, "invalid_datausage_key")
+
+ assertThat(dataCategoryMap).isNotNull()
+ assertThat(dataCategoryMap).isEmpty()
+ }
+
+ @Test
+ fun getDataCategoryMap_dataUsageInvalid_invalidBundle_emptyMap() {
+ val dataCategoryMap =
+ DataCategory.getDataCategoryMap(
+ createInvalidDataLabelPersistableBundle(), "invalid_datausage_key")
+
+ assertThat(dataCategoryMap).isNotNull()
+ assertThat(dataCategoryMap).isEmpty()
+ }
+
+ @Test
+ fun getDataCategoryMap_dataUsageInvalid_validBundle_emptyMap() {
+ val dataCategoryMap =
+ DataCategory.getDataCategoryMap(
+ createDataLabelPersistableBundle(), "invalid_datausage_key")
+
+ assertThat(dataCategoryMap).isNotNull()
+ assertThat(dataCategoryMap).isEmpty()
+ }
+
+ @Test
+ fun getDataCategoryMap_dataUsageInvalid_validBundleWithAdditionalInvalidCategory_null() {
+ // Create valid data label and put an additional invalid/unknown category key
+ val dataLabelBundle = createDataLabelPersistableBundleWithAdditonalInvalidCategory()
+
+ val dataCategoryMap =
+ DataCategory.getDataCategoryMap(dataLabelBundle, "invalid_datausage_key")
+
+ assertThat(dataCategoryMap).isNotNull()
+ assertThat(dataCategoryMap).isEmpty()
+ }
+
+ @Test
+ fun getDataCategory_nullBundle_nullDataCategory() {
+ val dataCategory =
+ DataCategory.getDataCategory(
+ null, DataLabelConstants.DATA_USAGE_SHARED, CATEGORY_LOCATION)
+
+ assertThat(dataCategory).isNull()
+ }
+
+ @Test
+ fun getDataCategory_emptyBundle_nullDataCategory() {
+ val dataCategory =
+ DataCategory.getDataCategory(
+ PersistableBundle.EMPTY, DataLabelConstants.DATA_USAGE_SHARED, CATEGORY_LOCATION)
+
+ assertThat(dataCategory).isNull()
+ }
+
+ @Test
+ fun getDataCategory_invalidBundle_nullDataCategory() {
+ val dataCategory =
+ DataCategory.getDataCategory(
+ createInvalidCategoryMapPersistableBundle(),
+ DataLabelConstants.DATA_USAGE_SHARED,
+ CATEGORY_LOCATION)
+
+ assertThat(dataCategory).isNull()
+ }
+
+ @Test
+ fun getDataCategory_validCategoriesAndInvalidType_nullDataCategory() {
+ val dataCategory =
+ DataCategory.getDataCategory(
+ createCategoryMapPersistableBundleWithInvalidTypes(),
+ DataLabelConstants.DATA_USAGE_SHARED,
+ INVALID_KEY)
+
+ assertThat(dataCategory).isNull()
+ }
+
+ @Test
+ fun getDataCategory_validBundle_validCategoryAndExpectedTypes() {
+ val dataCategory =
+ DataCategory.getDataCategory(
+ createCategoryMapPersistableBundle(),
+ DataLabelConstants.DATA_USAGE_SHARED,
+ CATEGORY_LOCATION)
+
+ assertThat(dataCategory).isNotNull()
+ assertThat(dataCategory?.dataTypes).isNotEmpty()
+ assertThat(dataCategory?.dataTypes?.keys)
+ .containsExactlyElementsIn(
+ DataTypeConstants.getValidDataTypesForCategory(CATEGORY_LOCATION))
+ }
+
+ @Test
+ fun getDataCategory_validBundleWithAddedInvalidType_validCategoryAndOnlyExpectedTypes() {
+ // Create valid bundle with additional invalid type
+ val dataTypeMapBundle = createCategoryMapPersistableBundle()
+ dataTypeMapBundle.putPersistableBundle(INVALID_KEY, createTypePersistableBundle())
+
+ val dataCategory =
+ DataCategory.getDataCategory(
+ dataTypeMapBundle, DataLabelConstants.DATA_USAGE_SHARED, CATEGORY_LOCATION)
+
+ assertThat(dataCategory).isNotNull()
+ assertThat(dataCategory?.dataTypes).isNotEmpty()
+ assertThat(dataCategory?.dataTypes?.keys)
+ .containsExactlyElementsIn(
+ DataTypeConstants.getValidDataTypesForCategory(CATEGORY_LOCATION))
+ }
+}
diff --git a/SafetyLabel/tests/java/com/android/permission/safetylabel/DataLabelTest.kt b/SafetyLabel/tests/java/com/android/permission/safetylabel/DataLabelTest.kt
new file mode 100644
index 000000000..1c0c56238
--- /dev/null
+++ b/SafetyLabel/tests/java/com/android/permission/safetylabel/DataLabelTest.kt
@@ -0,0 +1,126 @@
+/*
+ * 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.permission.safetylabel
+
+import android.os.PersistableBundle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createInvalidSafetyLabelPersistableBundle
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createSafetyLabelPersistableBundle
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createSafetyLabelPersistableBundleWithEmptyDataCollected
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createSafetyLabelPersistableBundleWithEmptyDataShared
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createSafetyLabelPersistableBundleWithInvalidDataCollected
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createSafetyLabelPersistableBundleWithInvalidDataShared
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createSafetyLabelPersistableBundleWithNullDataCollected
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createSafetyLabelPersistableBundleWithNullDataShared
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** CTS tests for [DataLabel]. */
+@RunWith(AndroidJUnit4::class)
+class DataLabelTest {
+ @Test
+ fun getDataLabel_nullBundle_nullDataLabel() {
+ val dataLabel: DataLabel? = DataLabel.getDataLabel(null)
+
+ assertThat(dataLabel).isNull()
+ }
+
+ @Test
+ fun getDataLabel_emptyBundle_nullDataLabel() {
+ val dataLabel: DataLabel? = DataLabel.getDataLabel(PersistableBundle.EMPTY)
+
+ assertThat(dataLabel).isNull()
+ }
+
+ @Test
+ fun getDataLabel_invalidBundle_nullDataLabel() {
+ val dataLabel: DataLabel? =
+ DataLabel.getDataLabel(createInvalidSafetyLabelPersistableBundle())
+
+ assertThat(dataLabel).isNull()
+ }
+
+ @Test
+ fun getDataLabel_nullDataCollectedBundle_dataCollectedEmpty() {
+ val dataLabel: DataLabel? =
+ DataLabel.getDataLabel(createSafetyLabelPersistableBundleWithNullDataCollected())
+
+ assertThat(dataLabel).isNotNull()
+ assertThat(dataLabel?.dataCollected).isEmpty()
+ assertThat(dataLabel?.dataShared).isNotEmpty()
+ }
+
+ @Test
+ fun getDataLabel_nullDataSharedBundle_dataSharedEmpty() {
+ val dataLabel: DataLabel? =
+ DataLabel.getDataLabel(createSafetyLabelPersistableBundleWithNullDataShared())
+
+ assertThat(dataLabel).isNotNull()
+ assertThat(dataLabel?.dataCollected).isNotEmpty()
+ assertThat(dataLabel?.dataShared).isEmpty()
+ }
+
+ @Test
+ fun getDataLabel_emptyDataCollectedBundle_dataCollectedEmpty() {
+ val dataLabel: DataLabel? =
+ DataLabel.getDataLabel(createSafetyLabelPersistableBundleWithEmptyDataCollected())
+
+ assertThat(dataLabel).isNotNull()
+ assertThat(dataLabel?.dataCollected).isEmpty()
+ assertThat(dataLabel?.dataShared).isNotEmpty()
+ }
+
+ @Test
+ fun getDataLabel_emptyDataSharedBundle_dataSharedEmpty() {
+ val dataLabel: DataLabel? =
+ DataLabel.getDataLabel(createSafetyLabelPersistableBundleWithEmptyDataShared())
+
+ assertThat(dataLabel).isNotNull()
+ assertThat(dataLabel?.dataCollected).isNotEmpty()
+ assertThat(dataLabel?.dataShared).isEmpty()
+ }
+
+ @Test
+ fun getDataLabel_invalidDataCollectedBundle_dataCollectedEmpty() {
+ val dataLabel: DataLabel? =
+ DataLabel.getDataLabel(createSafetyLabelPersistableBundleWithInvalidDataCollected())
+
+ assertThat(dataLabel).isNotNull()
+ assertThat(dataLabel?.dataCollected).isEmpty()
+ assertThat(dataLabel?.dataShared).isNotEmpty()
+ }
+
+ @Test
+ fun getDataLabel_invalidDataSharedBundle_dataSharedEmpty() {
+ val dataLabel: DataLabel? =
+ DataLabel.getDataLabel(createSafetyLabelPersistableBundleWithInvalidDataShared())
+
+ assertThat(dataLabel).isNotNull()
+ assertThat(dataLabel?.dataCollected).isNotEmpty()
+ assertThat(dataLabel?.dataShared).isEmpty()
+ }
+
+ @Test
+ fun getDataLabel_validBundle() {
+ val dataLabel: DataLabel? = DataLabel.getDataLabel(createSafetyLabelPersistableBundle())
+
+ assertThat(dataLabel).isNotNull()
+ assertThat(dataLabel?.dataCollected).isNotEmpty()
+ assertThat(dataLabel?.dataShared).isNotEmpty()
+ }
+}
diff --git a/SafetyLabel/tests/java/com/android/permission/safetylabel/DataTypeTest.kt b/SafetyLabel/tests/java/com/android/permission/safetylabel/DataTypeTest.kt
new file mode 100644
index 000000000..66d0db9f8
--- /dev/null
+++ b/SafetyLabel/tests/java/com/android/permission/safetylabel/DataTypeTest.kt
@@ -0,0 +1,280 @@
+/*
+ * 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.permission.safetylabel
+
+import android.os.PersistableBundle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.permission.safetylabel.DataCategoryConstants.CATEGORY_LOCATION
+import com.android.permission.safetylabel.DataPurposeConstants.PURPOSE_ADVERTISING
+import com.android.permission.safetylabel.DataPurposeConstants.PURPOSE_APP_FUNCTIONALITY
+import com.android.permission.safetylabel.DataType.KEY_EPHEMERAL
+import com.android.permission.safetylabel.DataType.KEY_PURPOSES
+import com.android.permission.safetylabel.DataType.KEY_IS_COLLECTION_OPTIONAL
+import com.android.permission.safetylabel.DataTypeConstants.LOCATION_APPROX_LOCATION
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.INVALID_KEY
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createInvalidTypeMapPersistableBundle
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createInvalidTypePersistableBundle
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createTypeMapPersistableBundle
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createTypeMapWithInvalidTypeDataPersistableBundle
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createTypePersistableBundle
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** CTS tests for [DataType]. */
+@RunWith(AndroidJUnit4::class)
+class DataTypeTest {
+ @Test
+ fun getDataTypeMap_invalidCategory_nullPersistableBundle_emptyMap() {
+ val dataTypeMap =
+ DataType.getDataTypeMap(null, DataLabelConstants.DATA_USAGE_SHARED, INVALID_KEY)
+
+ assertThat(dataTypeMap).isNotNull()
+ assertThat(dataTypeMap).isEmpty()
+ }
+
+ @Test
+ fun getDataTypeMap_invalidCategory_emptyPersistableBundle_emptyMap() {
+ val dataTypeMap =
+ DataType.getDataTypeMap(
+ PersistableBundle.EMPTY, DataLabelConstants.DATA_USAGE_SHARED, INVALID_KEY)
+
+ assertThat(dataTypeMap).isNotNull()
+ assertThat(dataTypeMap).isEmpty()
+ }
+
+ @Test
+ fun getDataTypeMap_invalidCategory_invalidBundle_emptyMap() {
+ val dataTypeMap =
+ DataType.getDataTypeMap(
+ createInvalidTypeMapPersistableBundle(),
+ DataLabelConstants.DATA_USAGE_SHARED,
+ INVALID_KEY)
+
+ assertThat(dataTypeMap).isNotNull()
+ assertThat(dataTypeMap).isEmpty()
+ }
+
+ @Test
+ fun getDataTypeMap_invalidCategory_validBundle_emptyMap() {
+ val dataTypeMap =
+ DataType.getDataTypeMap(
+ createTypeMapPersistableBundle(CATEGORY_LOCATION),
+ DataLabelConstants.DATA_USAGE_SHARED,
+ INVALID_KEY)
+
+ assertThat(dataTypeMap).isNotNull()
+ assertThat(dataTypeMap).isEmpty()
+ }
+
+ @Test
+ fun getDataTypeMap_validCategory_nullPersistableBundle_emptyMap() {
+ val dataTypeMap =
+ DataType.getDataTypeMap(null, DataLabelConstants.DATA_USAGE_SHARED, CATEGORY_LOCATION)
+
+ assertThat(dataTypeMap).isNotNull()
+ assertThat(dataTypeMap).isEmpty()
+ }
+
+ @Test
+ fun getDataTypeMap_validCategory_emptyPersistableBundle_emptyMap() {
+ val dataTypeMap =
+ DataType.getDataTypeMap(
+ PersistableBundle.EMPTY, DataLabelConstants.DATA_USAGE_SHARED, CATEGORY_LOCATION)
+
+ assertThat(dataTypeMap).isNotNull()
+ assertThat(dataTypeMap).isEmpty()
+ }
+
+ @Test
+ fun getDataTypeMap_validCategory_invalidBundle_emptyMap() {
+ val dataTypeMap =
+ DataType.getDataTypeMap(
+ createInvalidTypeMapPersistableBundle(),
+ DataLabelConstants.DATA_USAGE_SHARED,
+ CATEGORY_LOCATION)
+
+ assertThat(dataTypeMap).isNotNull()
+ assertThat(dataTypeMap).isEmpty()
+ }
+
+ @Test
+ fun getDataTypeMap_validCategory_validBundle_hasAllExpectedTypes() {
+ val typeMapPersistableBundle = createTypeMapPersistableBundle(CATEGORY_LOCATION)
+
+ val dataTypeMap =
+ DataType.getDataTypeMap(
+ typeMapPersistableBundle, DataLabelConstants.DATA_USAGE_SHARED, CATEGORY_LOCATION)
+
+ assertThat(dataTypeMap).isNotNull()
+ assertThat(dataTypeMap.keys)
+ .containsExactlyElementsIn(
+ DataTypeConstants.getValidDataTypesForCategory(CATEGORY_LOCATION))
+ }
+
+ @Test
+ fun getDataTypeMap_validCategory_validBundleWithAddedInvalidType_hasOnlyExpectedTypes() {
+ val typeMapPersistableBundle = createTypeMapPersistableBundle(CATEGORY_LOCATION)
+ // Add additional valid persistable bundle under invalid key
+ typeMapPersistableBundle.putPersistableBundle(INVALID_KEY, createTypePersistableBundle())
+
+ val dataTypeMap =
+ DataType.getDataTypeMap(
+ typeMapPersistableBundle, DataLabelConstants.DATA_USAGE_SHARED, CATEGORY_LOCATION)
+
+ assertThat(dataTypeMap).isNotNull()
+ assertThat(dataTypeMap.keys)
+ .containsExactlyElementsIn(
+ DataTypeConstants.getValidDataTypesForCategory(CATEGORY_LOCATION))
+ assertThat(dataTypeMap.keys).doesNotContain(INVALID_KEY)
+ }
+
+ @Test
+ fun getDataTypeMap_validCategory_validType_invalidData_emptyMap() {
+ val typeMapPersistableBundle =
+ createTypeMapWithInvalidTypeDataPersistableBundle(CATEGORY_LOCATION)
+
+ val dataTypeMap =
+ DataType.getDataTypeMap(
+ typeMapPersistableBundle, DataLabelConstants.DATA_USAGE_SHARED, CATEGORY_LOCATION)
+
+ assertThat(dataTypeMap).isNotNull()
+ assertThat(dataTypeMap).isEmpty()
+ }
+
+ @Test
+ fun getDataTypeMap_dataCollected_validCategory_validBundle_validateSingleExpectedType() {
+ val dataTypeMap =
+ DataType.getDataTypeMap(
+ createTypeMapPersistableBundle(CATEGORY_LOCATION),
+ DataLabelConstants.DATA_USAGE_COLLECTED,
+ CATEGORY_LOCATION)
+
+ assertThat(dataTypeMap).isNotNull()
+ assertThat(dataTypeMap).containsKey(LOCATION_APPROX_LOCATION)
+ val type = dataTypeMap[LOCATION_APPROX_LOCATION]!!
+ assertThat(type.purposeSet).containsExactly(PURPOSE_APP_FUNCTIONALITY, PURPOSE_ADVERTISING)
+ assertThat(type.isCollectionOptional).isTrue()
+ assertThat(type.ephemeral).isTrue()
+ }
+
+ @Test
+ fun getDataTypeMap_dataShared_validCategory_validBundle_validateSingleExpectedType() {
+ val dataTypeMap =
+ DataType.getDataTypeMap(
+ createTypeMapPersistableBundle(CATEGORY_LOCATION),
+ DataLabelConstants.DATA_USAGE_SHARED,
+ CATEGORY_LOCATION)
+
+ assertThat(dataTypeMap).isNotNull()
+ assertThat(dataTypeMap).containsKey(LOCATION_APPROX_LOCATION)
+ val type = dataTypeMap[LOCATION_APPROX_LOCATION]!!
+ assertThat(type.purposeSet).containsExactly(PURPOSE_APP_FUNCTIONALITY, PURPOSE_ADVERTISING)
+ assertThat(type.isCollectionOptional).isNull()
+ assertThat(type.ephemeral).isNull()
+ }
+
+ @Test
+ fun getDataType_invalidBundle_nullDataType() {
+ val dataType =
+ DataType.getDataType(
+ createInvalidTypePersistableBundle(), DataLabelConstants.DATA_USAGE_SHARED)
+
+ assertThat(dataType).isNull()
+ }
+
+ @Test
+ fun getDataType_dataCollected_validDataType() {
+ val dataType =
+ DataType.getDataType(
+ createTypePersistableBundle(), DataLabelConstants.DATA_USAGE_COLLECTED)
+
+ assertThat(dataType).isNotNull()
+ assertThat(dataType?.purposeSet)
+ .containsExactly(PURPOSE_APP_FUNCTIONALITY, PURPOSE_ADVERTISING)
+ assertThat(dataType?.isCollectionOptional).isTrue()
+ assertThat(dataType?.ephemeral).isTrue()
+ }
+
+ @Test
+ fun getDataType_dataShared_validDataType() {
+ val dataType =
+ DataType.getDataType(
+ createTypePersistableBundle(), DataLabelConstants.DATA_USAGE_SHARED)
+
+ assertThat(dataType).isNotNull()
+ assertThat(dataType?.purposeSet)
+ .containsExactly(PURPOSE_APP_FUNCTIONALITY, PURPOSE_ADVERTISING)
+ assertThat(dataType?.isCollectionOptional).isNull()
+ assertThat(dataType?.ephemeral).isNull()
+ }
+
+ @Test
+ fun getDataType_validDataTypeWithAddedInvalidPurpose_onlyValidPurposes() {
+ val typePersistableBundle = createTypePersistableBundle()
+ val purposes: IntArray = typePersistableBundle.getIntArray(KEY_PURPOSES)!!
+ val updatedPurposes: IntArray = intArrayOf(-1, *purposes)
+ typePersistableBundle.putIntArray(KEY_PURPOSES, updatedPurposes)
+
+ val dataType =
+ DataType.getDataType(typePersistableBundle, DataLabelConstants.DATA_USAGE_SHARED)
+
+ assertThat(dataType).isNotNull()
+ // Should not contain the additional "-1" purpose added above
+ assertThat(dataType?.purposeSet)
+ .containsExactly(PURPOSE_APP_FUNCTIONALITY, PURPOSE_ADVERTISING)
+ }
+
+ @Test
+ fun getDataType_dataTypeWithInvalidPurpose_nullDataType() {
+ val typePersistableBundle = createTypePersistableBundle()
+ typePersistableBundle.remove(KEY_PURPOSES)
+ val updatedPurposes: IntArray = intArrayOf(-1)
+ typePersistableBundle.putIntArray(KEY_PURPOSES, updatedPurposes)
+
+ val dataType =
+ DataType.getDataType(typePersistableBundle, DataLabelConstants.DATA_USAGE_SHARED)
+
+ assertThat(dataType).isNull()
+ }
+
+ @Test
+ fun getDataType_noPurpose_nullDataType() {
+ val typePersistableBundle = createTypePersistableBundle()
+ typePersistableBundle.remove(KEY_PURPOSES)
+
+ val dataType =
+ DataType.getDataType(typePersistableBundle, DataLabelConstants.DATA_USAGE_SHARED)
+
+ assertThat(dataType).isNull()
+ }
+
+ @Test
+ fun getDataType_dataCollected_validDataType_noUserControl_noEphemeral() {
+ val bundle = createTypePersistableBundle()
+ bundle.remove(KEY_IS_COLLECTION_OPTIONAL)
+ bundle.remove(KEY_EPHEMERAL)
+
+ val dataType = DataType.getDataType(bundle, DataLabelConstants.DATA_USAGE_COLLECTED)
+
+ assertThat(dataType).isNotNull()
+ assertThat(dataType?.purposeSet)
+ .containsExactly(PURPOSE_APP_FUNCTIONALITY, PURPOSE_ADVERTISING)
+ assertThat(dataType?.isCollectionOptional).isNull()
+ assertThat(dataType?.ephemeral).isNull()
+ }
+}
diff --git a/SafetyLabel/tests/java/com/android/permission/safetylabel/SafetyLabelTest.kt b/SafetyLabel/tests/java/com/android/permission/safetylabel/SafetyLabelTest.kt
new file mode 100644
index 000000000..1b694cc9a
--- /dev/null
+++ b/SafetyLabel/tests/java/com/android/permission/safetylabel/SafetyLabelTest.kt
@@ -0,0 +1,129 @@
+/*
+ * 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.permission.safetylabel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.permission.safetylabel.SafetyLabel.KEY_SAFETY_LABEL
+import com.android.permission.safetylabel.SafetyLabel.KEY_VERSION
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createInvalidMetadataPersistableBundle
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createMetadataPersistableBundle
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createMetadataPersistableBundleInvalidVersion
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createMetadataPersistableBundleWithInvalidSafetyLabel
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createMetadataPersistableBundleWithoutVersion
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createNonVersionedEmptyMetadataPersistableBundle
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createSafetyLabelPersistableBundleWithInvalidVersion
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createSafetyLabelPersistableBundleWithoutVersion
+import com.android.permission.safetylabel.SafetyLabelTestPersistableBundles.createVersionedEmptyMetadataPersistableBundle
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** CTS tests for [SafetyLabel]. */
+@RunWith(AndroidJUnit4::class)
+class SafetyLabelTest {
+
+ @Test
+ fun getSafetyLabelFromMetadata_nullMetadataBundle_nullSafetyLabel() {
+ val safetyLabel = SafetyLabel.getSafetyLabelFromMetadata(null)
+
+ assertThat(safetyLabel).isNull()
+ }
+
+ @Test
+ fun getSafetyLabelFromMetadata_emptyMetadataBundle_nullSafetyLabel() {
+ val safetyLabel =
+ SafetyLabel.getSafetyLabelFromMetadata(createNonVersionedEmptyMetadataPersistableBundle())
+
+ assertThat(safetyLabel).isNull()
+ }
+
+ @Test
+ fun getSafetyLabelFromMetadata_emptyVersionedMetadataBundle_nullSafetyLabel() {
+ val safetyLabel =
+ SafetyLabel.getSafetyLabelFromMetadata(createVersionedEmptyMetadataPersistableBundle())
+
+ assertThat(safetyLabel).isNull()
+ }
+
+ @Test
+ fun getSafetyLabelFromMetadata_invalidMetadataBundle_nullSafetyLabel() {
+ val safetyLabel =
+ SafetyLabel.getSafetyLabelFromMetadata(createInvalidMetadataPersistableBundle())
+
+ assertThat(safetyLabel).isNull()
+ }
+
+ @Test
+ fun getSafetyLabelFromMetadata_invalidSafetyLabelBundle_dataSharedEmpty() {
+ val safetyLabel =
+ SafetyLabel.getSafetyLabelFromMetadata(
+ createMetadataPersistableBundleWithInvalidSafetyLabel())
+
+ assertThat(safetyLabel).isNull()
+ }
+
+ @Test
+ fun getSafetyLabelFromMetadata_validBundle_hasDataShared() {
+ val bundle = createMetadataPersistableBundle(TOP_LEVEL_VERSION, SAFETY_LABELS_VERSION)
+ val topLevelVersion = bundle.getLong(KEY_VERSION)
+ val safetyLabelBundle = bundle.getPersistableBundle(KEY_SAFETY_LABEL)
+ val safetyLabelsVersion = safetyLabelBundle?.getLong(KEY_VERSION)
+ val safetyLabel = SafetyLabel.getSafetyLabelFromMetadata(bundle)
+
+ assertThat(topLevelVersion).isEqualTo(TOP_LEVEL_VERSION)
+ assertThat(safetyLabelsVersion).isEqualTo(SAFETY_LABELS_VERSION)
+ assertThat(safetyLabel).isNotNull()
+ assertThat(safetyLabel?.dataLabel).isNotNull()
+ }
+
+ @Test
+ fun getSafetyLabelFromMetadata_invalidBundle_noTopLevelBundleVersion() {
+ val safetyLabel =
+ SafetyLabel.getSafetyLabelFromMetadata(createMetadataPersistableBundleWithoutVersion())
+ assertThat(safetyLabel).isNull()
+ }
+
+ @Test
+ fun getSafetyLabelFromMetadata_invalidBundle_InvalidTopLevelBundleVersion() {
+ val safetyLabel =
+ SafetyLabel.getSafetyLabelFromMetadata(createMetadataPersistableBundleInvalidVersion())
+ assertThat(safetyLabel).isNull()
+ }
+
+ @Test
+ fun getSafetyLabelFromMetadata_invalidBundle_NoSafetyLabelBundleVersion() {
+ val bundle = createVersionedEmptyMetadataPersistableBundle()
+ bundle.putPersistableBundle(
+ SafetyLabel.KEY_SAFETY_LABEL, createSafetyLabelPersistableBundleWithoutVersion())
+ val safetyLabel = SafetyLabel.getSafetyLabelFromMetadata(bundle)
+ assertThat(safetyLabel).isNull()
+ }
+
+ @Test
+ fun getSafetyLabelFromMetadata_invalidBundle_InvalidSafetyLabelBundleVersion() {
+ val bundle = createVersionedEmptyMetadataPersistableBundle()
+ bundle.putPersistableBundle(
+ SafetyLabel.KEY_SAFETY_LABEL, createSafetyLabelPersistableBundleWithInvalidVersion())
+ val safetyLabel = SafetyLabel.getSafetyLabelFromMetadata(bundle)
+ assertThat(safetyLabel).isNull()
+ }
+
+ companion object {
+ private const val TOP_LEVEL_VERSION = 3L
+ private const val SAFETY_LABELS_VERSION = 2L
+ }
+} \ No newline at end of file
diff --git a/SafetyLabel/tests/java/com/android/permission/safetylabel/SafetyLabelTestPersistableBundles.kt b/SafetyLabel/tests/java/com/android/permission/safetylabel/SafetyLabelTestPersistableBundles.kt
new file mode 100644
index 000000000..ae4459b44
--- /dev/null
+++ b/SafetyLabel/tests/java/com/android/permission/safetylabel/SafetyLabelTestPersistableBundles.kt
@@ -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.permission.safetylabel
+
+import android.os.PersistableBundle
+
+import androidx.annotation.VisibleForTesting
+
+import com.android.permission.safetylabel.DataCategoryConstants.CATEGORY_LOCATION
+import com.android.permission.safetylabel.DataCategoryConstants.Category
+import com.android.permission.safetylabel.DataPurposeConstants.PURPOSE_ADVERTISING
+import com.android.permission.safetylabel.DataPurposeConstants.PURPOSE_APP_FUNCTIONALITY
+import com.android.permission.safetylabel.DataType.KEY_EPHEMERAL
+import com.android.permission.safetylabel.DataType.KEY_PURPOSES
+import com.android.permission.safetylabel.DataType.KEY_IS_COLLECTION_OPTIONAL
+import com.android.permission.safetylabel.SafetyLabel.KEY_VERSION
+
+/** A class that facilitates creating test safety label persistable bundles. */
+object SafetyLabelTestPersistableBundles {
+ private const val TOP_LEVEL_VERSION = 1L
+ private const val SAFETY_LABELS_VERSION = 1L
+ @VisibleForTesting const val INVALID_TOP_LEVEL_VERSION = -1L
+ @VisibleForTesting const val INVALID_SAFETY_LABELS_VERSION = -2L
+ const val INVALID_KEY = "invalid_key"
+
+ /**
+ * Returns [PersistableBundle] representation of an empty top level metadata persistable bundle.
+ */
+ fun createNonVersionedEmptyMetadataPersistableBundle(): PersistableBundle {
+ return PersistableBundle()
+ }
+
+ /**
+ * Returns [PersistableBundle] representation of a top level metadata versioned by the provided
+ * top level version number, or the default value [TOP_LEVEL_VERSION] if not provided.
+ */
+ fun createVersionedEmptyMetadataPersistableBundle(
+ version: Long = TOP_LEVEL_VERSION
+ ): PersistableBundle {
+ return PersistableBundle().apply {
+ putLong(KEY_VERSION, version)
+ }
+ }
+
+ /**
+ * Returns [PersistableBundle] representation of a top level metadata versioned by the provided
+ * top level version number, or the default value [TOP_LEVEL_VERSION] if not provided.
+ * And the embedded safety labels will be versioned by the provided safety labels version number,
+ * or the default value [SAFETY_LABELS_VERSION] if not provided.
+ */
+ fun createMetadataPersistableBundle(
+ topLevelVersion: Long = TOP_LEVEL_VERSION,
+ safetyLabelsVersion: Long = SAFETY_LABELS_VERSION
+ ): PersistableBundle {
+ return createVersionedEmptyMetadataPersistableBundle(topLevelVersion).apply {
+ putPersistableBundle(SafetyLabel.KEY_SAFETY_LABEL,
+ createSafetyLabelPersistableBundle(safetyLabelsVersion))
+ }
+ }
+
+ /**
+ * Returns [PersistableBundle] representation of a metadata with invalid safety label key.
+ */
+ fun createInvalidMetadataPersistableBundle(): PersistableBundle {
+ return createVersionedEmptyMetadataPersistableBundle().apply {
+ putPersistableBundle(INVALID_KEY, createSafetyLabelPersistableBundle())
+ }
+ }
+
+ /**
+ * Returns [PersistableBundle] representation of a metadata with invalid safety label bundle.
+ */
+ fun createMetadataPersistableBundleWithInvalidSafetyLabel(): PersistableBundle {
+ return createVersionedEmptyMetadataPersistableBundle().apply {
+ putPersistableBundle(
+ SafetyLabel.KEY_SAFETY_LABEL, createInvalidSafetyLabelPersistableBundle())
+ }
+ }
+
+ /**
+ * Returns [PersistableBundle] representation of an invalid metadata without version number.
+ */
+ fun createMetadataPersistableBundleWithoutVersion(): PersistableBundle {
+ return createMetadataPersistableBundle().apply { remove(KEY_VERSION) }
+ }
+
+ /**
+ * Returns [PersistableBundle] representation of a metadata with invalid top level version number.
+ */
+ fun createMetadataPersistableBundleInvalidVersion(): PersistableBundle {
+ return createMetadataPersistableBundle().apply {
+ putLong(KEY_VERSION, INVALID_TOP_LEVEL_VERSION)
+ }
+ }
+
+ /**
+ * Returns [PersistableBundle] representation of an empty safety label versioned by the provided
+ * version number, or the default value [SAFETY_LABELS_VERSION] if not provided.
+ */
+ private fun createVersionedEmptySafetyLabelsPersistableBundle(
+ version: Long = SAFETY_LABELS_VERSION
+ ): PersistableBundle {
+ return PersistableBundle().apply {
+ putLong(KEY_VERSION, version)
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of a valid safety label */
+ fun createSafetyLabelPersistableBundle(
+ version: Long = SAFETY_LABELS_VERSION
+ ): PersistableBundle {
+ return createVersionedEmptySafetyLabelsPersistableBundle(version).apply {
+ putPersistableBundle(DataLabel.KEY_DATA_LABEL, createDataLabelPersistableBundle())
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of a non-versioned invalid safety label */
+ fun createSafetyLabelPersistableBundleWithoutVersion(): PersistableBundle {
+ return createSafetyLabelPersistableBundle().apply {
+ remove(KEY_VERSION)
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of a safety label with invalid version number */
+ fun createSafetyLabelPersistableBundleWithInvalidVersion(): PersistableBundle {
+ return createSafetyLabelPersistableBundle().apply {
+ putLong(KEY_VERSION, INVALID_SAFETY_LABELS_VERSION)
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of an invalid safety label */
+ fun createInvalidSafetyLabelPersistableBundle(): PersistableBundle {
+ return createVersionedEmptySafetyLabelsPersistableBundle().apply {
+ putPersistableBundle(INVALID_KEY, createDataLabelPersistableBundle())
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of an invalid safety label */
+ fun createSafetyLabelPersistableBundleWithNullDataCollected(): PersistableBundle {
+ return createVersionedEmptySafetyLabelsPersistableBundle().apply {
+ putPersistableBundle(
+ DataLabel.KEY_DATA_LABEL, createDataLabelPersistableBundleWithNullDataCollected())
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of an invalid safety label */
+ fun createSafetyLabelPersistableBundleWithNullDataShared(): PersistableBundle {
+ return createVersionedEmptySafetyLabelsPersistableBundle().apply {
+ putPersistableBundle(
+ DataLabel.KEY_DATA_LABEL, createDataLabelPersistableBundleWithNullDataShared())
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of an invalid safety label */
+ fun createSafetyLabelPersistableBundleWithEmptyDataCollected(): PersistableBundle {
+ return createVersionedEmptySafetyLabelsPersistableBundle().apply {
+ putPersistableBundle(
+ DataLabel.KEY_DATA_LABEL, createDataLabelPersistableBundleWithEmptyDataCollected())
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of an invalid safety label */
+ fun createSafetyLabelPersistableBundleWithEmptyDataShared(): PersistableBundle {
+ return createVersionedEmptySafetyLabelsPersistableBundle().apply {
+ putPersistableBundle(
+ DataLabel.KEY_DATA_LABEL, createDataLabelPersistableBundleWithEmptyDataShared())
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of an invalid safety label */
+ fun createSafetyLabelPersistableBundleWithInvalidDataCollected(): PersistableBundle {
+ return createVersionedEmptySafetyLabelsPersistableBundle().apply {
+ putPersistableBundle(
+ DataLabel.KEY_DATA_LABEL, createDataLabelPersistableBundleWithInvalidDataCollected())
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of an invalid safety label */
+ fun createSafetyLabelPersistableBundleWithInvalidDataShared(): PersistableBundle {
+ return createVersionedEmptySafetyLabelsPersistableBundle().apply {
+ putPersistableBundle(
+ DataLabel.KEY_DATA_LABEL, createDataLabelPersistableBundleWithInvalidDataShared())
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of a data label */
+ fun createDataLabelPersistableBundle(): PersistableBundle {
+ return createVersionedEmptySafetyLabelsPersistableBundle().apply {
+ putPersistableBundle(
+ DataLabelConstants.DATA_USAGE_SHARED, createCategoryMapPersistableBundle())
+ putPersistableBundle(
+ DataLabelConstants.DATA_USAGE_COLLECTED, createCategoryMapPersistableBundle())
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of an invalid data label */
+ fun createInvalidDataLabelPersistableBundle(): PersistableBundle {
+ return createVersionedEmptySafetyLabelsPersistableBundle().apply {
+ putPersistableBundle(INVALID_KEY, createCategoryMapPersistableBundle())
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of a null data collected data label */
+ private fun createDataLabelPersistableBundleWithNullDataCollected(): PersistableBundle {
+ return createDataLabelPersistableBundle().apply {
+ remove(DataLabelConstants.DATA_USAGE_COLLECTED)
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of a null data shared data label */
+ private fun createDataLabelPersistableBundleWithNullDataShared(): PersistableBundle {
+ return createDataLabelPersistableBundle().apply { remove(DataLabelConstants.DATA_USAGE_SHARED) }
+ }
+
+ /** Returns [PersistableBundle] representation of an empty data collected data label */
+ private fun createDataLabelPersistableBundleWithEmptyDataCollected(): PersistableBundle {
+ return createDataLabelPersistableBundle().apply {
+ remove(DataLabelConstants.DATA_USAGE_COLLECTED)
+ putPersistableBundle(DataLabelConstants.DATA_USAGE_COLLECTED, PersistableBundle.EMPTY)
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of an empty data shared data label */
+ private fun createDataLabelPersistableBundleWithEmptyDataShared(): PersistableBundle {
+ return createDataLabelPersistableBundle().apply {
+ remove(DataLabelConstants.DATA_USAGE_SHARED)
+ putPersistableBundle(DataLabelConstants.DATA_USAGE_SHARED, PersistableBundle.EMPTY)
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of an invalid data collected data label */
+ private fun createDataLabelPersistableBundleWithInvalidDataCollected(): PersistableBundle {
+ return createDataLabelPersistableBundle().apply {
+ remove(DataLabelConstants.DATA_USAGE_COLLECTED)
+ putPersistableBundle(
+ DataLabelConstants.DATA_USAGE_COLLECTED, createInvalidCategoryMapPersistableBundle())
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of an invalid data shared data label */
+ private fun createDataLabelPersistableBundleWithInvalidDataShared(): PersistableBundle {
+ return createDataLabelPersistableBundle().apply {
+ remove(DataLabelConstants.DATA_USAGE_SHARED)
+ putPersistableBundle(
+ DataLabelConstants.DATA_USAGE_SHARED, createInvalidCategoryMapPersistableBundle())
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of data label with additional invalid categories*/
+ fun createDataLabelPersistableBundleWithAdditonalInvalidCategory(): PersistableBundle {
+ return PersistableBundle().apply {
+ putPersistableBundle(
+ DataLabelConstants.DATA_USAGE_SHARED,
+ createCategoryMapPersistableBundleWithAdditionalInvalidCategory())
+ putPersistableBundle(
+ DataLabelConstants.DATA_USAGE_COLLECTED,
+ createCategoryMapPersistableBundleWithAdditionalInvalidCategory())
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of a [Map] of valid data categories */
+ fun createCategoryMapPersistableBundle(): PersistableBundle {
+ return PersistableBundle().apply {
+ DataCategoryConstants.VALID_CATEGORIES.forEach { categoryKey ->
+ putPersistableBundle(categoryKey, createTypeMapPersistableBundle(categoryKey))
+ }
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of a [Map] of valid data categories */
+ fun createCategoryMapPersistableBundleWithAdditionalInvalidCategory(): PersistableBundle {
+ return PersistableBundle().apply {
+ DataCategoryConstants.VALID_CATEGORIES.forEach { categoryKey ->
+ putPersistableBundle(categoryKey, createTypeMapPersistableBundle(categoryKey))
+ }
+ putPersistableBundle(INVALID_KEY, createTypeMapPersistableBundle(CATEGORY_LOCATION))
+ }
+ }
+
+ /**
+ * Returns [PersistableBundle] representation of a [Map] of valid data categories and invalid
+ * types
+ */
+ fun createCategoryMapPersistableBundleWithInvalidTypes(): PersistableBundle {
+ return PersistableBundle().apply {
+ DataCategoryConstants.VALID_CATEGORIES.forEach { categoryKey ->
+ putPersistableBundle(categoryKey, createInvalidTypeMapPersistableBundle())
+ }
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of a [Map] of invalid data categories */
+ fun createInvalidCategoryMapPersistableBundle(): PersistableBundle {
+ return PersistableBundle().apply {
+ putPersistableBundle(INVALID_KEY, createTypeMapPersistableBundle(CATEGORY_LOCATION))
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of a [Map] of valid data type */
+ fun createTypeMapPersistableBundle(@Category category: String): PersistableBundle {
+ return PersistableBundle().apply {
+ DataTypeConstants.getValidDataTypesForCategory(category).forEach { type ->
+ putPersistableBundle(type, createTypePersistableBundle())
+ }
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of a [Map] of invalid data type */
+ fun createInvalidTypeMapPersistableBundle(): PersistableBundle {
+ return PersistableBundle().apply {
+ putPersistableBundle(INVALID_KEY, createTypePersistableBundle())
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of a [Map] of valid type, with invalid data */
+ fun createTypeMapWithInvalidTypeDataPersistableBundle(
+ @Category category: String
+ ): PersistableBundle {
+ return PersistableBundle().apply {
+ DataTypeConstants.getValidDataTypesForCategory(category).forEach { type ->
+ putPersistableBundle(type, createInvalidTypePersistableBundle())
+ }
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of a valid data type */
+ fun createTypePersistableBundle(): PersistableBundle {
+ return PersistableBundle().apply {
+ putIntArray(KEY_PURPOSES, intArrayOf(PURPOSE_APP_FUNCTIONALITY, PURPOSE_ADVERTISING))
+ putBoolean(KEY_IS_COLLECTION_OPTIONAL, true)
+ putBoolean(KEY_EPHEMERAL, true)
+ }
+ }
+
+ /** Returns [PersistableBundle] representation of an invalid data type */
+ fun createInvalidTypePersistableBundle(): PersistableBundle {
+ return PersistableBundle().apply { putLong(INVALID_KEY, 0) }
+ }
+}
diff --git a/framework-s/Android.bp b/framework-s/Android.bp
index 5b0cc1aee..e017a7ea5 100644
--- a/framework-s/Android.bp
+++ b/framework-s/Android.bp
@@ -34,8 +34,8 @@ filegroup {
}
filegroup {
- name: "safetycenter-config-schema",
- srcs: ["java/android/safetycenter/config/safety_center_config.xsd"],
+ name: "safetycenter-config-schemas",
+ srcs: ["java/android/safetycenter/config/safety_center_config*.xsd"],
path: "java/android/safetycenter/config/",
visibility: ["//packages/modules/Permission/SafetyCenter/ConfigLintChecker"],
}
@@ -68,6 +68,7 @@ java_sdk_library {
],
static_libs: [
"framework-permission-s-shared",
+ "modules-utils-build",
],
apex_available: [
"com.android.permission",
@@ -80,7 +81,7 @@ java_sdk_library {
"//packages/modules/Permission:__subpackages__",
],
installable: true,
- jarjar_rules: ":permission-jarjar-rules",
+ jarjar_rules: "jarjar-rules.txt",
lint: {
strict_updatability_linting: true,
},
@@ -89,8 +90,7 @@ java_sdk_library {
"android.permission",
"android.app.role",
"android.safetycenter",
- // For com.android.permission.jarjar.
- "com.android.permission",
+ "android.safetylabel",
],
}
diff --git a/framework-s/api/current.txt b/framework-s/api/current.txt
index 4ecc98980..d54af92f5 100644
--- a/framework-s/api/current.txt
+++ b/framework-s/api/current.txt
@@ -12,6 +12,7 @@ package android.app.role {
field public static final String ROLE_DIALER = "android.app.role.DIALER";
field public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY";
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";
}
diff --git a/framework-s/api/system-current.txt b/framework-s/api/system-current.txt
index db2d140ca..9545356a4 100644
--- a/framework-s/api/system-current.txt
+++ b/framework-s/api/system-current.txt
@@ -23,6 +23,7 @@ package android.app.role {
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void addRoleHolderAsUser(@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 addRoleHolderFromController(@NonNull String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_DEFAULT_APPLICATIONS) public String getDefaultApplication(@NonNull String);
method @Deprecated @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
@@ -33,10 +34,13 @@ package android.app.role {
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 @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";
+ field public static final String ROLE_FINANCED_DEVICE_KIOSK = "android.app.role.FINANCED_DEVICE_KIOSK";
field public static final String ROLE_SYSTEM_ACTIVITY_RECOGNIZER = "android.app.role.SYSTEM_ACTIVITY_RECOGNIZER";
+ field public static final String ROLE_SYSTEM_CALL_STREAMING = "android.app.role.SYSTEM_CALL_STREAMING";
field public static final String ROLE_SYSTEM_SUPERVISION = "android.app.role.SYSTEM_SUPERVISION";
field public static final String ROLE_SYSTEM_WELLBEING = "android.app.role.SYSTEM_WELLBEING";
}
@@ -48,7 +52,9 @@ package android.safetycenter {
public final class SafetyCenterData implements android.os.Parcelable {
ctor public SafetyCenterData(@NonNull android.safetycenter.SafetyCenterStatus, @NonNull java.util.List<android.safetycenter.SafetyCenterIssue>, @NonNull java.util.List<android.safetycenter.SafetyCenterEntryOrGroup>, @NonNull java.util.List<android.safetycenter.SafetyCenterStaticEntryGroup>);
method public int describeContents();
+ method @NonNull public java.util.List<android.safetycenter.SafetyCenterIssue> getDismissedIssues();
method @NonNull public java.util.List<android.safetycenter.SafetyCenterEntryOrGroup> getEntriesOrGroups();
+ method @NonNull public android.os.Bundle getExtras();
method @NonNull public java.util.List<android.safetycenter.SafetyCenterIssue> getIssues();
method @NonNull public java.util.List<android.safetycenter.SafetyCenterStaticEntryGroup> getStaticEntryGroups();
method @NonNull public android.safetycenter.SafetyCenterStatus getStatus();
@@ -56,6 +62,22 @@ package android.safetycenter {
field @NonNull public static final android.os.Parcelable.Creator<android.safetycenter.SafetyCenterData> CREATOR;
}
+ public static final class SafetyCenterData.Builder {
+ ctor public SafetyCenterData.Builder(@NonNull android.safetycenter.SafetyCenterStatus);
+ ctor public SafetyCenterData.Builder(@NonNull android.safetycenter.SafetyCenterData);
+ method @NonNull public android.safetycenter.SafetyCenterData.Builder addDismissedIssue(@NonNull android.safetycenter.SafetyCenterIssue);
+ method @NonNull public android.safetycenter.SafetyCenterData.Builder addEntryOrGroup(@NonNull android.safetycenter.SafetyCenterEntryOrGroup);
+ method @NonNull public android.safetycenter.SafetyCenterData.Builder addIssue(@NonNull android.safetycenter.SafetyCenterIssue);
+ method @NonNull public android.safetycenter.SafetyCenterData.Builder addStaticEntryGroup(@NonNull android.safetycenter.SafetyCenterStaticEntryGroup);
+ method @NonNull public android.safetycenter.SafetyCenterData build();
+ method @NonNull public android.safetycenter.SafetyCenterData.Builder clearDismissedIssues();
+ method @NonNull public android.safetycenter.SafetyCenterData.Builder clearEntriesOrGroups();
+ method @NonNull public android.safetycenter.SafetyCenterData.Builder clearExtras();
+ method @NonNull public android.safetycenter.SafetyCenterData.Builder clearIssues();
+ method @NonNull public android.safetycenter.SafetyCenterData.Builder clearStaticEntryGroups();
+ method @NonNull public android.safetycenter.SafetyCenterData.Builder setExtras(@NonNull android.os.Bundle);
+ }
+
public final class SafetyCenterEntry implements android.os.Parcelable {
method public int describeContents();
method @Nullable public android.safetycenter.SafetyCenterEntry.IconAction getIconAction();
@@ -149,6 +171,8 @@ package android.safetycenter {
public final class SafetyCenterIssue implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.List<android.safetycenter.SafetyCenterIssue.Action> getActions();
+ method @Nullable public CharSequence getAttributionTitle();
+ method @Nullable public String getGroupId();
method @NonNull public String getId();
method public int getSeverityLevel();
method @Nullable public CharSequence getSubtitle();
@@ -165,6 +189,7 @@ package android.safetycenter {
public static final class SafetyCenterIssue.Action implements android.os.Parcelable {
method public int describeContents();
+ method @Nullable public android.safetycenter.SafetyCenterIssue.Action.ConfirmationDialogDetails getConfirmationDialogDetails();
method @NonNull public String getId();
method @NonNull public CharSequence getLabel();
method @NonNull public android.app.PendingIntent getPendingIntent();
@@ -177,7 +202,9 @@ package android.safetycenter {
public static final class SafetyCenterIssue.Action.Builder {
ctor public SafetyCenterIssue.Action.Builder(@NonNull String, @NonNull CharSequence, @NonNull android.app.PendingIntent);
+ ctor public SafetyCenterIssue.Action.Builder(@NonNull android.safetycenter.SafetyCenterIssue.Action);
method @NonNull public android.safetycenter.SafetyCenterIssue.Action build();
+ method @NonNull public android.safetycenter.SafetyCenterIssue.Action.Builder setConfirmationDialogDetails(@Nullable android.safetycenter.SafetyCenterIssue.Action.ConfirmationDialogDetails);
method @NonNull public android.safetycenter.SafetyCenterIssue.Action.Builder setId(@NonNull String);
method @NonNull public android.safetycenter.SafetyCenterIssue.Action.Builder setIsInFlight(boolean);
method @NonNull public android.safetycenter.SafetyCenterIssue.Action.Builder setLabel(@NonNull CharSequence);
@@ -186,12 +213,25 @@ package android.safetycenter {
method @NonNull public android.safetycenter.SafetyCenterIssue.Action.Builder setWillResolve(boolean);
}
+ public static final class SafetyCenterIssue.Action.ConfirmationDialogDetails implements android.os.Parcelable {
+ ctor public SafetyCenterIssue.Action.ConfirmationDialogDetails(@NonNull CharSequence, @NonNull CharSequence, @NonNull CharSequence, @NonNull CharSequence);
+ method public int describeContents();
+ method @NonNull public CharSequence getAcceptButtonText();
+ method @NonNull public CharSequence getDenyButtonText();
+ method @NonNull public CharSequence getText();
+ method @NonNull public CharSequence getTitle();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.safetycenter.SafetyCenterIssue.Action.ConfirmationDialogDetails> CREATOR;
+ }
+
public static final class SafetyCenterIssue.Builder {
ctor public SafetyCenterIssue.Builder(@NonNull String, @NonNull CharSequence, @NonNull CharSequence);
ctor public SafetyCenterIssue.Builder(@NonNull android.safetycenter.SafetyCenterIssue);
method @NonNull public android.safetycenter.SafetyCenterIssue build();
method @NonNull public android.safetycenter.SafetyCenterIssue.Builder setActions(@NonNull java.util.List<android.safetycenter.SafetyCenterIssue.Action>);
+ method @NonNull public android.safetycenter.SafetyCenterIssue.Builder setAttributionTitle(@Nullable CharSequence);
method @NonNull public android.safetycenter.SafetyCenterIssue.Builder setDismissible(boolean);
+ method @NonNull public android.safetycenter.SafetyCenterIssue.Builder setGroupId(@Nullable String);
method @NonNull public android.safetycenter.SafetyCenterIssue.Builder setId(@NonNull String);
method @NonNull public android.safetycenter.SafetyCenterIssue.Builder setSeverityLevel(int);
method @NonNull public android.safetycenter.SafetyCenterIssue.Builder setShouldConfirmDismissal(boolean);
@@ -211,6 +251,7 @@ package android.safetycenter {
method @Nullable @RequiresPermission(android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE) public android.safetycenter.SafetySourceData getSafetySourceData(@NonNull String);
method @RequiresPermission(anyOf={android.Manifest.permission.READ_SAFETY_CENTER_STATUS, android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE}) public boolean isSafetyCenterEnabled();
method @RequiresPermission(android.Manifest.permission.MANAGE_SAFETY_CENTER) public void refreshSafetySources(int);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_SAFETY_CENTER) public void refreshSafetySources(int, @NonNull java.util.List<java.lang.String>);
method @RequiresPermission(android.Manifest.permission.MANAGE_SAFETY_CENTER) public void removeOnSafetyCenterDataChangedListener(@NonNull android.safetycenter.SafetyCenterManager.OnSafetyCenterDataChangedListener);
method @RequiresPermission(android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE) public void reportSafetySourceError(@NonNull String, @NonNull android.safetycenter.SafetySourceErrorDetails);
method @RequiresPermission(android.Manifest.permission.MANAGE_SAFETY_CENTER) public void setSafetyCenterConfigForTests(@NonNull android.safetycenter.config.SafetyCenterConfig);
@@ -222,6 +263,7 @@ package android.safetycenter {
field public static final String EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID = "android.safetycenter.extra.REFRESH_SAFETY_SOURCES_BROADCAST_ID";
field public static final String EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE = "android.safetycenter.extra.REFRESH_SAFETY_SOURCES_REQUEST_TYPE";
field public static final String EXTRA_REFRESH_SAFETY_SOURCE_IDS = "android.safetycenter.extra.REFRESH_SAFETY_SOURCE_IDS";
+ field public static final String EXTRA_SAFETY_SOURCES_GROUP_ID = "android.safetycenter.extra.SAFETY_SOURCES_GROUP_ID";
field public static final String EXTRA_SAFETY_SOURCE_ID = "android.safetycenter.extra.SAFETY_SOURCE_ID";
field public static final String EXTRA_SAFETY_SOURCE_ISSUE_ID = "android.safetycenter.extra.SAFETY_SOURCE_ISSUE_ID";
field public static final String EXTRA_SAFETY_SOURCE_USER_HANDLE = "android.safetycenter.extra.SAFETY_SOURCE_USER_HANDLE";
@@ -229,6 +271,7 @@ package android.safetycenter {
field public static final int REFRESH_REASON_DEVICE_REBOOT = 300; // 0x12c
field public static final int REFRESH_REASON_OTHER = 600; // 0x258
field public static final int REFRESH_REASON_PAGE_OPEN = 100; // 0x64
+ field public static final int REFRESH_REASON_PERIODIC = 700; // 0x2bc
field public static final int REFRESH_REASON_RESCAN_BUTTON_CLICK = 200; // 0xc8
field public static final int REFRESH_REASON_SAFETY_CENTER_ENABLED = 500; // 0x1f4
}
@@ -310,6 +353,7 @@ package android.safetycenter {
public static final class SafetyEvent.Builder {
ctor public SafetyEvent.Builder(int);
+ ctor public SafetyEvent.Builder(@NonNull android.safetycenter.SafetyEvent);
method @NonNull public android.safetycenter.SafetyEvent build();
method @NonNull public android.safetycenter.SafetyEvent.Builder setRefreshBroadcastId(@Nullable String);
method @NonNull public android.safetycenter.SafetyEvent.Builder setSafetySourceIssueActionId(@Nullable String);
@@ -318,6 +362,7 @@ package android.safetycenter {
public final class SafetySourceData implements android.os.Parcelable {
method public int describeContents();
+ method @NonNull public android.os.Bundle getExtras();
method @NonNull public java.util.List<android.safetycenter.SafetySourceIssue> getIssues();
method @Nullable public android.safetycenter.SafetySourceStatus getStatus();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -330,9 +375,12 @@ package android.safetycenter {
public static final class SafetySourceData.Builder {
ctor public SafetySourceData.Builder();
+ ctor public SafetySourceData.Builder(@NonNull android.safetycenter.SafetySourceData);
method @NonNull public android.safetycenter.SafetySourceData.Builder addIssue(@NonNull android.safetycenter.SafetySourceIssue);
method @NonNull public android.safetycenter.SafetySourceData build();
+ method @NonNull public android.safetycenter.SafetySourceData.Builder clearExtras();
method @NonNull public android.safetycenter.SafetySourceData.Builder clearIssues();
+ method @NonNull public android.safetycenter.SafetySourceData.Builder setExtras(@NonNull android.os.Bundle);
method @NonNull public android.safetycenter.SafetySourceData.Builder setStatus(@Nullable android.safetycenter.SafetySourceStatus);
}
@@ -347,9 +395,14 @@ package android.safetycenter {
public final class SafetySourceIssue implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.List<android.safetycenter.SafetySourceIssue.Action> getActions();
+ method @Nullable public CharSequence getAttributionTitle();
+ method @Nullable public android.safetycenter.SafetySourceIssue.Notification getCustomNotification();
+ method @Nullable public String getDeduplicationId();
method @NonNull public String getId();
+ method public int getIssueActionability();
method public int getIssueCategory();
method @NonNull public String getIssueTypeId();
+ method public int getNotificationBehavior();
method @Nullable public android.app.PendingIntent getOnDismissPendingIntent();
method public int getSeverityLevel();
method @Nullable public CharSequence getSubtitle();
@@ -357,13 +410,24 @@ package android.safetycenter {
method @NonNull public CharSequence getTitle();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.safetycenter.SafetySourceIssue> CREATOR;
+ field public static final int ISSUE_ACTIONABILITY_AUTOMATIC = 200; // 0xc8
+ field public static final int ISSUE_ACTIONABILITY_MANUAL = 0; // 0x0
+ field public static final int ISSUE_ACTIONABILITY_TIP = 100; // 0x64
field public static final int ISSUE_CATEGORY_ACCOUNT = 200; // 0xc8
+ field public static final int ISSUE_CATEGORY_DATA = 400; // 0x190
field public static final int ISSUE_CATEGORY_DEVICE = 100; // 0x64
field public static final int ISSUE_CATEGORY_GENERAL = 300; // 0x12c
+ field public static final int ISSUE_CATEGORY_PASSWORDS = 500; // 0x1f4
+ field public static final int ISSUE_CATEGORY_PERSONAL_SAFETY = 600; // 0x258
+ field public static final int NOTIFICATION_BEHAVIOR_DELAYED = 200; // 0xc8
+ field public static final int NOTIFICATION_BEHAVIOR_IMMEDIATELY = 300; // 0x12c
+ field public static final int NOTIFICATION_BEHAVIOR_NEVER = 100; // 0x64
+ field public static final int NOTIFICATION_BEHAVIOR_UNSPECIFIED = 0; // 0x0
}
public static final class SafetySourceIssue.Action implements android.os.Parcelable {
method public int describeContents();
+ method @Nullable public android.safetycenter.SafetySourceIssue.Action.ConfirmationDialogDetails getConfirmationDialogDetails();
method @NonNull public String getId();
method @NonNull public CharSequence getLabel();
method @NonNull public android.app.PendingIntent getPendingIntent();
@@ -375,21 +439,58 @@ package android.safetycenter {
public static final class SafetySourceIssue.Action.Builder {
ctor public SafetySourceIssue.Action.Builder(@NonNull String, @NonNull CharSequence, @NonNull android.app.PendingIntent);
+ ctor public SafetySourceIssue.Action.Builder(@NonNull android.safetycenter.SafetySourceIssue.Action);
method @NonNull public android.safetycenter.SafetySourceIssue.Action build();
+ method @NonNull public android.safetycenter.SafetySourceIssue.Action.Builder setConfirmationDialogDetails(@Nullable android.safetycenter.SafetySourceIssue.Action.ConfirmationDialogDetails);
method @NonNull public android.safetycenter.SafetySourceIssue.Action.Builder setSuccessMessage(@Nullable CharSequence);
method @NonNull public android.safetycenter.SafetySourceIssue.Action.Builder setWillResolve(boolean);
}
+ public static final class SafetySourceIssue.Action.ConfirmationDialogDetails implements android.os.Parcelable {
+ ctor public SafetySourceIssue.Action.ConfirmationDialogDetails(@NonNull CharSequence, @NonNull CharSequence, @NonNull CharSequence, @NonNull CharSequence);
+ method public int describeContents();
+ method @NonNull public CharSequence getAcceptButtonText();
+ method @NonNull public CharSequence getDenyButtonText();
+ method @NonNull public CharSequence getText();
+ method @NonNull public CharSequence getTitle();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.safetycenter.SafetySourceIssue.Action.ConfirmationDialogDetails> CREATOR;
+ }
+
public static final class SafetySourceIssue.Builder {
ctor public SafetySourceIssue.Builder(@NonNull String, @NonNull CharSequence, @NonNull CharSequence, int, @NonNull String);
+ ctor public SafetySourceIssue.Builder(@NonNull android.safetycenter.SafetySourceIssue);
method @NonNull public android.safetycenter.SafetySourceIssue.Builder addAction(@NonNull android.safetycenter.SafetySourceIssue.Action);
method @NonNull public android.safetycenter.SafetySourceIssue build();
method @NonNull public android.safetycenter.SafetySourceIssue.Builder clearActions();
+ method @NonNull public android.safetycenter.SafetySourceIssue.Builder setAttributionTitle(@Nullable CharSequence);
+ method @NonNull public android.safetycenter.SafetySourceIssue.Builder setCustomNotification(@Nullable android.safetycenter.SafetySourceIssue.Notification);
+ method @NonNull public android.safetycenter.SafetySourceIssue.Builder setDeduplicationId(@Nullable String);
+ method @NonNull public android.safetycenter.SafetySourceIssue.Builder setIssueActionability(int);
method @NonNull public android.safetycenter.SafetySourceIssue.Builder setIssueCategory(int);
+ method @NonNull public android.safetycenter.SafetySourceIssue.Builder setNotificationBehavior(int);
method @NonNull public android.safetycenter.SafetySourceIssue.Builder setOnDismissPendingIntent(@Nullable android.app.PendingIntent);
method @NonNull public android.safetycenter.SafetySourceIssue.Builder setSubtitle(@Nullable CharSequence);
}
+ public static final class SafetySourceIssue.Notification implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.List<android.safetycenter.SafetySourceIssue.Action> getActions();
+ method @NonNull public CharSequence getText();
+ method @NonNull public CharSequence getTitle();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.safetycenter.SafetySourceIssue.Notification> CREATOR;
+ }
+
+ public static final class SafetySourceIssue.Notification.Builder {
+ ctor public SafetySourceIssue.Notification.Builder(@NonNull CharSequence, @NonNull CharSequence);
+ ctor public SafetySourceIssue.Notification.Builder(@NonNull android.safetycenter.SafetySourceIssue.Notification);
+ method @NonNull public android.safetycenter.SafetySourceIssue.Notification.Builder addAction(@NonNull android.safetycenter.SafetySourceIssue.Action);
+ method @NonNull public android.safetycenter.SafetySourceIssue.Notification.Builder addActions(@NonNull java.util.List<android.safetycenter.SafetySourceIssue.Action>);
+ method @NonNull public android.safetycenter.SafetySourceIssue.Notification build();
+ method @NonNull public android.safetycenter.SafetySourceIssue.Notification.Builder clearActions();
+ }
+
public final class SafetySourceStatus implements android.os.Parcelable {
method public int describeContents();
method @Nullable public android.safetycenter.SafetySourceStatus.IconAction getIconAction();
@@ -404,6 +505,7 @@ package android.safetycenter {
public static final class SafetySourceStatus.Builder {
ctor public SafetySourceStatus.Builder(@NonNull CharSequence, @NonNull CharSequence, int);
+ ctor public SafetySourceStatus.Builder(@NonNull android.safetycenter.SafetySourceStatus);
method @NonNull public android.safetycenter.SafetySourceStatus build();
method @NonNull public android.safetycenter.SafetySourceStatus.Builder setEnabled(boolean);
method @NonNull public android.safetycenter.SafetySourceStatus.Builder setIconAction(@Nullable android.safetycenter.SafetySourceStatus.IconAction);
@@ -434,16 +536,21 @@ package android.safetycenter.config {
public static final class SafetyCenterConfig.Builder {
ctor public SafetyCenterConfig.Builder();
+ ctor public SafetyCenterConfig.Builder(@NonNull android.safetycenter.config.SafetyCenterConfig);
method @NonNull public android.safetycenter.config.SafetyCenterConfig.Builder addSafetySourcesGroup(@NonNull android.safetycenter.config.SafetySourcesGroup);
method @NonNull public android.safetycenter.config.SafetyCenterConfig build();
}
public final class SafetySource implements android.os.Parcelable {
+ method public boolean areNotificationsAllowed();
method public int describeContents();
+ method @Nullable public String getDeduplicationGroup();
method @NonNull public String getId();
method public int getInitialDisplayState();
method @Nullable public String getIntentAction();
method public int getMaxSeverityLevel();
+ method @Nullable public String getOptionalPackageName();
+ method @NonNull public java.util.Set<java.lang.String> getPackageCertificateHashes();
method @NonNull public String getPackageName();
method public int getProfile();
method @StringRes public int getSearchTermsResId();
@@ -468,12 +575,16 @@ package android.safetycenter.config {
public static final class SafetySource.Builder {
ctor public SafetySource.Builder(int);
+ ctor public SafetySource.Builder(@NonNull android.safetycenter.config.SafetySource);
+ method @NonNull public android.safetycenter.config.SafetySource.Builder addPackageCertificateHash(@NonNull String);
method @NonNull public android.safetycenter.config.SafetySource build();
+ method @NonNull public android.safetycenter.config.SafetySource.Builder setDeduplicationGroup(@Nullable String);
method @NonNull public android.safetycenter.config.SafetySource.Builder setId(@Nullable String);
method @NonNull public android.safetycenter.config.SafetySource.Builder setInitialDisplayState(int);
method @NonNull public android.safetycenter.config.SafetySource.Builder setIntentAction(@Nullable String);
method @NonNull public android.safetycenter.config.SafetySource.Builder setLoggingAllowed(boolean);
method @NonNull public android.safetycenter.config.SafetySource.Builder setMaxSeverityLevel(int);
+ method @NonNull public android.safetycenter.config.SafetySource.Builder setNotificationsAllowed(boolean);
method @NonNull public android.safetycenter.config.SafetySource.Builder setPackageName(@Nullable String);
method @NonNull public android.safetycenter.config.SafetySource.Builder setProfile(int);
method @NonNull public android.safetycenter.config.SafetySource.Builder setRefreshOnPageOpenAllowed(boolean);
@@ -493,21 +604,34 @@ package android.safetycenter.config {
method public int getType();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.safetycenter.config.SafetySourcesGroup> CREATOR;
- field public static final int SAFETY_SOURCES_GROUP_TYPE_COLLAPSIBLE = 0; // 0x0
+ field @Deprecated public static final int SAFETY_SOURCES_GROUP_TYPE_COLLAPSIBLE = 0; // 0x0
field public static final int SAFETY_SOURCES_GROUP_TYPE_HIDDEN = 2; // 0x2
- field public static final int SAFETY_SOURCES_GROUP_TYPE_RIGID = 1; // 0x1
+ field @Deprecated public static final int SAFETY_SOURCES_GROUP_TYPE_RIGID = 1; // 0x1
+ field public static final int SAFETY_SOURCES_GROUP_TYPE_STATEFUL = 0; // 0x0
+ field public static final int SAFETY_SOURCES_GROUP_TYPE_STATELESS = 1; // 0x1
field public static final int STATELESS_ICON_TYPE_NONE = 0; // 0x0
field public static final int STATELESS_ICON_TYPE_PRIVACY = 1; // 0x1
}
public static final class SafetySourcesGroup.Builder {
ctor public SafetySourcesGroup.Builder();
+ ctor public SafetySourcesGroup.Builder(@NonNull android.safetycenter.config.SafetySourcesGroup);
method @NonNull public android.safetycenter.config.SafetySourcesGroup.Builder addSafetySource(@NonNull android.safetycenter.config.SafetySource);
method @NonNull public android.safetycenter.config.SafetySourcesGroup build();
method @NonNull public android.safetycenter.config.SafetySourcesGroup.Builder setId(@Nullable String);
method @NonNull public android.safetycenter.config.SafetySourcesGroup.Builder setStatelessIconType(int);
method @NonNull public android.safetycenter.config.SafetySourcesGroup.Builder setSummaryResId(@StringRes int);
method @NonNull public android.safetycenter.config.SafetySourcesGroup.Builder setTitleResId(@StringRes int);
+ method @NonNull public android.safetycenter.config.SafetySourcesGroup.Builder setType(int);
+ }
+
+}
+
+package android.safetylabel {
+
+ public final class SafetyLabelConstants {
+ field public static final String PERMISSION_RATIONALE_ENABLED = "permission_rationale_enabled";
+ field public static final String SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED = "safety_label_change_notifications_enabled";
}
}
diff --git a/framework-s/jarjar-rules.txt b/framework-s/jarjar-rules.txt
new file mode 100644
index 000000000..3b888fe99
--- /dev/null
+++ b/framework-s/jarjar-rules.txt
@@ -0,0 +1,4 @@
+rule android.os.HandlerExecutor 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/role/IRoleManager.aidl b/framework-s/java/android/app/role/IRoleManager.aidl
index 5217c12ff..5f7cb1bf5 100644
--- a/framework-s/java/android/app/role/IRoleManager.aidl
+++ b/framework-s/java/android/app/role/IRoleManager.aidl
@@ -40,6 +40,11 @@ interface IRoleManager {
void clearRoleHoldersAsUser(in String roleName, int flags, int userId,
in RemoteCallback callback);
+ String getDefaultApplicationAsUser(in String roleName, int userId);
+
+ void setDefaultApplicationAsUser(in String roleName, in String packageName, int flags,
+ int userId, in RemoteCallback callback);
+
void addOnRoleHoldersChangedListenerAsUser(IOnRoleHoldersChangedListener listener, int userId);
void removeOnRoleHoldersChangedListenerAsUser(IOnRoleHoldersChangedListener listener,
diff --git a/framework-s/java/android/app/role/RoleManager.java b/framework-s/java/android/app/role/RoleManager.java
index bd8831070..de697f801 100644
--- a/framework-s/java/android/app/role/RoleManager.java
+++ b/framework-s/java/android/app/role/RoleManager.java
@@ -25,6 +25,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.UserHandleAware;
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.Intent;
@@ -129,6 +130,14 @@ public final class RoleManager {
public static final String ROLE_CALL_SCREENING = "android.app.role.CALL_SCREENING";
/**
+ * The name of the notes role.
+ *
+ * @see Intent#ACTION_CREATE_NOTE
+ * @see Intent#EXTRA_USE_STYLUS_MODE
+ */
+ public static final String ROLE_NOTES = "android.app.role.NOTES";
+
+ /**
* The name of the system wellbeing role.
*
* @hide
@@ -163,6 +172,28 @@ public final class RoleManager {
"android.app.role.DEVICE_POLICY_MANAGEMENT";
/**
+ * The name of the financed device kiosk role.
+ *
+ * A financed device is a device purchased through a creditor and typically paid back under an
+ * installment plan.
+ * The creditor has the ability to lock a financed device in case of payment default.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String ROLE_FINANCED_DEVICE_KIOSK =
+ "android.app.role.FINANCED_DEVICE_KIOSK";
+
+ /**
+ * The name of the system call streaming role.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String ROLE_SYSTEM_CALL_STREAMING =
+ "android.app.role.SYSTEM_CALL_STREAMING";
+
+ /**
* @hide
*/
@IntDef(flag = true, value = { MANAGE_HOLDERS_FLAG_DONT_KILL_APP })
@@ -443,6 +474,71 @@ public final class RoleManager {
}
}
+ /**
+ * Get package names of the applications holding the role for a default application.
+ * <p>
+ * <strong>Note:</strong> Using this API requires holding
+ * {@code android.permission.MANAGE_DEFAULT_APPLICATIONS}.
+ *
+ * @param roleName the name of the default application role to get
+ *
+ * @return a package name of the role holder or {@code null} if not set.
+ *
+ * @see #setDefaultApplication(String, String, int, Executor, Consumer)
+ *
+ * @hide
+ */
+ @Nullable
+ @RequiresPermission(Manifest.permission.MANAGE_DEFAULT_APPLICATIONS)
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @UserHandleAware
+ @SystemApi
+ public String getDefaultApplication(@NonNull String roleName) {
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ try {
+ return mService.getDefaultApplicationAsUser(
+ roleName, mContext.getUser().getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Set a specific application as the default application.
+ * <p>
+ * <strong>Note:</strong> Using this API requires holding
+ * {@code android.permission.MANAGE_DEFAULT_APPLICATIONS}.
+ *
+ * @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,
+ * or {@code null} to unset.
+ * @param flags optional behavior flags
+ * @param executor the {@code Executor} to run the callback on.
+ * @param callback the callback for whether this call is successful
+ *
+ * @see #getDefaultApplication(String)
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_DEFAULT_APPLICATIONS)
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @UserHandleAware
+ @SystemApi
+ public void setDefaultApplication(@NonNull String roleName, @Nullable String packageName,
+ @ManageHoldersFlags int flags, @CallbackExecutor @NonNull Executor executor,
+ @NonNull Consumer<Boolean> callback) {
+ 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 {
+ mService.setDefaultApplicationAsUser(roleName, packageName, flags,
+ mContext.getUser().getIdentifier(), createRemoteCallback(executor, callback));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
@NonNull
private static RemoteCallback createRemoteCallback(@NonNull Executor executor,
@NonNull Consumer<Boolean> callback) {
diff --git a/framework-s/java/android/app/role/TEST_MAPPING b/framework-s/java/android/app/role/TEST_MAPPING
index f8f140dd7..ce53dca05 100644
--- a/framework-s/java/android/app/role/TEST_MAPPING
+++ b/framework-s/java/android/app/role/TEST_MAPPING
@@ -4,7 +4,24 @@
"name": "CtsRoleTestCases",
"options": [
{
- "include-filter": "android.app.role.cts.RoleManagerTest"
+ "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"
}
]
}
diff --git a/framework-s/java/android/safetycenter/ISafetyCenterManager.aidl b/framework-s/java/android/safetycenter/ISafetyCenterManager.aidl
index 9805090be..3290c221b 100644
--- a/framework-s/java/android/safetycenter/ISafetyCenterManager.aidl
+++ b/framework-s/java/android/safetycenter/ISafetyCenterManager.aidl
@@ -22,6 +22,7 @@ import android.safetycenter.SafetyEvent;
import android.safetycenter.SafetySourceData;
import android.safetycenter.SafetySourceErrorDetails;
import android.safetycenter.config.SafetyCenterConfig;
+import java.util.List;
/**
* AIDL Interface for communicating with the Safety Center, which consolidates UI for security and
@@ -72,16 +73,23 @@ interface ISafetyCenterManager {
/** Requests safety sources to set their latest SafetySourceData for Safety Center. */
void refreshSafetySources(int refreshReason, int userId);
+ /**
+ * Requests a specific subset of safety sources to set their latest SafetySourceData for
+ * Safety Center.
+ */
+ void refreshSpecificSafetySources(int refreshReason, int userId, in List<String> safetySourceIds);
+
/** Returns the current SafetyCenterConfig, if available. */
SafetyCenterConfig getSafetyCenterConfig();
/**
* Returns the current SafetyCenterData, assembled from the SafetySourceData from all sources.
*/
- SafetyCenterData getSafetyCenterData(int userId);
+ SafetyCenterData getSafetyCenterData(String packageName, int userId);
void addOnSafetyCenterDataChangedListener(
IOnSafetyCenterDataChangedListener listener,
+ String packageName,
int userId);
void removeOnSafetyCenterDataChangedListener(
@@ -89,8 +97,7 @@ interface ISafetyCenterManager {
int userId);
/**
- * Dismiss a Safety Center issue and prevent it from appearing in the Safety Center or affecting
- * the overall safety status.
+ * Dismiss a Safety Center issue and prevent it affecting the overall safety status.
*/
void dismissSafetyCenterIssue(String issueId, int userId);
diff --git a/framework-s/java/android/safetycenter/SafetyCenterData.java b/framework-s/java/android/safetycenter/SafetyCenterData.java
index 9a6e7f0ec..720fb4997 100644
--- a/framework-s/java/android/safetycenter/SafetyCenterData.java
+++ b/framework-s/java/android/safetycenter/SafetyCenterData.java
@@ -17,20 +17,26 @@
package android.safetycenter;
import static android.os.Build.VERSION_CODES.TIRAMISU;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static java.util.Collections.unmodifiableList;
import static java.util.Objects.requireNonNull;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.RequiresApi;
+import com.android.modules.utils.build.SdkLevel;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
/**
* A representation of the safety state of the device.
@@ -41,6 +47,21 @@ import java.util.Objects;
@RequiresApi(TIRAMISU)
public final class SafetyCenterData implements Parcelable {
+ /**
+ * A key used in {@link #getExtras()} to map {@link SafetyCenterIssue} ids to their associated
+ * {@link SafetyCenterEntryGroup} ids.
+ */
+ private static final String ISSUES_TO_GROUPS_BUNDLE_KEY = "IssuesToGroups";
+
+ /**
+ * A key used in {@link #getExtras()} to map {@link SafetyCenterStaticEntry} to their associated
+ * ids.
+ *
+ * <p>{@link SafetyCenterStaticEntry} are keyed by {@code
+ * SafetyCenterIds.toBundleKey(safetyCenterStaticEntry)}.
+ */
+ private static final String STATIC_ENTRIES_TO_IDS_BUNDLE_KEY = "StaticEntriesToIds";
+
@NonNull
public static final Creator<SafetyCenterData> CREATOR =
new Creator<SafetyCenterData>() {
@@ -53,7 +74,32 @@ public final class SafetyCenterData implements Parcelable {
in.createTypedArrayList(SafetyCenterEntryOrGroup.CREATOR);
List<SafetyCenterStaticEntryGroup> staticEntryGroups =
in.createTypedArrayList(SafetyCenterStaticEntryGroup.CREATOR);
- return new SafetyCenterData(status, issues, entryOrGroups, staticEntryGroups);
+
+ if (SdkLevel.isAtLeastU()) {
+ List<SafetyCenterIssue> dismissedIssues =
+ in.createTypedArrayList(SafetyCenterIssue.CREATOR);
+ Bundle extras = in.readBundle(getClass().getClassLoader());
+ SafetyCenterData.Builder builder = new SafetyCenterData.Builder(status);
+ for (int i = 0; i < issues.size(); i++) {
+ builder.addIssue(issues.get(i));
+ }
+ for (int i = 0; i < entryOrGroups.size(); i++) {
+ builder.addEntryOrGroup(entryOrGroups.get(i));
+ }
+ for (int i = 0; i < staticEntryGroups.size(); i++) {
+ builder.addStaticEntryGroup(staticEntryGroups.get(i));
+ }
+ for (int i = 0; i < dismissedIssues.size(); i++) {
+ builder.addDismissedIssue(dismissedIssues.get(i));
+ }
+ if (extras != null) {
+ builder.setExtras(extras);
+ }
+ return builder.build();
+ } else {
+ return new SafetyCenterData(
+ status, issues, entryOrGroups, staticEntryGroups);
+ }
}
@Override
@@ -66,6 +112,8 @@ public final class SafetyCenterData implements Parcelable {
@NonNull private final List<SafetyCenterIssue> mIssues;
@NonNull private final List<SafetyCenterEntryOrGroup> mEntriesOrGroups;
@NonNull private final List<SafetyCenterStaticEntryGroup> mStaticEntryGroups;
+ @NonNull private final List<SafetyCenterIssue> mDismissedIssues;
+ @NonNull private final Bundle mExtras;
/** Creates a {@link SafetyCenterData}. */
public SafetyCenterData(
@@ -77,6 +125,23 @@ public final class SafetyCenterData implements Parcelable {
mIssues = unmodifiableList(new ArrayList<>(requireNonNull(issues)));
mEntriesOrGroups = unmodifiableList(new ArrayList<>(requireNonNull(entriesOrGroups)));
mStaticEntryGroups = unmodifiableList(new ArrayList<>(requireNonNull(staticEntryGroups)));
+ mDismissedIssues = unmodifiableList(new ArrayList<>());
+ mExtras = Bundle.EMPTY;
+ }
+
+ private SafetyCenterData(
+ @NonNull SafetyCenterStatus status,
+ @NonNull List<SafetyCenterIssue> issues,
+ @NonNull List<SafetyCenterEntryOrGroup> entriesOrGroups,
+ @NonNull List<SafetyCenterStaticEntryGroup> staticEntryGroups,
+ @NonNull List<SafetyCenterIssue> dismissedIssues,
+ @NonNull Bundle extras) {
+ mStatus = status;
+ mIssues = issues;
+ mEntriesOrGroups = entriesOrGroups;
+ mStaticEntryGroups = staticEntryGroups;
+ mDismissedIssues = dismissedIssues;
+ mExtras = extras;
}
/** Returns the overall {@link SafetyCenterStatus} of the Safety Center. */
@@ -106,6 +171,31 @@ public final class SafetyCenterData implements Parcelable {
return mStaticEntryGroups;
}
+ /** Returns the list of dismissed {@link SafetyCenterIssue} objects in the Safety Center. */
+ @NonNull
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public List<SafetyCenterIssue> getDismissedIssues() {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ return mDismissedIssues;
+ }
+
+ /**
+ * Returns a {@link Bundle} containing additional information, {@link Bundle#EMPTY} by default.
+ *
+ * <p>Note: internal state of this {@link Bundle} is not used for {@link Object#equals} and
+ * {@link Object#hashCode} implementation of {@link SafetyCenterData}.
+ */
+ @NonNull
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Bundle getExtras() {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ return mExtras;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -114,12 +204,80 @@ public final class SafetyCenterData implements Parcelable {
return Objects.equals(mStatus, that.mStatus)
&& Objects.equals(mIssues, that.mIssues)
&& Objects.equals(mEntriesOrGroups, that.mEntriesOrGroups)
- && Objects.equals(mStaticEntryGroups, that.mStaticEntryGroups);
+ && Objects.equals(mStaticEntryGroups, that.mStaticEntryGroups)
+ && Objects.equals(mDismissedIssues, that.mDismissedIssues)
+ && areKnownExtrasContentsEqual(mExtras, that.mExtras);
+ }
+
+ /** We're only comparing the bundle data that we know of. */
+ private static boolean areKnownExtrasContentsEqual(
+ @NonNull Bundle left, @NonNull Bundle right) {
+ return areBundlesEqual(left, right, ISSUES_TO_GROUPS_BUNDLE_KEY)
+ && areBundlesEqual(left, right, STATIC_ENTRIES_TO_IDS_BUNDLE_KEY);
+ }
+
+ private static boolean areBundlesEqual(
+ @NonNull Bundle left, @NonNull Bundle right, @NonNull String bundleKey) {
+ Bundle leftBundle = left.getBundle(bundleKey);
+ Bundle rightBundle = right.getBundle(bundleKey);
+
+ if (leftBundle == null && rightBundle == null) {
+ return true;
+ }
+
+ if (leftBundle == null || rightBundle == null) {
+ return false;
+ }
+
+ Set<String> leftKeys = leftBundle.keySet();
+ Set<String> rightKeys = rightBundle.keySet();
+
+ if (!Objects.equals(leftKeys, rightKeys)) {
+ return false;
+ }
+
+ for (String key : leftKeys) {
+ if (!Objects.equals(
+ getBundleValue(leftBundle, bundleKey, key),
+ getBundleValue(rightBundle, bundleKey, key))) {
+ return false;
+ }
+ }
+
+ return true;
}
@Override
public int hashCode() {
- return Objects.hash(mStatus, mIssues, mEntriesOrGroups, mStaticEntryGroups);
+ return Objects.hash(
+ mStatus,
+ mIssues,
+ mEntriesOrGroups,
+ mStaticEntryGroups,
+ mDismissedIssues,
+ getExtrasHash());
+ }
+
+ /** We're only hashing bundle data that we know of. */
+ private int getExtrasHash() {
+ return Objects.hash(
+ bundleHash(ISSUES_TO_GROUPS_BUNDLE_KEY),
+ bundleHash(STATIC_ENTRIES_TO_IDS_BUNDLE_KEY));
+ }
+
+ private int bundleHash(@NonNull String bundleKey) {
+ Bundle bundle = mExtras.getBundle(bundleKey);
+ if (bundle == null) {
+ return 0;
+ }
+
+ int hash = 0;
+ for (String key : bundle.keySet()) {
+ hash +=
+ Objects.hashCode(key)
+ ^ Objects.hashCode(getBundleValue(bundle, bundleKey, key));
+ }
+ return hash;
}
@Override
@@ -133,9 +291,53 @@ public final class SafetyCenterData implements Parcelable {
+ mEntriesOrGroups
+ ", mStaticEntryGroups="
+ mStaticEntryGroups
+ + ", mDismissedIssues="
+ + mDismissedIssues
+ + ", mExtras="
+ + extrasToString()
+ '}';
}
+ /** We're only including bundle data that we know of. */
+ @NonNull
+ private String extrasToString() {
+ int knownExtras = 0;
+ StringBuilder sb = new StringBuilder();
+ if (appendBundleString(sb, ISSUES_TO_GROUPS_BUNDLE_KEY)) {
+ knownExtras++;
+ }
+ if (appendBundleString(sb, STATIC_ENTRIES_TO_IDS_BUNDLE_KEY)) {
+ knownExtras++;
+ }
+
+ boolean hasUnknownExtras = knownExtras != mExtras.keySet().size();
+ if (hasUnknownExtras) {
+ sb.append("(has unknown extras)");
+ } else if (knownExtras == 0) {
+ sb.append("(no extras)");
+ }
+
+ return sb.toString();
+ }
+
+ private boolean appendBundleString(@NonNull StringBuilder sb, @NonNull String bundleKey) {
+ Bundle bundle = mExtras.getBundle(bundleKey);
+ if (bundle == null) {
+ return false;
+ }
+ sb.append(bundleKey);
+ sb.append(":[");
+ for (String key : bundle.keySet()) {
+ sb.append("(key=")
+ .append(key)
+ .append(";value=")
+ .append(getBundleValue(bundle, bundleKey, key))
+ .append(")");
+ }
+ sb.append("]");
+ return true;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -147,5 +349,168 @@ public final class SafetyCenterData implements Parcelable {
dest.writeTypedList(mIssues);
dest.writeTypedList(mEntriesOrGroups);
dest.writeTypedList(mStaticEntryGroups);
+ if (SdkLevel.isAtLeastU()) {
+ dest.writeTypedList(mDismissedIssues);
+ dest.writeBundle(mExtras);
+ }
+ }
+
+ /** Builder class for {@link SafetyCenterData}. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static final class Builder {
+
+ @NonNull private final SafetyCenterStatus mStatus;
+ @NonNull private final List<SafetyCenterIssue> mIssues = new ArrayList<>();
+ @NonNull private final List<SafetyCenterEntryOrGroup> mEntriesOrGroups = new ArrayList<>();
+
+ @NonNull
+ private final List<SafetyCenterStaticEntryGroup> mStaticEntryGroups = new ArrayList<>();
+
+ @NonNull private final List<SafetyCenterIssue> mDismissedIssues = new ArrayList<>();
+ @NonNull private Bundle mExtras = Bundle.EMPTY;
+
+ public Builder(@NonNull SafetyCenterStatus status) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ mStatus = requireNonNull(status);
+ }
+
+ /** Creates a {@link Builder} with the values from the given {@link SafetyCenterData}. */
+ public Builder(@NonNull SafetyCenterData safetyCenterData) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ requireNonNull(safetyCenterData);
+ mStatus = safetyCenterData.mStatus;
+ mIssues.addAll(safetyCenterData.mIssues);
+ mEntriesOrGroups.addAll(safetyCenterData.mEntriesOrGroups);
+ mStaticEntryGroups.addAll(safetyCenterData.mStaticEntryGroups);
+ mDismissedIssues.addAll(safetyCenterData.mDismissedIssues);
+ mExtras = safetyCenterData.mExtras.deepCopy();
+ }
+
+ /** Adds data for a {@link SafetyCenterIssue} to be shown in UI. */
+ @NonNull
+ public SafetyCenterData.Builder addIssue(@NonNull SafetyCenterIssue safetyCenterIssue) {
+ mIssues.add(requireNonNull(safetyCenterIssue));
+ return this;
+ }
+
+ /** Adds data for a {@link SafetyCenterEntryOrGroup} to be shown in UI. */
+ @NonNull
+ @SuppressWarnings("MissingGetterMatchingBuilder") // incorrectly expects "getEntryOrGroups"
+ public SafetyCenterData.Builder addEntryOrGroup(
+ @NonNull SafetyCenterEntryOrGroup safetyCenterEntryOrGroup) {
+ mEntriesOrGroups.add(requireNonNull(safetyCenterEntryOrGroup));
+ return this;
+ }
+
+ /** Adds data for a {@link SafetyCenterStaticEntryGroup} to be shown in UI. */
+ @NonNull
+ public SafetyCenterData.Builder addStaticEntryGroup(
+ @NonNull SafetyCenterStaticEntryGroup safetyCenterStaticEntryGroup) {
+ mStaticEntryGroups.add(requireNonNull(safetyCenterStaticEntryGroup));
+ return this;
+ }
+
+ /** Adds data for a dismissed {@link SafetyCenterIssue} to be shown in UI. */
+ @NonNull
+ public SafetyCenterData.Builder addDismissedIssue(
+ @NonNull SafetyCenterIssue dismissedSafetyCenterIssue) {
+ mDismissedIssues.add(requireNonNull(dismissedSafetyCenterIssue));
+ return this;
+ }
+
+ /**
+ * Sets additional information for the {@link SafetyCenterData}.
+ *
+ * <p>If not set, the default value is {@link Bundle#EMPTY}.
+ */
+ @NonNull
+ public SafetyCenterData.Builder setExtras(@NonNull Bundle extras) {
+ mExtras = requireNonNull(extras);
+ return this;
+ }
+
+ /**
+ * Resets additional information for the {@link SafetyCenterData} to the default value of
+ * {@link Bundle#EMPTY}.
+ */
+ @NonNull
+ public SafetyCenterData.Builder clearExtras() {
+ mExtras = Bundle.EMPTY;
+ return this;
+ }
+
+ /**
+ * Clears data for all the {@link SafetyCenterIssue}s that were added to this {@link
+ * SafetyCenterData.Builder}.
+ */
+ @NonNull
+ public SafetyCenterData.Builder clearIssues() {
+ mIssues.clear();
+ return this;
+ }
+
+ /**
+ * Clears data for all the {@link SafetyCenterEntryOrGroup}s that were added to this {@link
+ * SafetyCenterData.Builder}.
+ */
+ @NonNull
+ public SafetyCenterData.Builder clearEntriesOrGroups() {
+ mEntriesOrGroups.clear();
+ return this;
+ }
+
+ /**
+ * Clears data for all the {@link SafetyCenterStaticEntryGroup}s that were added to this
+ * {@link SafetyCenterData.Builder}.
+ */
+ @NonNull
+ public SafetyCenterData.Builder clearStaticEntryGroups() {
+ mStaticEntryGroups.clear();
+ return this;
+ }
+
+ /**
+ * Clears data for all the dismissed {@link SafetyCenterIssue}s that were added to this
+ * {@link SafetyCenterData.Builder}.
+ */
+ @NonNull
+ public SafetyCenterData.Builder clearDismissedIssues() {
+ mDismissedIssues.clear();
+ return this;
+ }
+
+ /**
+ * Creates the {@link SafetyCenterData} defined by this {@link SafetyCenterData.Builder}.
+ */
+ @NonNull
+ public SafetyCenterData build() {
+ List<SafetyCenterIssue> issues = unmodifiableList(new ArrayList<>(mIssues));
+ List<SafetyCenterEntryOrGroup> entriesOrGroups =
+ unmodifiableList(new ArrayList<>(mEntriesOrGroups));
+ List<SafetyCenterStaticEntryGroup> staticEntryGroups =
+ unmodifiableList(new ArrayList<>(mStaticEntryGroups));
+ List<SafetyCenterIssue> dismissedIssues =
+ unmodifiableList(new ArrayList<>(mDismissedIssues));
+
+ return new SafetyCenterData(
+ mStatus, issues, entriesOrGroups, staticEntryGroups, dismissedIssues, mExtras);
+ }
+ }
+
+ @Nullable
+ private static Object getBundleValue(
+ @NonNull Bundle bundle, @NonNull String bundleParentKey, @NonNull String key) {
+ switch (bundleParentKey) {
+ case ISSUES_TO_GROUPS_BUNDLE_KEY:
+ return bundle.getStringArrayList(key);
+ case STATIC_ENTRIES_TO_IDS_BUNDLE_KEY:
+ return bundle.getString(key);
+ default:
+ }
+ throw new IllegalArgumentException("Unexpected bundle parent key: " + bundleParentKey);
}
}
diff --git a/framework-s/java/android/safetycenter/SafetyCenterEntry.java b/framework-s/java/android/safetycenter/SafetyCenterEntry.java
index 690d4a1ac..c7939be79 100644
--- a/framework-s/java/android/safetycenter/SafetyCenterEntry.java
+++ b/framework-s/java/android/safetycenter/SafetyCenterEntry.java
@@ -265,9 +265,8 @@ public final class SafetyCenterEntry implements Parcelable {
@Override
public String toString() {
return "SafetyCenterEntry{"
- + "mId='"
+ + "mId="
+ mId
- + '\''
+ ", mTitle="
+ mTitle
+ ", mSummary="
@@ -528,7 +527,7 @@ public final class SafetyCenterEntry implements Parcelable {
default:
}
throw new IllegalArgumentException(
- String.format("Unexpected IconActionType for IconAction: %s", value));
+ "Unexpected IconActionType for IconAction: " + value);
}
}
@@ -544,7 +543,7 @@ public final class SafetyCenterEntry implements Parcelable {
default:
}
throw new IllegalArgumentException(
- String.format("Unexpected EntrySeverityLevel for SafetyCenterEntry: %s", value));
+ "Unexpected EntrySeverityLevel for SafetyCenterEntry: " + value);
}
@SeverityUnspecifiedIconType
@@ -557,7 +556,6 @@ public final class SafetyCenterEntry implements Parcelable {
default:
}
throw new IllegalArgumentException(
- String.format(
- "Unexpected SeverityUnspecifiedIconType for SafetyCenterEntry: %s", value));
+ "Unexpected SeverityUnspecifiedIconType for SafetyCenterEntry: " + value);
}
}
diff --git a/framework-s/java/android/safetycenter/SafetyCenterEntryGroup.java b/framework-s/java/android/safetycenter/SafetyCenterEntryGroup.java
index 47c84b723..20d0260f0 100644
--- a/framework-s/java/android/safetycenter/SafetyCenterEntryGroup.java
+++ b/framework-s/java/android/safetycenter/SafetyCenterEntryGroup.java
@@ -26,6 +26,7 @@ import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.safetycenter.config.SafetySourcesGroup;
import android.text.TextUtils;
import androidx.annotation.RequiresApi;
@@ -86,10 +87,7 @@ public final class SafetyCenterEntryGroup implements Parcelable {
mEntries = entries;
}
- /**
- * Returns the encoded string ID which uniquely identifies this entry group within the Safety
- * Center on the device for the current user across all profiles and accounts.
- */
+ /** Returns the ID of the {@link SafetySourcesGroup} that this group corresponds to. */
@NonNull
public String getId() {
return mId;
@@ -149,9 +147,8 @@ public final class SafetyCenterEntryGroup implements Parcelable {
@Override
public String toString() {
return "SafetyCenterEntryGroup{"
- + "mId='"
+ + "mId="
+ mId
- + '\''
+ ", mTitle="
+ mTitle
+ ", mSummary="
@@ -297,8 +294,7 @@ public final class SafetyCenterEntryGroup implements Parcelable {
default:
}
throw new IllegalArgumentException(
- String.format(
- "Unexpected EntrySeverityLevel for SafetyCenterEntryGroup: %s", value));
+ "Unexpected EntrySeverityLevel for SafetyCenterEntryGroup: " + value);
}
@SafetyCenterEntry.SeverityUnspecifiedIconType
@@ -311,8 +307,6 @@ public final class SafetyCenterEntryGroup implements Parcelable {
default:
}
throw new IllegalArgumentException(
- String.format(
- "Unexpected SeverityUnspecifiedIconType for SafetyCenterEntryGroup: %s",
- value));
+ "Unexpected SeverityUnspecifiedIconType for SafetyCenterEntryGroup: " + value);
}
}
diff --git a/framework-s/java/android/safetycenter/SafetyCenterIssue.java b/framework-s/java/android/safetycenter/SafetyCenterIssue.java
index e772ee905..cee872a3a 100644
--- a/framework-s/java/android/safetycenter/SafetyCenterIssue.java
+++ b/framework-s/java/android/safetycenter/SafetyCenterIssue.java
@@ -17,6 +17,7 @@
package android.safetycenter;
import static android.os.Build.VERSION_CODES.TIRAMISU;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static java.util.Collections.unmodifiableList;
import static java.util.Objects.requireNonNull;
@@ -29,10 +30,13 @@ import android.annotation.SystemApi;
import android.app.PendingIntent;
import android.os.Parcel;
import android.os.Parcelable;
+import android.safetycenter.config.SafetySourcesGroup;
import android.text.TextUtils;
import androidx.annotation.RequiresApi;
+import com.android.modules.utils.build.SdkLevel;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -91,13 +95,19 @@ public final class SafetyCenterIssue implements Parcelable {
CharSequence title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
CharSequence subtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
CharSequence summary = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- return new Builder(id, title, summary)
- .setSubtitle(subtitle)
- .setSeverityLevel(in.readInt())
- .setDismissible(in.readBoolean())
- .setShouldConfirmDismissal(in.readBoolean())
- .setActions(in.createTypedArrayList(Action.CREATOR))
- .build();
+ SafetyCenterIssue.Builder builder =
+ new Builder(id, title, summary)
+ .setSubtitle(subtitle)
+ .setSeverityLevel(in.readInt())
+ .setDismissible(in.readBoolean())
+ .setShouldConfirmDismissal(in.readBoolean())
+ .setActions(in.createTypedArrayList(Action.CREATOR));
+ if (SdkLevel.isAtLeastU()) {
+ builder.setAttributionTitle(
+ TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in));
+ builder.setGroupId(in.readString());
+ }
+ return builder.build();
}
@Override
@@ -114,6 +124,8 @@ public final class SafetyCenterIssue implements Parcelable {
private final boolean mDismissible;
private final boolean mShouldConfirmDismissal;
@NonNull private final List<Action> mActions;
+ @Nullable private final CharSequence mAttributionTitle;
+ @Nullable private final String mGroupId;
private SafetyCenterIssue(
@NonNull String id,
@@ -123,7 +135,9 @@ public final class SafetyCenterIssue implements Parcelable {
@IssueSeverityLevel int severityLevel,
boolean isDismissible,
boolean shouldConfirmDismissal,
- @NonNull List<Action> actions) {
+ @NonNull List<Action> actions,
+ @Nullable CharSequence attributionTitle,
+ @Nullable String groupId) {
mId = id;
mTitle = title;
mSubtitle = subtitle;
@@ -132,6 +146,8 @@ public final class SafetyCenterIssue implements Parcelable {
mDismissible = isDismissible;
mShouldConfirmDismissal = shouldConfirmDismissal;
mActions = actions;
+ mAttributionTitle = attributionTitle;
+ mGroupId = groupId;
}
/**
@@ -161,6 +177,24 @@ public final class SafetyCenterIssue implements Parcelable {
return mSummary;
}
+ /**
+ * Returns the attribution title of this issue, or {@code null} if it has none.
+ *
+ * <p>This is displayed in the UI and helps to attribute issue cards to a particular source.
+ *
+ * @throws UnsupportedOperationException if accessed from a version lower than {@link
+ * UPSIDE_DOWN_CAKE}
+ */
+ @Nullable
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public CharSequence getAttributionTitle() {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException(
+ "Method not supported for versions lower than UPSIDE_DOWN_CAKE");
+ }
+ return mAttributionTitle;
+ }
+
/** Returns the {@link IssueSeverityLevel} of this issue. */
@IssueSeverityLevel
public int getSeverityLevel() {
@@ -188,6 +222,26 @@ public final class SafetyCenterIssue implements Parcelable {
return mActions;
}
+ /**
+ * Returns the ID of the {@link SafetySourcesGroup} that this issue belongs to, or {@code null}
+ * if it has none.
+ *
+ * <p>This ID is used for displaying the issue on its corresponding subpage in the Safety Center
+ * UI.
+ *
+ * @throws UnsupportedOperationException if accessed from a version lower than {@link
+ * UPSIDE_DOWN_CAKE}
+ */
+ @Nullable
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public String getGroupId() {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException(
+ "Method not supported for versions lower than UPSIDE_DOWN_CAKE");
+ }
+ return mGroupId;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -200,7 +254,9 @@ public final class SafetyCenterIssue implements Parcelable {
&& TextUtils.equals(mTitle, that.mTitle)
&& TextUtils.equals(mSubtitle, that.mSubtitle)
&& TextUtils.equals(mSummary, that.mSummary)
- && Objects.equals(mActions, that.mActions);
+ && Objects.equals(mActions, that.mActions)
+ && TextUtils.equals(mAttributionTitle, that.mAttributionTitle)
+ && Objects.equals(mGroupId, that.mGroupId);
}
@Override
@@ -213,15 +269,16 @@ public final class SafetyCenterIssue implements Parcelable {
mSeverityLevel,
mDismissible,
mShouldConfirmDismissal,
- mActions);
+ mActions,
+ mAttributionTitle,
+ mGroupId);
}
@Override
public String toString() {
return "SafetyCenterIssue{"
- + "mId='"
+ + "mId="
+ mId
- + '\''
+ ", mTitle="
+ mTitle
+ ", mSubtitle="
@@ -236,6 +293,10 @@ public final class SafetyCenterIssue implements Parcelable {
+ mShouldConfirmDismissal
+ ", mActions="
+ mActions
+ + ", mAttributionTitle="
+ + mAttributionTitle
+ + ", mGroupId="
+ + mGroupId
+ '}';
}
@@ -254,6 +315,10 @@ public final class SafetyCenterIssue implements Parcelable {
dest.writeBoolean(mDismissible);
dest.writeBoolean(mShouldConfirmDismissal);
dest.writeTypedList(mActions);
+ if (SdkLevel.isAtLeastU()) {
+ TextUtils.writeToParcel(mAttributionTitle, dest, flags);
+ dest.writeString(mGroupId);
+ }
}
/** Builder class for {@link SafetyCenterIssue}. */
@@ -267,6 +332,8 @@ public final class SafetyCenterIssue implements Parcelable {
private boolean mDismissible = true;
private boolean mShouldConfirmDismissal = true;
private List<Action> mActions = new ArrayList<>();
+ @Nullable private CharSequence mAttributionTitle;
+ @Nullable private String mGroupId;
/**
* Creates a {@link Builder} for a {@link SafetyCenterIssue}.
@@ -292,6 +359,8 @@ public final class SafetyCenterIssue implements Parcelable {
mDismissible = issue.mDismissible;
mShouldConfirmDismissal = issue.mShouldConfirmDismissal;
mActions = new ArrayList<>(issue.mActions);
+ mAttributionTitle = issue.mAttributionTitle;
+ mGroupId = issue.mGroupId;
}
/** Sets the ID for this issue. */
@@ -323,6 +392,25 @@ public final class SafetyCenterIssue implements Parcelable {
}
/**
+ * Sets or clears the optional attribution title for this issue.
+ *
+ * <p>This is displayed in the UI and helps to attribute issue cards to a particular source.
+ *
+ * @throws UnsupportedOperationException if accessed from a version lower than {@link
+ * UPSIDE_DOWN_CAKE}
+ */
+ @NonNull
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder setAttributionTitle(@Nullable CharSequence attributionTitle) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException(
+ "Method not supported for versions lower than UPSIDE_DOWN_CAKE");
+ }
+ mAttributionTitle = attributionTitle;
+ return this;
+ }
+
+ /**
* Sets {@link IssueSeverityLevel} for this issue. Defaults to {@link
* #ISSUE_SEVERITY_LEVEL_OK}.
*/
@@ -358,6 +446,27 @@ public final class SafetyCenterIssue implements Parcelable {
return this;
}
+ /**
+ * Sets the ID of {@link SafetySourcesGroup} that this issue belongs to. Defaults to a
+ * {@code null} value.
+ *
+ * <p>This ID is used for displaying the issue on its corresponding subpage in the Safety
+ * Center UI.
+ *
+ * @throws UnsupportedOperationException if accessed from a version lower than {@link
+ * UPSIDE_DOWN_CAKE}
+ */
+ @NonNull
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder setGroupId(@Nullable String groupId) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException(
+ "Method not supported for versions lower than UPSIDE_DOWN_CAKE");
+ }
+ mGroupId = groupId;
+ return this;
+ }
+
/** Creates the {@link SafetyCenterIssue} defined by this {@link Builder}. */
@NonNull
public SafetyCenterIssue build() {
@@ -369,7 +478,9 @@ public final class SafetyCenterIssue implements Parcelable {
mSeverityLevel,
mDismissible,
mShouldConfirmDismissal,
- unmodifiableList(new ArrayList<>(mActions)));
+ unmodifiableList(new ArrayList<>(mActions)),
+ mAttributionTitle,
+ mGroupId);
}
}
@@ -378,10 +489,7 @@ public final class SafetyCenterIssue implements Parcelable {
*
* <p>When a user initiates an {@link Action}, that action's associated {@link PendingIntent}
* will be executed, and the {@code successMessage} will be displayed if present.
- *
- * @hide
*/
- @SystemApi
public static final class Action implements Parcelable {
@NonNull
@@ -392,12 +500,19 @@ public final class SafetyCenterIssue implements Parcelable {
String id = in.readString();
CharSequence label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
PendingIntent pendingIntent = in.readTypedObject(PendingIntent.CREATOR);
- return new Builder(id, label, pendingIntent)
- .setWillResolve(in.readBoolean())
- .setIsInFlight(in.readBoolean())
- .setSuccessMessage(
- TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in))
- .build();
+ Builder builder =
+ new Builder(id, label, pendingIntent)
+ .setWillResolve(in.readBoolean())
+ .setIsInFlight(in.readBoolean())
+ .setSuccessMessage(
+ TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(
+ in));
+ if (SdkLevel.isAtLeastU()) {
+ ConfirmationDialogDetails confirmationDialogDetails =
+ in.readTypedObject(ConfirmationDialogDetails.CREATOR);
+ builder.setConfirmationDialogDetails(confirmationDialogDetails);
+ }
+ return builder.build();
}
@Override
@@ -412,6 +527,7 @@ public final class SafetyCenterIssue implements Parcelable {
private final boolean mWillResolve;
private final boolean mInFlight;
@Nullable private final CharSequence mSuccessMessage;
+ @Nullable private final ConfirmationDialogDetails mConfirmationDialogDetails;
private Action(
@NonNull String id,
@@ -419,13 +535,15 @@ public final class SafetyCenterIssue implements Parcelable {
@NonNull PendingIntent pendingIntent,
boolean willResolve,
boolean inFlight,
- @Nullable CharSequence successMessage) {
+ @Nullable CharSequence successMessage,
+ @Nullable ConfirmationDialogDetails confirmationDialogDetails) {
mId = id;
mLabel = label;
mPendingIntent = pendingIntent;
mWillResolve = willResolve;
mInFlight = inFlight;
mSuccessMessage = successMessage;
+ mConfirmationDialogDetails = confirmationDialogDetails;
}
/** Returns the ID of this action. */
@@ -473,6 +591,19 @@ public final class SafetyCenterIssue implements Parcelable {
return mSuccessMessage;
}
+ /**
+ * Returns the optional data to be displayed in the confirmation dialog prior to launching
+ * the {@link PendingIntent} when the action is clicked on.
+ */
+ @Nullable
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public ConfirmationDialogDetails getConfirmationDialogDetails() {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ return mConfirmationDialogDetails;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -483,13 +614,21 @@ public final class SafetyCenterIssue implements Parcelable {
&& Objects.equals(mPendingIntent, action.mPendingIntent)
&& mWillResolve == action.mWillResolve
&& mInFlight == action.mInFlight
- && TextUtils.equals(mSuccessMessage, action.mSuccessMessage);
+ && TextUtils.equals(mSuccessMessage, action.mSuccessMessage)
+ && Objects.equals(
+ mConfirmationDialogDetails, action.mConfirmationDialogDetails);
}
@Override
public int hashCode() {
return Objects.hash(
- mId, mLabel, mSuccessMessage, mWillResolve, mInFlight, mPendingIntent);
+ mId,
+ mLabel,
+ mSuccessMessage,
+ mWillResolve,
+ mInFlight,
+ mPendingIntent,
+ mConfirmationDialogDetails);
}
@Override
@@ -507,6 +646,8 @@ public final class SafetyCenterIssue implements Parcelable {
+ mInFlight
+ ", mSuccessMessage="
+ mSuccessMessage
+ + ", mConfirmationDialogDetails="
+ + mConfirmationDialogDetails
+ '}';
}
@@ -523,6 +664,120 @@ public final class SafetyCenterIssue implements Parcelable {
dest.writeBoolean(mWillResolve);
dest.writeBoolean(mInFlight);
TextUtils.writeToParcel(mSuccessMessage, dest, flags);
+ if (SdkLevel.isAtLeastU()) {
+ dest.writeTypedObject(mConfirmationDialogDetails, flags);
+ }
+ }
+
+ /** Data for an action confirmation dialog to be shown before action is executed. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static final class ConfirmationDialogDetails implements Parcelable {
+
+ @NonNull
+ public static final Creator<ConfirmationDialogDetails> CREATOR =
+ new Creator<ConfirmationDialogDetails>() {
+ @Override
+ public ConfirmationDialogDetails createFromParcel(Parcel in) {
+ CharSequence title =
+ TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ CharSequence text =
+ TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ CharSequence acceptButtonText =
+ TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ CharSequence denyButtonText =
+ TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ return new ConfirmationDialogDetails(
+ title, text, acceptButtonText, denyButtonText);
+ }
+
+ @Override
+ public ConfirmationDialogDetails[] newArray(int size) {
+ return new ConfirmationDialogDetails[size];
+ }
+ };
+
+ @NonNull private final CharSequence mTitle;
+ @NonNull private final CharSequence mText;
+ @NonNull private final CharSequence mAcceptButtonText;
+ @NonNull private final CharSequence mDenyButtonText;
+
+ public ConfirmationDialogDetails(
+ @NonNull CharSequence title,
+ @NonNull CharSequence text,
+ @NonNull CharSequence acceptButtonText,
+ @NonNull CharSequence denyButtonText) {
+ mTitle = requireNonNull(title);
+ mText = requireNonNull(text);
+ mAcceptButtonText = requireNonNull(acceptButtonText);
+ mDenyButtonText = requireNonNull(denyButtonText);
+ }
+
+ /** Returns the title of action confirmation dialog. */
+ @NonNull
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ /** Returns the text of action confirmation dialog. */
+ @NonNull
+ public CharSequence getText() {
+ return mText;
+ }
+
+ /** Returns the text of the button to accept action execution. */
+ @NonNull
+ public CharSequence getAcceptButtonText() {
+ return mAcceptButtonText;
+ }
+
+ /** Returns the text of the button to deny action execution. */
+ @NonNull
+ public CharSequence getDenyButtonText() {
+ return mDenyButtonText;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ TextUtils.writeToParcel(mTitle, dest, flags);
+ TextUtils.writeToParcel(mText, dest, flags);
+ TextUtils.writeToParcel(mAcceptButtonText, dest, flags);
+ TextUtils.writeToParcel(mDenyButtonText, dest, flags);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof ConfirmationDialogDetails)) return false;
+ ConfirmationDialogDetails that = (ConfirmationDialogDetails) o;
+ return TextUtils.equals(mTitle, that.mTitle)
+ && TextUtils.equals(mText, that.mText)
+ && TextUtils.equals(mAcceptButtonText, that.mAcceptButtonText)
+ && TextUtils.equals(mDenyButtonText, that.mDenyButtonText);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTitle, mText, mAcceptButtonText, mDenyButtonText);
+ }
+
+ @Override
+ public String toString() {
+ return "ConfirmationDialogDetails{"
+ + "mTitle="
+ + mTitle
+ + ", mText="
+ + mText
+ + ", mAcceptButtonText="
+ + mAcceptButtonText
+ + ", mDenyButtonText="
+ + mDenyButtonText
+ + '}';
+ }
}
/** Builder class for {@link Action}. */
@@ -534,6 +789,7 @@ public final class SafetyCenterIssue implements Parcelable {
private boolean mWillResolve;
private boolean mInFlight;
@Nullable private CharSequence mSuccessMessage;
+ @Nullable private ConfirmationDialogDetails mConfirmationDialogDetails;
/**
* Creates a new {@link Builder} for an {@link Action}.
@@ -551,6 +807,22 @@ public final class SafetyCenterIssue implements Parcelable {
mPendingIntent = requireNonNull(pendingIntent);
}
+ /** Creates a {@link Builder} with the values from the given {@link Action}. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder(@NonNull Action action) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ requireNonNull(action);
+ mId = action.mId;
+ mLabel = action.mLabel;
+ mPendingIntent = action.mPendingIntent;
+ mWillResolve = action.mWillResolve;
+ mInFlight = action.mInFlight;
+ mSuccessMessage = action.mSuccessMessage;
+ mConfirmationDialogDetails = action.mConfirmationDialogDetails;
+ }
+
/** Sets the ID of this {@link Action} */
@NonNull
public Builder setId(@NonNull String id) {
@@ -609,11 +881,32 @@ public final class SafetyCenterIssue implements Parcelable {
return this;
}
+ /**
+ * Sets the optional data to be displayed in the confirmation dialog prior to launching
+ * the {@link PendingIntent} when the action is clicked on.
+ */
+ @NonNull
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder setConfirmationDialogDetails(
+ @Nullable ConfirmationDialogDetails confirmationDialogDetails) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ mConfirmationDialogDetails = confirmationDialogDetails;
+ return this;
+ }
+
/** Creates the {@link Action} defined by this {@link Builder}. */
@NonNull
public Action build() {
return new Action(
- mId, mLabel, mPendingIntent, mWillResolve, mInFlight, mSuccessMessage);
+ mId,
+ mLabel,
+ mPendingIntent,
+ mWillResolve,
+ mInFlight,
+ mSuccessMessage,
+ mConfirmationDialogDetails);
}
}
}
@@ -628,6 +921,6 @@ public final class SafetyCenterIssue implements Parcelable {
default:
}
throw new IllegalArgumentException(
- String.format("Unexpected IssueSeverityLevel for SafetyCenterIssue: %s", value));
+ "Unexpected IssueSeverityLevel for SafetyCenterIssue: " + value);
}
}
diff --git a/framework-s/java/android/safetycenter/SafetyCenterManager.java b/framework-s/java/android/safetycenter/SafetyCenterManager.java
index c24eda6d6..bb67f578f 100644
--- a/framework-s/java/android/safetycenter/SafetyCenterManager.java
+++ b/framework-s/java/android/safetycenter/SafetyCenterManager.java
@@ -21,6 +21,7 @@ import static android.Manifest.permission.READ_SAFETY_CENTER_STATUS;
import static android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE;
import static android.annotation.SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION;
import static android.os.Build.VERSION_CODES.TIRAMISU;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static java.util.Objects.requireNonNull;
@@ -32,6 +33,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
@@ -42,9 +44,11 @@ import android.util.ArrayMap;
import androidx.annotation.RequiresApi;
import com.android.internal.annotations.GuardedBy;
+import com.android.modules.utils.build.SdkLevel;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
@@ -195,12 +199,21 @@ public final class SafetyCenterManager {
* disambiguate personal profile vs. managed profiles issues).
*
* <p>This extra can be used in conjunction with {@link #EXTRA_SAFETY_SOURCE_ISSUE_ID} and
- * {@link #EXTRA_SAFETY_SOURCE_ID}. Otherwise, no redirection will occur.
+ * {@link #EXTRA_SAFETY_SOURCE_ID}. Otherwise, the device's primary user will be used.
*/
public static final String EXTRA_SAFETY_SOURCE_USER_HANDLE =
"android.safetycenter.extra.SAFETY_SOURCE_USER_HANDLE";
/**
+ * Used as a {@code String} extra field in {@link Intent#ACTION_SAFETY_CENTER} intents to
+ * specify the ID for a group of safety sources. If applicable, this will redirect to the
+ * group's corresponding subpage in the UI.
+ */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static final String EXTRA_SAFETY_SOURCES_GROUP_ID =
+ "android.safetycenter.extra.SAFETY_SOURCES_GROUP_ID";
+
+ /**
* Used as an int value for {@link #EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE} to indicate that
* the safety source should fetch fresh data relating to their safety state upon receiving a
* broadcast with intent action {@link #ACTION_REFRESH_SAFETY_SOURCES} and provide it to Safety
@@ -214,7 +227,7 @@ public final class SafetyCenterManager {
/**
* Used as an int value for {@link #EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE} to indicate that
- * upon receiving a broadcasts with intent action {@link #ACTION_REFRESH_SAFETY_SOURCES}, the
+ * upon receiving a broadcast with intent action {@link #ACTION_REFRESH_SAFETY_SOURCES}, the
* safety source should provide data relating to their safety state to Safety Center.
*
* <p>If the source already has its safety data cached, it may provide it without triggering a
@@ -255,6 +268,10 @@ public final class SafetyCenterManager {
/** Indicates a generic reason for Safety Center refresh. */
public static final int REFRESH_REASON_OTHER = 600;
+ /** Indicates a periodic background refresh. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static final int REFRESH_REASON_PERIODIC = 700;
+
/**
* The reason for requesting a refresh of {@link SafetySourceData} from safety sources.
*
@@ -268,9 +285,11 @@ public final class SafetyCenterManager {
REFRESH_REASON_DEVICE_REBOOT,
REFRESH_REASON_DEVICE_LOCALE_CHANGE,
REFRESH_REASON_SAFETY_CENTER_ENABLED,
- REFRESH_REASON_OTHER
+ REFRESH_REASON_OTHER,
+ REFRESH_REASON_PERIODIC
})
@Retention(RetentionPolicy.SOURCE)
+ @TargetApi(UPSIDE_DOWN_CAKE)
public @interface RefreshReason {}
/** Listener for changes to {@link SafetyCenterData}. */
@@ -429,6 +448,42 @@ public final class SafetyCenterManager {
}
}
+ /**
+ * Requests a specific subset of safety sources to set their latest {@link SafetySourceData} for
+ * Safety Center.
+ *
+ * <p>This API sends a broadcast to safety sources with action {@link
+ * #ACTION_REFRESH_SAFETY_SOURCES} and {@link #EXTRA_REFRESH_SAFETY_SOURCE_IDS} to specify the
+ * IDs of safety sources being requested for data by Safety Center.
+ *
+ * <p>This API is an overload of {@link #refreshSafetySources(int)} and is used to request data
+ * from safety sources that are part of a subpage in the Safety Center UI.
+ *
+ * @see #refreshSafetySources(int)
+ * @param refreshReason the reason for the refresh
+ * @param safetySourceIds list of IDs for the safety sources being refreshed
+ * @throws UnsupportedOperationException if accessed from a version lower than {@link
+ * UPSIDE_DOWN_CAKE}
+ */
+ @RequiresPermission(MANAGE_SAFETY_CENTER)
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public void refreshSafetySources(
+ @RefreshReason int refreshReason, @NonNull List<String> safetySourceIds) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException(
+ "Method not supported for versions lower than UPSIDE_DOWN_CAKE");
+ }
+
+ requireNonNull(safetySourceIds, "safetySourceIds cannot be null");
+
+ try {
+ mService.refreshSpecificSafetySources(
+ refreshReason, mContext.getUser().getIdentifier(), safetySourceIds);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/** Returns the current {@link SafetyCenterConfig}, if available. */
@RequiresPermission(MANAGE_SAFETY_CENTER)
@Nullable
@@ -448,7 +503,8 @@ public final class SafetyCenterManager {
@NonNull
public SafetyCenterData getSafetyCenterData() {
try {
- return mService.getSafetyCenterData(mContext.getUser().getIdentifier());
+ return mService.getSafetyCenterData(
+ mContext.getPackageName(), mContext.getUser().getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -472,7 +528,7 @@ public final class SafetyCenterManager {
ListenerDelegate delegate = new ListenerDelegate(executor, listener);
try {
mService.addOnSafetyCenterDataChangedListener(
- delegate, mContext.getUser().getIdentifier());
+ delegate, mContext.getPackageName(), mContext.getUser().getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -506,8 +562,7 @@ public final class SafetyCenterManager {
}
/**
- * Dismiss a Safety Center issue and prevent it from appearing in the Safety Center or affecting
- * the overall safety status.
+ * Dismiss a Safety Center issue and prevent it from affecting the overall safety status.
*
* @param safetyCenterIssueId the target issue ID returned by {@link SafetyCenterIssue#getId()}
*/
diff --git a/framework-s/java/android/safetycenter/SafetyCenterStatus.java b/framework-s/java/android/safetycenter/SafetyCenterStatus.java
index 0105f19de..e428aef35 100644
--- a/framework-s/java/android/safetycenter/SafetyCenterStatus.java
+++ b/framework-s/java/android/safetycenter/SafetyCenterStatus.java
@@ -296,7 +296,7 @@ public final class SafetyCenterStatus implements Parcelable {
default:
}
throw new IllegalArgumentException(
- String.format("Unexpected OverallSeverityLevel for SafetyCenterStatus: %s", value));
+ "Unexpected OverallSeverityLevel for SafetyCenterStatus: " + value);
}
@RefreshStatus
@@ -309,6 +309,6 @@ public final class SafetyCenterStatus implements Parcelable {
default:
}
throw new IllegalArgumentException(
- String.format("Unexpected RefreshStatus for SafetyCenterStatus: %s", value));
+ "Unexpected RefreshStatus for SafetyCenterStatus: " + value);
}
}
diff --git a/framework-s/java/android/safetycenter/SafetyEvent.java b/framework-s/java/android/safetycenter/SafetyEvent.java
index 471b847f6..72e8defaa 100644
--- a/framework-s/java/android/safetycenter/SafetyEvent.java
+++ b/framework-s/java/android/safetycenter/SafetyEvent.java
@@ -17,6 +17,9 @@
package android.safetycenter;
import static android.os.Build.VERSION_CODES.TIRAMISU;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+
+import static java.util.Objects.requireNonNull;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -27,6 +30,8 @@ import android.os.Parcelable;
import androidx.annotation.RequiresApi;
+import com.android.modules.utils.build.SdkLevel;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
@@ -209,15 +214,12 @@ public final class SafetyEvent implements Parcelable {
return "SafetyEvent{"
+ "mType="
+ mType
- + ", mRefreshBroadcastId='"
+ + ", mRefreshBroadcastId="
+ mRefreshBroadcastId
- + '\''
- + ", mSafetySourceIssueId='"
+ + ", mSafetySourceIssueId="
+ mSafetySourceIssueId
- + '\''
- + ", mSafetySourceIssueActionId='"
+ + ", mSafetySourceIssueActionId="
+ mSafetySourceIssueActionId
- + '\''
+ '}';
}
@@ -234,6 +236,19 @@ public final class SafetyEvent implements Parcelable {
mType = validateType(type);
}
+ /** Creates a {@link Builder} with the values from the given {@link SafetyEvent}. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder(@NonNull SafetyEvent safetyEvent) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ requireNonNull(safetyEvent);
+ mType = safetyEvent.mType;
+ mRefreshBroadcastId = safetyEvent.mRefreshBroadcastId;
+ mSafetySourceIssueId = safetyEvent.mSafetySourceIssueId;
+ mSafetySourceIssueActionId = safetyEvent.mSafetySourceIssueActionId;
+ }
+
/**
* Sets an optional broadcast id provided by Safety Center when requesting a refresh,
* through {@link SafetyCenterManager#EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID}.
@@ -296,16 +311,12 @@ public final class SafetyEvent implements Parcelable {
case SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED:
if (mSafetySourceIssueId == null) {
throw new IllegalArgumentException(
- String.format(
- "Missing issue id for resolving action safety event (%s)",
- mType));
+ "Missing issue id for resolving action safety event: " + mType);
}
if (mSafetySourceIssueActionId == null) {
throw new IllegalArgumentException(
- String.format(
- "Missing issue action id for resolving action safety event "
- + "(%s)",
- mType));
+ "Missing issue action id for resolving action safety event: "
+ + mType);
}
break;
case SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED:
@@ -330,7 +341,6 @@ public final class SafetyEvent implements Parcelable {
return value;
default:
}
- throw new IllegalArgumentException(
- String.format("Unexpected Type for SafetyEvent: %s", value));
+ throw new IllegalArgumentException("Unexpected Type for SafetyEvent: " + value);
}
}
diff --git a/framework-s/java/android/safetycenter/SafetySourceData.java b/framework-s/java/android/safetycenter/SafetySourceData.java
index 59a575e4d..2e80621a2 100644
--- a/framework-s/java/android/safetycenter/SafetySourceData.java
+++ b/framework-s/java/android/safetycenter/SafetySourceData.java
@@ -17,6 +17,7 @@
package android.safetycenter;
import static android.os.Build.VERSION_CODES.TIRAMISU;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static com.android.internal.util.Preconditions.checkArgument;
@@ -27,16 +28,21 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.RequiresApi;
+import com.android.modules.utils.build.SdkLevel;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
/**
* Data class used by safety sources to propagate safety information such as their safety status and
@@ -160,6 +166,12 @@ public final class SafetySourceData implements Parcelable {
for (int i = 0; i < issues.size(); i++) {
builder.addIssue(issues.get(i));
}
+ if (SdkLevel.isAtLeastU()) {
+ Bundle extras = in.readBundle(getClass().getClassLoader());
+ if (extras != null) {
+ builder.setExtras(extras);
+ }
+ }
return builder.build();
}
@@ -171,11 +183,15 @@ public final class SafetySourceData implements Parcelable {
@Nullable private final SafetySourceStatus mStatus;
@NonNull private final List<SafetySourceIssue> mIssues;
+ @NonNull private final Bundle mExtras;
private SafetySourceData(
- @Nullable SafetySourceStatus status, @NonNull List<SafetySourceIssue> issues) {
+ @Nullable SafetySourceStatus status,
+ @NonNull List<SafetySourceIssue> issues,
+ @NonNull Bundle extras) {
this.mStatus = status;
this.mIssues = issues;
+ this.mExtras = extras;
}
/** Returns the data for the {@link SafetySourceStatus} to be shown in UI. */
@@ -190,6 +206,21 @@ public final class SafetySourceData implements Parcelable {
return mIssues;
}
+ /**
+ * Returns a {@link Bundle} containing additional information, {@link Bundle#EMPTY} by default.
+ *
+ * <p>Note: internal state of this {@link Bundle} is not used for {@link Object#equals} and
+ * {@link Object#hashCode} implementation of {@link SafetySourceData}.
+ */
+ @NonNull
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Bundle getExtras() {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ return mExtras;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -199,6 +230,9 @@ public final class SafetySourceData implements Parcelable {
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeTypedObject(mStatus, flags);
dest.writeTypedList(mIssues);
+ if (SdkLevel.isAtLeastU()) {
+ dest.writeBundle(mExtras);
+ }
}
@Override
@@ -216,7 +250,13 @@ public final class SafetySourceData implements Parcelable {
@Override
public String toString() {
- return "SafetySourceData{" + ", mStatus=" + mStatus + ", mIssues=" + mIssues + '}';
+ return "SafetySourceData{"
+ + "mStatus="
+ + mStatus
+ + ", mIssues="
+ + mIssues
+ + (!mExtras.isEmpty() ? ", (has extras)" : "")
+ + '}';
}
/** Builder class for {@link SafetySourceData}. */
@@ -225,6 +265,22 @@ public final class SafetySourceData implements Parcelable {
@NonNull private final List<SafetySourceIssue> mIssues = new ArrayList<>();
@Nullable private SafetySourceStatus mStatus;
+ @NonNull private Bundle mExtras = Bundle.EMPTY;
+
+ /** Creates a {@link Builder} for a {@link SafetySourceData}. */
+ public Builder() {}
+
+ /** Creates a {@link Builder} with the values from the given {@link SafetySourceData}. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder(@NonNull SafetySourceData safetySourceData) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ requireNonNull(safetySourceData);
+ mIssues.addAll(safetySourceData.mIssues);
+ mStatus = safetySourceData.mStatus;
+ mExtras = safetySourceData.mExtras.deepCopy();
+ }
/** Sets data for the {@link SafetySourceStatus} to be shown in UI. */
@NonNull
@@ -241,6 +297,35 @@ public final class SafetySourceData implements Parcelable {
}
/**
+ * Sets additional information for the {@link SafetySourceData}.
+ *
+ * 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();
+ }
+ mExtras = requireNonNull(extras);
+ return this;
+ }
+
+ /**
+ * Resets additional information for the {@link SafetySourceData} to the default value of
+ * {@link Bundle#EMPTY}.
+ */
+ @NonNull
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder clearExtras() {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ mExtras = Bundle.EMPTY;
+ return this;
+ }
+
+ /**
* Clears data for all the {@link SafetySourceIssue}s that were added to this {@link
* Builder}.
*/
@@ -254,23 +339,35 @@ public final class SafetySourceData implements Parcelable {
@NonNull
public SafetySourceData build() {
List<SafetySourceIssue> issues = unmodifiableList(new ArrayList<>(mIssues));
- if (mStatus != null) {
- int issuesMaxSeverityLevel = getIssuesMaxSeverityLevel(issues);
- if (issuesMaxSeverityLevel > SafetySourceData.SEVERITY_LEVEL_INFORMATION) {
- checkArgument(
- issuesMaxSeverityLevel <= mStatus.getSeverityLevel(),
- "Safety source data must not contain any issue with a severity level "
- + "both greater than SEVERITY_LEVEL_INFORMATION and greater "
- + "than the status severity level");
- }
+ int issuesMaxSeverityLevel = getIssuesMaxSeverityLevelEnforcingUniqueIds(issues);
+ if (mStatus == null) {
+ return new SafetySourceData(null, issues, mExtras);
+ }
+ int statusSeverityLevel = mStatus.getSeverityLevel();
+ boolean requiresAttention = issuesMaxSeverityLevel > SEVERITY_LEVEL_INFORMATION;
+ if (requiresAttention) {
+ checkArgument(
+ statusSeverityLevel >= issuesMaxSeverityLevel,
+ "Safety source data cannot have issues that are more severe than its"
+ + " status");
}
- return new SafetySourceData(mStatus, issues);
+
+ return new SafetySourceData(mStatus, issues, mExtras);
}
- private static int getIssuesMaxSeverityLevel(@NonNull List<SafetySourceIssue> issues) {
+ private static int getIssuesMaxSeverityLevelEnforcingUniqueIds(
+ @NonNull List<SafetySourceIssue> issues) {
int max = Integer.MIN_VALUE;
+ Set<String> issueIds = new HashSet<>();
for (int i = 0; i < issues.size(); i++) {
- max = Math.max(max, issues.get(i).getSeverityLevel());
+ SafetySourceIssue safetySourceIssue = issues.get(i);
+
+ String issueId = safetySourceIssue.getId();
+ checkArgument(
+ !issueIds.contains(issueId),
+ "Safety source data cannot have duplicate issue ids");
+ max = Math.max(max, safetySourceIssue.getSeverityLevel());
+ issueIds.add(issueId);
}
return max;
}
diff --git a/framework-s/java/android/safetycenter/SafetySourceIssue.java b/framework-s/java/android/safetycenter/SafetySourceIssue.java
index ddd55b131..985131764 100644
--- a/framework-s/java/android/safetycenter/SafetySourceIssue.java
+++ b/framework-s/java/android/safetycenter/SafetySourceIssue.java
@@ -17,6 +17,7 @@
package android.safetycenter;
import static android.os.Build.VERSION_CODES.TIRAMISU;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static com.android.internal.util.Preconditions.checkArgument;
@@ -28,18 +29,24 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.TargetApi;
import android.app.PendingIntent;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import androidx.annotation.RequiresApi;
+import com.android.modules.utils.build.SdkLevel;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
/**
* Data for a safety source issue in the Safety Center page.
@@ -62,9 +69,26 @@ public final class SafetySourceIssue implements Parcelable {
/** Indicates that the risk associated with the issue is related to a user's account safety. */
public static final int ISSUE_CATEGORY_ACCOUNT = 200;
- /** Indicates that the risk associated with the issue is related to a user's general safety. */
+ /**
+ * Indicates that the risk associated with the issue is related to a user's general safety.
+ *
+ * <p>This is the default. It is a generic value used when the category is not known or is not
+ * relevant.
+ */
public static final int ISSUE_CATEGORY_GENERAL = 300;
+ /** Indicates that the risk associated with the issue is related to a user's data. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static final int ISSUE_CATEGORY_DATA = 400;
+
+ /** Indicates that the risk associated with the issue is related to a user's passwords. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static final int ISSUE_CATEGORY_PASSWORDS = 500;
+
+ /** Indicates that the risk associated with the issue is related to a user's personal safety. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static final int ISSUE_CATEGORY_PERSONAL_SAFETY = 600;
+
/**
* All possible issue categories.
*
@@ -82,10 +106,108 @@ public final class SafetySourceIssue implements Parcelable {
ISSUE_CATEGORY_DEVICE,
ISSUE_CATEGORY_ACCOUNT,
ISSUE_CATEGORY_GENERAL,
+ ISSUE_CATEGORY_DATA,
+ ISSUE_CATEGORY_PASSWORDS,
+ ISSUE_CATEGORY_PERSONAL_SAFETY
})
@Retention(RetentionPolicy.SOURCE)
+ @TargetApi(UPSIDE_DOWN_CAKE)
public @interface IssueCategory {}
+ /** Value signifying that the source has not specified a particular notification behavior. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static final int NOTIFICATION_BEHAVIOR_UNSPECIFIED = 0;
+
+ /** An issue which Safety Center should never notify the user about. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static final int NOTIFICATION_BEHAVIOR_NEVER = 100;
+
+ /**
+ * An issue which Safety Center may notify the user about after a delay if it has not been
+ * resolved. Safety Center does not provide any guarantee about the duration of the delay.
+ */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static final int NOTIFICATION_BEHAVIOR_DELAYED = 200;
+
+ /** An issue which Safety Center may notify the user about immediately. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static final int NOTIFICATION_BEHAVIOR_IMMEDIATELY = 300;
+
+ /**
+ * All possible notification behaviors.
+ *
+ * <p>The notification behavior of a {@link SafetySourceIssue} determines if and when Safety
+ * Center should notify the user about it.
+ *
+ * @hide
+ * @see Builder#setNotificationBehavior(int)
+ */
+ @IntDef(
+ prefix = {"NOTIFICATION_BEHAVIOR_"},
+ value = {
+ NOTIFICATION_BEHAVIOR_UNSPECIFIED,
+ NOTIFICATION_BEHAVIOR_NEVER,
+ NOTIFICATION_BEHAVIOR_DELAYED,
+ NOTIFICATION_BEHAVIOR_IMMEDIATELY
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @TargetApi(UPSIDE_DOWN_CAKE)
+ public @interface NotificationBehavior {}
+
+ /**
+ * An issue which requires manual user input to be resolved.
+ *
+ * <p>This is the default.
+ */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static final int ISSUE_ACTIONABILITY_MANUAL = 0;
+
+ /**
+ * An issue which is just a "tip" and may not require any user input.
+ *
+ * <p>It is still possible to provide {@link Action}s to e.g. "learn more" about it or
+ * acknowledge it.
+ */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static final int ISSUE_ACTIONABILITY_TIP = 100;
+
+ /**
+ * An issue which has already been actioned and may not require any user input.
+ *
+ * <p>It is still possible to provide {@link Action}s to e.g. "learn more" about it or
+ * acknowledge it.
+ */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static final int ISSUE_ACTIONABILITY_AUTOMATIC = 200;
+
+ /**
+ * All possible issue actionability.
+ *
+ * <p>An issue's actionability represent what action is expected from the user as a result of
+ * showing them this issue.
+ *
+ * <p>If the user needs to manually resolve it; this is typically achieved using an {@link
+ * Action} (e.g. by resolving the issue directly through the Safety Center screen, or by
+ * navigating to another page).
+ *
+ * <p>If the issue does not need to be resolved manually by the user, it is possible not to
+ * provide any {@link Action}. However, this may still be desirable to e.g. to "learn more"
+ * about it or acknowledge it.
+ *
+ * @hide
+ * @see Builder#setIssueActionability(int)
+ */
+ @IntDef(
+ prefix = {"ISSUE_ACTIONABILITY_"},
+ value = {
+ ISSUE_ACTIONABILITY_MANUAL,
+ ISSUE_ACTIONABILITY_TIP,
+ ISSUE_ACTIONABILITY_AUTOMATIC
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @TargetApi(UPSIDE_DOWN_CAKE)
+ public @interface IssueActionability {}
+
@NonNull
public static final Creator<SafetySourceIssue> CREATOR =
new Creator<SafetySourceIssue>() {
@@ -109,6 +231,14 @@ public final class SafetySourceIssue implements Parcelable {
for (int i = 0; i < actions.size(); i++) {
builder.addAction(actions.get(i));
}
+ if (SdkLevel.isAtLeastU()) {
+ builder.setCustomNotification(in.readTypedObject(Notification.CREATOR));
+ builder.setNotificationBehavior(in.readInt());
+ builder.setAttributionTitle(
+ TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in));
+ builder.setDeduplicationId(in.readString());
+ builder.setIssueActionability(in.readInt());
+ }
return builder.build();
}
@@ -127,6 +257,11 @@ public final class SafetySourceIssue implements Parcelable {
@Nullable private final PendingIntent mOnDismissPendingIntent;
@IssueCategory private final int mIssueCategory;
@NonNull private final String mIssueTypeId;
+ @Nullable private final Notification mCustomNotification;
+ @NotificationBehavior private final int mNotificationBehavior;
+ @Nullable private final CharSequence mAttributionTitle;
+ @Nullable private final String mDeduplicationId;
+ @IssueActionability private final int mIssueActionability;
private SafetySourceIssue(
@NonNull String id,
@@ -137,7 +272,12 @@ public final class SafetySourceIssue implements Parcelable {
@IssueCategory int issueCategory,
@NonNull List<Action> actions,
@Nullable PendingIntent onDismissPendingIntent,
- @NonNull String issueTypeId) {
+ @NonNull String issueTypeId,
+ @Nullable Notification customNotification,
+ @NotificationBehavior int notificationBehavior,
+ @Nullable CharSequence attributionTitle,
+ @Nullable String deduplicationId,
+ @IssueActionability int issueActionability) {
this.mId = id;
this.mTitle = title;
this.mSubtitle = subtitle;
@@ -147,6 +287,11 @@ public final class SafetySourceIssue implements Parcelable {
this.mActions = actions;
this.mOnDismissPendingIntent = onDismissPendingIntent;
this.mIssueTypeId = issueTypeId;
+ this.mCustomNotification = customNotification;
+ this.mNotificationBehavior = notificationBehavior;
+ this.mAttributionTitle = attributionTitle;
+ this.mDeduplicationId = deduplicationId;
+ this.mIssueActionability = issueActionability;
}
/**
@@ -181,6 +326,22 @@ public final class SafetySourceIssue implements Parcelable {
return mSummary;
}
+ /**
+ * Returns the localized attribution title of the issue to be displayed in the UI.
+ *
+ * <p>This is displayed in the UI and helps to attribute issue cards to a particular source. If
+ * this value is {@code null}, the title of the group that contains the Safety Source will be
+ * used.
+ */
+ @Nullable
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public CharSequence getAttributionTitle() {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ return mAttributionTitle;
+ }
+
/** Returns the {@link SafetySourceData.SeverityLevel} of the issue. */
@SafetySourceData.SeverityLevel
public int getSeverityLevel() {
@@ -241,6 +402,114 @@ public final class SafetySourceIssue implements Parcelable {
return mIssueTypeId;
}
+ /**
+ * Returns the optional custom {@link Notification} for this issue which overrides the title,
+ * text and actions for any {@link android.app.Notification} generated for this {@link
+ * SafetySourceIssue}.
+ *
+ * <p>Safety Center may still generate a default notification from the other details of this
+ * issue when no custom notification has been set. See {@link #getNotificationBehavior()} for
+ * details
+ *
+ * @see Builder#setCustomNotification(android.safetycenter.SafetySourceIssue.Notification
+ * @see #getNotificationBehavior()
+ */
+ @Nullable
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Notification getCustomNotification() {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ return mCustomNotification;
+ }
+
+ /**
+ * Returns the {@link NotificationBehavior} for this issue which determines if and when Safety
+ * Center will post a notification for this issue.
+ *
+ * <p>Any notification will be based on the {@link #getCustomNotification()} if set, or the
+ * other properties of this issue otherwise.
+ *
+ * <ul>
+ * <li>If {@link #NOTIFICATION_BEHAVIOR_IMMEDIATELY} then Safety Center will immediately
+ * create and post a notification
+ * <li>If {@link #NOTIFICATION_BEHAVIOR_DELAYED} then a notification will only be posted after
+ * a delay, if this issue has not been resolved.
+ * <li>If {@link #NOTIFICATION_BEHAVIOR_UNSPECIFIED} then a notification may or may not be
+ * posted, the exact behavior is defined by Safety Center.
+ * <li>If {@link #NOTIFICATION_BEHAVIOR_NEVER} Safety Center will never post a notification
+ * about this issue. Sources should specify this behavior when they wish to handle their
+ * own notifications. When this behavior is set sources should not set a custom
+ * notification.
+ * </ul>
+ *
+ * @see Builder#setNotificationBehavior(int)
+ */
+ @NotificationBehavior
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public int getNotificationBehavior() {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ return mNotificationBehavior;
+ }
+
+ /**
+ * Returns the identifier used to deduplicate this issue against other issues with the same
+ * deduplication identifiers.
+ *
+ * <p>Deduplication identifier will be used to identify duplicate issues. This identifier
+ * applies across all safety sources which are part of the same deduplication group.
+ * Deduplication groups can be set, for each source, in the SafetyCenter config. Therefore, two
+ * issues are considered duplicate if their sources are part of the same deduplication group and
+ * they have the same deduplication identifier.
+ *
+ * <p>Out of all issues that are found to be duplicates, only one will be shown in the UI (the
+ * one with the highest severity, or in case of same severities, the one placed highest in the
+ * config).
+ *
+ * <p>Expected usage implies different sources will coordinate to set the same deduplication
+ * identifiers on issues that they want to deduplicate.
+ *
+ * <p>This shouldn't be a default mechanism for deduplication of issues. Most of the time
+ * sources should coordinate or communicate to only send the issue from one of them. That would
+ * also allow sources to choose which one will be displaying the issue, instead of depending on
+ * severity and config order. This API should only be needed if for some reason this isn't
+ * possible, for example, when sources can't communicate with each other and/or send issues at
+ * different times and/or issues can be of different severities.
+ */
+ @Nullable
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public String getDeduplicationId() {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ return mDeduplicationId;
+ }
+
+ /**
+ * Returns the {@link IssueActionability} for this issue which determines what type of action is
+ * required from the user:
+ *
+ * <ul>
+ * <li>If {@link #ISSUE_ACTIONABILITY_MANUAL} then user input is required to resolve the issue
+ * <li>If {@link #ISSUE_ACTIONABILITY_TIP} then the user needs to review this issue as a tip
+ * to improve their overall safety, and possibly acknowledge it
+ * <li>If {@link #ISSUE_ACTIONABILITY_AUTOMATIC} then the user needs to review this issue as
+ * something that has been resolved on their behalf, and possibly acknowledge it
+ * </ul>
+ *
+ * @see Builder#setIssueActionability(int)
+ */
+ @IssueActionability
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public int getIssueActionability() {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ return mIssueActionability;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -257,6 +526,13 @@ public final class SafetySourceIssue implements Parcelable {
dest.writeTypedList(mActions);
dest.writeTypedObject(mOnDismissPendingIntent, flags);
dest.writeString(mIssueTypeId);
+ if (SdkLevel.isAtLeastU()) {
+ dest.writeTypedObject(mCustomNotification, flags);
+ dest.writeInt(mNotificationBehavior);
+ TextUtils.writeToParcel(mAttributionTitle, dest, flags);
+ dest.writeString(mDeduplicationId);
+ dest.writeInt(mIssueActionability);
+ }
}
@Override
@@ -272,7 +548,12 @@ public final class SafetySourceIssue implements Parcelable {
&& mIssueCategory == that.mIssueCategory
&& mActions.equals(that.mActions)
&& Objects.equals(mOnDismissPendingIntent, that.mOnDismissPendingIntent)
- && TextUtils.equals(mIssueTypeId, that.mIssueTypeId);
+ && TextUtils.equals(mIssueTypeId, that.mIssueTypeId)
+ && Objects.equals(mCustomNotification, that.mCustomNotification)
+ && mNotificationBehavior == that.mNotificationBehavior
+ && TextUtils.equals(mAttributionTitle, that.mAttributionTitle)
+ && TextUtils.equals(mDeduplicationId, that.mDeduplicationId)
+ && mIssueActionability == that.mIssueActionability;
}
@Override
@@ -286,7 +567,12 @@ public final class SafetySourceIssue implements Parcelable {
mIssueCategory,
mActions,
mOnDismissPendingIntent,
- mIssueTypeId);
+ mIssueTypeId,
+ mCustomNotification,
+ mNotificationBehavior,
+ mAttributionTitle,
+ mDeduplicationId,
+ mIssueActionability);
}
@Override
@@ -310,6 +596,16 @@ public final class SafetySourceIssue implements Parcelable {
+ mOnDismissPendingIntent
+ ", mIssueTypeId="
+ mIssueTypeId
+ + ", mCustomNotification="
+ + mCustomNotification
+ + ", mNotificationBehavior="
+ + mNotificationBehavior
+ + ", mAttributionTitle="
+ + mAttributionTitle
+ + ", mDeduplicationId="
+ + mDeduplicationId
+ + ", mIssueActionability="
+ + mIssueActionability
+ '}';
}
@@ -323,10 +619,7 @@ public final class SafetySourceIssue implements Parcelable {
*
* <p>The user will be allowed to invoke the action from the UI by clicking on a UI element and
* consequently resolve the issue.
- *
- * @hide
*/
- @SystemApi
public static final class Action implements Parcelable {
@NonNull
@@ -337,11 +630,18 @@ public final class SafetySourceIssue implements Parcelable {
String id = in.readString();
CharSequence label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
PendingIntent pendingIntent = in.readTypedObject(PendingIntent.CREATOR);
- return new Builder(id, label, pendingIntent)
- .setWillResolve(in.readBoolean())
- .setSuccessMessage(
- TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in))
- .build();
+ Builder builder =
+ new Builder(id, label, pendingIntent)
+ .setWillResolve(in.readBoolean())
+ .setSuccessMessage(
+ TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(
+ in));
+ if (SdkLevel.isAtLeastU()) {
+ ConfirmationDialogDetails confirmationDialogDetails =
+ in.readTypedObject(ConfirmationDialogDetails.CREATOR);
+ builder.setConfirmationDialogDetails(confirmationDialogDetails);
+ }
+ return builder.build();
}
@Override
@@ -350,23 +650,38 @@ public final class SafetySourceIssue implements Parcelable {
}
};
+ private static void enforceUniqueActionIds(
+ @NonNull List<SafetySourceIssue.Action> actions, @NonNull String message) {
+ Set<String> actionIds = new HashSet<>();
+ for (int i = 0; i < actions.size(); i++) {
+ SafetySourceIssue.Action action = actions.get(i);
+
+ String actionId = action.getId();
+ checkArgument(!actionIds.contains(actionId), message);
+ actionIds.add(actionId);
+ }
+ }
+
@NonNull private final String mId;
@NonNull private final CharSequence mLabel;
@NonNull private final PendingIntent mPendingIntent;
private final boolean mWillResolve;
@Nullable private final CharSequence mSuccessMessage;
+ @Nullable private final ConfirmationDialogDetails mConfirmationDialogDetails;
private Action(
@NonNull String id,
@NonNull CharSequence label,
@NonNull PendingIntent pendingIntent,
boolean willResolve,
- @Nullable CharSequence successMessage) {
+ @Nullable CharSequence successMessage,
+ @Nullable ConfirmationDialogDetails confirmationDialogDetails) {
mId = id;
mLabel = label;
mPendingIntent = pendingIntent;
mWillResolve = willResolve;
mSuccessMessage = successMessage;
+ mConfirmationDialogDetails = confirmationDialogDetails;
}
/**
@@ -416,6 +731,19 @@ public final class SafetySourceIssue implements Parcelable {
return mSuccessMessage;
}
+ /**
+ * Returns the optional data to be displayed in the confirmation dialog prior to launching
+ * the {@link PendingIntent} when the action is clicked on.
+ */
+ @Nullable
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public ConfirmationDialogDetails getConfirmationDialogDetails() {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ return mConfirmationDialogDetails;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -428,6 +756,9 @@ public final class SafetySourceIssue implements Parcelable {
dest.writeTypedObject(mPendingIntent, flags);
dest.writeBoolean(mWillResolve);
TextUtils.writeToParcel(mSuccessMessage, dest, flags);
+ if (SdkLevel.isAtLeastU()) {
+ dest.writeTypedObject(mConfirmationDialogDetails, flags);
+ }
}
@Override
@@ -439,12 +770,19 @@ public final class SafetySourceIssue implements Parcelable {
&& TextUtils.equals(mLabel, that.mLabel)
&& mPendingIntent.equals(that.mPendingIntent)
&& mWillResolve == that.mWillResolve
- && TextUtils.equals(mSuccessMessage, that.mSuccessMessage);
+ && TextUtils.equals(mSuccessMessage, that.mSuccessMessage)
+ && Objects.equals(mConfirmationDialogDetails, that.mConfirmationDialogDetails);
}
@Override
public int hashCode() {
- return Objects.hash(mId, mLabel, mPendingIntent, mWillResolve, mSuccessMessage);
+ return Objects.hash(
+ mId,
+ mLabel,
+ mPendingIntent,
+ mWillResolve,
+ mSuccessMessage,
+ mConfirmationDialogDetails);
}
@Override
@@ -460,9 +798,122 @@ public final class SafetySourceIssue implements Parcelable {
+ mWillResolve
+ ", mSuccessMessage="
+ mSuccessMessage
+ + ", mConfirmationDialogDetails="
+ + mConfirmationDialogDetails
+ '}';
}
+ /** Data for an action confirmation dialog to be shown before action is executed. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static final class ConfirmationDialogDetails implements Parcelable {
+
+ @NonNull
+ public static final Creator<ConfirmationDialogDetails> CREATOR =
+ new Creator<ConfirmationDialogDetails>() {
+ @Override
+ public ConfirmationDialogDetails createFromParcel(Parcel in) {
+ CharSequence title =
+ TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ CharSequence text =
+ TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ CharSequence acceptButtonText =
+ TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ CharSequence denyButtonText =
+ TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ return new ConfirmationDialogDetails(
+ title, text, acceptButtonText, denyButtonText);
+ }
+
+ @Override
+ public ConfirmationDialogDetails[] newArray(int size) {
+ return new ConfirmationDialogDetails[size];
+ }
+ };
+
+ @NonNull private final CharSequence mTitle;
+ @NonNull private final CharSequence mText;
+ @NonNull private final CharSequence mAcceptButtonText;
+ @NonNull private final CharSequence mDenyButtonText;
+
+ public ConfirmationDialogDetails(
+ @NonNull CharSequence title,
+ @NonNull CharSequence text,
+ @NonNull CharSequence acceptButtonText,
+ @NonNull CharSequence denyButtonText) {
+ mTitle = requireNonNull(title);
+ mText = requireNonNull(text);
+ mAcceptButtonText = requireNonNull(acceptButtonText);
+ mDenyButtonText = requireNonNull(denyButtonText);
+ }
+
+ /** Returns the title of action confirmation dialog. */
+ @NonNull
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ /** Returns the text of action confirmation dialog. */
+ @NonNull
+ public CharSequence getText() {
+ return mText;
+ }
+
+ /** Returns the text of the button to accept action execution. */
+ @NonNull
+ public CharSequence getAcceptButtonText() {
+ return mAcceptButtonText;
+ }
+
+ /** Returns the text of the button to deny action execution. */
+ @NonNull
+ public CharSequence getDenyButtonText() {
+ return mDenyButtonText;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ TextUtils.writeToParcel(mTitle, dest, flags);
+ TextUtils.writeToParcel(mText, dest, flags);
+ TextUtils.writeToParcel(mAcceptButtonText, dest, flags);
+ TextUtils.writeToParcel(mDenyButtonText, dest, flags);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof ConfirmationDialogDetails)) return false;
+ ConfirmationDialogDetails that = (ConfirmationDialogDetails) o;
+ return TextUtils.equals(mTitle, that.mTitle)
+ && TextUtils.equals(mText, that.mText)
+ && TextUtils.equals(mAcceptButtonText, that.mAcceptButtonText)
+ && TextUtils.equals(mDenyButtonText, that.mDenyButtonText);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTitle, mText, mAcceptButtonText, mDenyButtonText);
+ }
+
+ @Override
+ public String toString() {
+ return "ConfirmationDialogDetails{"
+ + "mTitle="
+ + mTitle
+ + ", mText="
+ + mText
+ + ", mAcceptButtonText="
+ + mAcceptButtonText
+ + ", mDenyButtonText="
+ + mDenyButtonText
+ + '}';
+ }
+ }
+
/** Builder class for {@link Action}. */
public static final class Builder {
@@ -471,6 +922,7 @@ public final class SafetySourceIssue implements Parcelable {
@NonNull private final PendingIntent mPendingIntent;
private boolean mWillResolve = false;
@Nullable private CharSequence mSuccessMessage;
+ @Nullable private ConfirmationDialogDetails mConfirmationDialogDetails;
/** Creates a {@link Builder} for an {@link Action}. */
public Builder(
@@ -482,9 +934,28 @@ public final class SafetySourceIssue implements Parcelable {
mPendingIntent = requireNonNull(pendingIntent);
}
+ /** Creates a {@link Builder} with the values from the given {@link Action}. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder(@NonNull Action action) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ requireNonNull(action);
+ mId = action.mId;
+ mLabel = action.mLabel;
+ mPendingIntent = action.mPendingIntent;
+ mWillResolve = action.mWillResolve;
+ mSuccessMessage = action.mSuccessMessage;
+ mConfirmationDialogDetails = action.mConfirmationDialogDetails;
+ }
+
/**
* Sets whether the action will resolve the safety issue. Defaults to {@code false}.
*
+ * <p>Note: It is not allowed for resolvable actions to have a {@link PendingIntent}
+ * that launches activity. When extra confirmation is needed consider using {@link
+ * Builder#setConfirmationDialogDetails}.
+ *
* @see #willResolve()
*/
@SuppressLint("MissingGetterMatchingBuilder")
@@ -504,10 +975,212 @@ public final class SafetySourceIssue implements Parcelable {
return this;
}
+ /**
+ * Sets the optional data to be displayed in the confirmation dialog prior to launching
+ * the {@link PendingIntent} when the action is clicked on.
+ */
+ @NonNull
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder setConfirmationDialogDetails(
+ @Nullable ConfirmationDialogDetails confirmationDialogDetails) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ mConfirmationDialogDetails = confirmationDialogDetails;
+ return this;
+ }
+
/** Creates the {@link Action} defined by this {@link Builder}. */
@NonNull
public Action build() {
- return new Action(mId, mLabel, mPendingIntent, mWillResolve, mSuccessMessage);
+ if (SdkLevel.isAtLeastU()) {
+ boolean willResolveWithActivity = mWillResolve && mPendingIntent.isActivity();
+ checkArgument(
+ !willResolveWithActivity,
+ "Launching activity from Action that should resolve the"
+ + " SafetySourceIssue is not allowed. Consider using setting a"
+ + " Confirmation if needed, and either set the willResolve to"
+ + " false or make PendingIntent to start a service/send a"
+ + " broadcast.");
+ }
+ return new Action(
+ mId,
+ mLabel,
+ mPendingIntent,
+ mWillResolve,
+ mSuccessMessage,
+ mConfirmationDialogDetails);
+ }
+ }
+ }
+
+ /**
+ * Data for Safety Center to use when constructing a system {@link android.app.Notification}
+ * about a related {@link SafetySourceIssue}.
+ *
+ * <p>Safety Center can construct a default notification for any issue, but sources may use
+ * {@link Builder#setCustomNotification(android.safetycenter.SafetySourceIssue.Notification)} if
+ * they want to override the title, text or actions.
+ *
+ * @see #getCustomNotification()
+ * @see Builder#setCustomNotification(android.safetycenter.SafetySourceIssue.Notification)
+ * @see #getNotificationBehavior()
+ */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static final class Notification implements Parcelable {
+
+ @NonNull
+ public static final Creator<Notification> CREATOR =
+ new Creator<Notification>() {
+ @Override
+ public Notification createFromParcel(Parcel in) {
+ return new Builder(
+ TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in),
+ TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in))
+ .addActions(in.createTypedArrayList(Action.CREATOR))
+ .build();
+ }
+
+ @Override
+ public Notification[] newArray(int size) {
+ return new Notification[size];
+ }
+ };
+
+ @NonNull private final CharSequence mTitle;
+ @NonNull private final CharSequence mText;
+ @NonNull private final List<Action> mActions;
+
+ private Notification(
+ @NonNull CharSequence title,
+ @NonNull CharSequence text,
+ @NonNull List<Action> actions) {
+ mTitle = title;
+ mText = text;
+ mActions = actions;
+ }
+
+ /**
+ * Custom title which will be used instead of {@link SafetySourceIssue#getTitle()} when
+ * building a {@link android.app.Notification} for this issue.
+ */
+ @NonNull
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ /**
+ * Custom text which will be used instead of {@link SafetySourceIssue#getSummary()} when
+ * building a {@link android.app.Notification} for this issue.
+ */
+ @NonNull
+ public CharSequence getText() {
+ return mText;
+ }
+
+ /**
+ * Custom list of {@link Action} instances which will be used instead of {@link
+ * SafetySourceIssue#getActions()} when building a {@link android.app.Notification} for this
+ * issue.
+ *
+ * <p>If this list is empty then the resulting {@link android.app.Notification} will have
+ * zero action buttons.
+ */
+ @NonNull
+ public List<Action> getActions() {
+ return mActions;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ TextUtils.writeToParcel(mTitle, dest, flags);
+ TextUtils.writeToParcel(mText, dest, flags);
+ dest.writeTypedList(mActions);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Notification)) return false;
+ Notification that = (Notification) o;
+ return TextUtils.equals(mTitle, that.mTitle)
+ && TextUtils.equals(mText, that.mText)
+ && mActions.equals(that.mActions);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTitle, mText, mActions);
+ }
+
+ @Override
+ public String toString() {
+ return "Notification{"
+ + "mTitle="
+ + mTitle
+ + ", mText="
+ + mText
+ + ", mActions="
+ + mActions
+ + '}';
+ }
+
+ /** Builder for {@link SafetySourceIssue.Notification}. */
+ public static final class Builder {
+
+ @NonNull private final CharSequence mTitle;
+ @NonNull private final CharSequence mText;
+ @NonNull private final List<Action> mActions = new ArrayList<>();
+
+ public Builder(@NonNull CharSequence title, @NonNull CharSequence text) {
+ mTitle = requireNonNull(title);
+ mText = requireNonNull(text);
+ }
+
+ /** Creates a {@link Builder} with the values from the given {@link Notification}. */
+ public Builder(@NonNull Notification notification) {
+ requireNonNull(notification);
+ mTitle = notification.mTitle;
+ mText = notification.mText;
+ mActions.addAll(notification.mActions);
+ }
+
+ /** Adds an {@link Action} to the custom {@link Notification}. */
+ @NonNull
+ public Builder addAction(@NonNull Action action) {
+ mActions.add(requireNonNull(action));
+ return this;
+ }
+
+ /** Adds several {@link Action}s to the custom {@link Notification}. */
+ @NonNull
+ public Builder addActions(@NonNull List<Action> actions) {
+ mActions.addAll(requireNonNull(actions));
+ return this;
+ }
+
+ /** Clears all the {@link Action}s that were added so far. */
+ @NonNull
+ public Builder clearActions() {
+ mActions.clear();
+ return this;
+ }
+
+ /** Builds a {@link Notification} instance. */
+ @NonNull
+ public Notification build() {
+ List<Action> actions = unmodifiableList(new ArrayList<>(mActions));
+ Action.enforceUniqueActionIds(
+ actions, "Custom notification cannot have duplicate action ids");
+ checkArgument(
+ actions.size() <= 2,
+ "Custom notification must not contain more than 2 actions");
+ return new Notification(mTitle, mText, actions);
}
}
}
@@ -525,6 +1198,18 @@ public final class SafetySourceIssue implements Parcelable {
@Nullable private CharSequence mSubtitle;
@IssueCategory private int mIssueCategory = ISSUE_CATEGORY_GENERAL;
@Nullable private PendingIntent mOnDismissPendingIntent;
+ @Nullable private CharSequence mAttributionTitle;
+ @Nullable private String mDeduplicationId;
+
+ @Nullable private Notification mCustomNotification = null;
+
+ @SuppressLint("NewApi")
+ @NotificationBehavior
+ private int mNotificationBehavior = NOTIFICATION_BEHAVIOR_UNSPECIFIED;
+
+ @SuppressLint("NewApi")
+ @IssueActionability
+ private int mIssueActionability = ISSUE_ACTIONABILITY_MANUAL;
/** Creates a {@link Builder} for a {@link SafetySourceIssue}. */
public Builder(
@@ -540,6 +1225,29 @@ public final class SafetySourceIssue implements Parcelable {
this.mIssueTypeId = requireNonNull(issueTypeId);
}
+ /** Creates a {@link Builder} with the values from the given {@link SafetySourceIssue}. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder(@NonNull SafetySourceIssue safetySourceIssue) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ requireNonNull(safetySourceIssue);
+ mId = safetySourceIssue.mId;
+ mTitle = safetySourceIssue.mTitle;
+ mSummary = safetySourceIssue.mSummary;
+ mSeverityLevel = safetySourceIssue.mSeverityLevel;
+ mIssueTypeId = safetySourceIssue.mIssueTypeId;
+ mActions.addAll(safetySourceIssue.mActions);
+ mSubtitle = safetySourceIssue.mSubtitle;
+ mIssueCategory = safetySourceIssue.mIssueCategory;
+ mOnDismissPendingIntent = safetySourceIssue.mOnDismissPendingIntent;
+ mAttributionTitle = safetySourceIssue.mAttributionTitle;
+ mDeduplicationId = safetySourceIssue.mDeduplicationId;
+ mCustomNotification = safetySourceIssue.mCustomNotification;
+ mNotificationBehavior = safetySourceIssue.mNotificationBehavior;
+ mIssueActionability = safetySourceIssue.mIssueActionability;
+ }
+
/** Sets the localized subtitle. */
@NonNull
public Builder setSubtitle(@Nullable CharSequence subtitle) {
@@ -548,6 +1256,23 @@ public final class SafetySourceIssue implements Parcelable {
}
/**
+ * Sets or clears the optional attribution title for this issue.
+ *
+ * <p>This is displayed in the UI and helps to attribute an issue to a particular source. If
+ * this value is {@code null}, the title of the group that contains the Safety Source will
+ * be used.
+ */
+ @NonNull
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public Builder setAttributionTitle(@Nullable CharSequence attributionTitle) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ mAttributionTitle = attributionTitle;
+ return this;
+ }
+
+ /**
* Sets the category of the risk associated with the issue.
*
* <p>The default category will be {@link #ISSUE_CATEGORY_GENERAL}.
@@ -591,11 +1316,98 @@ public final class SafetySourceIssue implements Parcelable {
return this;
}
+ /**
+ * Sets a custom {@link Notification} for this issue.
+ *
+ * <p>Using a custom {@link Notification} a source may specify a different {@link
+ * Notification#getTitle()}, {@link Notification#getText()} and {@link
+ * Notification#getActions()} for Safety Center to use when constructing a notification for
+ * this issue.
+ *
+ * <p>Safety Center may still generate a default notification from the other details of this
+ * issue when no custom notification has been set, depending on the issue's {@link
+ * #getNotificationBehavior()}.
+ *
+ * @see #getCustomNotification()
+ * @see #setNotificationBehavior(int)
+ */
+ @NonNull
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder setCustomNotification(@Nullable Notification customNotification) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ mCustomNotification = customNotification;
+ return this;
+ }
+
+ /**
+ * Sets the notification behavior of the issue.
+ *
+ * <p>Must be one of {@link #NOTIFICATION_BEHAVIOR_UNSPECIFIED}, {@link
+ * #NOTIFICATION_BEHAVIOR_NEVER}, {@link #NOTIFICATION_BEHAVIOR_DELAYED} or {@link
+ * #NOTIFICATION_BEHAVIOR_IMMEDIATELY}. See {@link #getNotificationBehavior()} for details
+ * of how Safety Center will interpret each of these.
+ *
+ * @see #getNotificationBehavior()
+ */
+ @NonNull
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder setNotificationBehavior(@NotificationBehavior int notificationBehavior) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ mNotificationBehavior = validateNotificationBehavior(notificationBehavior);
+ return this;
+ }
+
+ /**
+ * Sets the deduplication identifier for the issue.
+ *
+ * @see #getDeduplicationId()
+ */
+ @NonNull
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder setDeduplicationId(@Nullable String deduplicationId) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ mDeduplicationId = deduplicationId;
+ return this;
+ }
+
+ /**
+ * Sets the issue actionability of the issue.
+ *
+ * <p>Must be one of {@link #ISSUE_ACTIONABILITY_MANUAL} (default), {@link
+ * #ISSUE_ACTIONABILITY_TIP}, {@link #ISSUE_ACTIONABILITY_AUTOMATIC}.
+ *
+ * @see #getIssueActionability()
+ */
+ @NonNull
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder setIssueActionability(@IssueActionability int issueActionability) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ mIssueActionability = validateIssueActionability(issueActionability);
+ return this;
+ }
+
/** Creates the {@link SafetySourceIssue} defined by this {@link Builder}. */
@NonNull
public SafetySourceIssue build() {
List<SafetySourceIssue.Action> actions = unmodifiableList(new ArrayList<>(mActions));
- checkArgument(!actions.isEmpty(), "Safety source issue must contain at least 1 action");
+ Action.enforceUniqueActionIds(
+ actions, "Safety source issue cannot have duplicate action ids");
+ if (SdkLevel.isAtLeastU()) {
+ checkArgument(
+ mIssueActionability != ISSUE_ACTIONABILITY_MANUAL || !actions.isEmpty(),
+ "Actionable safety source issue must contain at least 1 action");
+ } else {
+ checkArgument(
+ !actions.isEmpty(), "Safety source issue must contain at least 1 action");
+ }
checkArgument(
actions.size() <= 2,
"Safety source issue must not contain more than 2 actions");
@@ -608,7 +1420,12 @@ public final class SafetySourceIssue implements Parcelable {
mIssueCategory,
actions,
mOnDismissPendingIntent,
- mIssueTypeId);
+ mIssueTypeId,
+ mCustomNotification,
+ mNotificationBehavior,
+ mAttributionTitle,
+ mDeduplicationId,
+ mIssueActionability);
}
}
@@ -626,7 +1443,7 @@ public final class SafetySourceIssue implements Parcelable {
default:
}
throw new IllegalArgumentException(
- String.format("Unexpected SeverityLevel for SafetySourceIssue: %s", value));
+ "Unexpected SeverityLevel for SafetySourceIssue: " + value);
}
@IssueCategory
@@ -638,7 +1455,43 @@ public final class SafetySourceIssue implements Parcelable {
return value;
default:
}
+ if (SdkLevel.isAtLeastU()) {
+ switch (value) {
+ case ISSUE_CATEGORY_DATA:
+ case ISSUE_CATEGORY_PASSWORDS:
+ case ISSUE_CATEGORY_PERSONAL_SAFETY:
+ return value;
+ default:
+ }
+ }
+ throw new IllegalArgumentException(
+ "Unexpected IssueCategory for SafetySourceIssue: " + value);
+ }
+
+ @NotificationBehavior
+ private static int validateNotificationBehavior(int value) {
+ switch (value) {
+ case NOTIFICATION_BEHAVIOR_UNSPECIFIED:
+ case NOTIFICATION_BEHAVIOR_NEVER:
+ case NOTIFICATION_BEHAVIOR_DELAYED:
+ case NOTIFICATION_BEHAVIOR_IMMEDIATELY:
+ return value;
+ default:
+ }
+ throw new IllegalArgumentException(
+ "Unexpected NotificationBehavior for SafetySourceIssue: " + value);
+ }
+
+ @IssueActionability
+ private static int validateIssueActionability(int value) {
+ switch (value) {
+ case ISSUE_ACTIONABILITY_MANUAL:
+ case ISSUE_ACTIONABILITY_TIP:
+ case ISSUE_ACTIONABILITY_AUTOMATIC:
+ return value;
+ default:
+ }
throw new IllegalArgumentException(
- String.format("Unexpected IssueCategory for SafetySourceIssue: %s", value));
+ "Unexpected IssueActionability for SafetySourceIssue: " + value);
}
}
diff --git a/framework-s/java/android/safetycenter/SafetySourceStatus.java b/framework-s/java/android/safetycenter/SafetySourceStatus.java
index 9817df01c..37095eb59 100644
--- a/framework-s/java/android/safetycenter/SafetySourceStatus.java
+++ b/framework-s/java/android/safetycenter/SafetySourceStatus.java
@@ -17,6 +17,7 @@
package android.safetycenter;
import static android.os.Build.VERSION_CODES.TIRAMISU;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static com.android.internal.util.Preconditions.checkArgument;
@@ -33,6 +34,8 @@ import android.text.TextUtils;
import androidx.annotation.RequiresApi;
+import com.android.modules.utils.build.SdkLevel;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
@@ -208,10 +211,7 @@ public final class SafetySourceStatus implements Parcelable {
* <p>The action will be shown as a clickable icon chosen from a predefined set of icons (see
* {@link IconType}). The icon should indicate to the user what action will be performed on
* clicking on it.
- *
- * @hide
*/
- @SystemApi
public static final class IconAction implements Parcelable {
@NonNull
@@ -319,8 +319,7 @@ public final class SafetySourceStatus implements Parcelable {
return value;
default:
}
- throw new IllegalArgumentException(
- String.format("Unexpected IconType for IconAction: %s", value));
+ throw new IllegalArgumentException("Unexpected IconType for IconAction: " + value);
}
}
@@ -345,6 +344,21 @@ public final class SafetySourceStatus implements Parcelable {
this.mSeverityLevel = validateSeverityLevel(severityLevel);
}
+ /** Creates a {@link Builder} with the values of the given {@link SafetySourceStatus}. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder(@NonNull SafetySourceStatus safetySourceStatus) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ requireNonNull(safetySourceStatus);
+ mTitle = safetySourceStatus.mTitle;
+ mSummary = safetySourceStatus.mSummary;
+ mSeverityLevel = safetySourceStatus.mSeverityLevel;
+ mPendingIntent = safetySourceStatus.mPendingIntent;
+ mIconAction = safetySourceStatus.mIconAction;
+ mEnabled = safetySourceStatus.mEnabled;
+ }
+
/**
* Sets an optional {@link PendingIntent} for the safety source status.
*
@@ -409,6 +423,6 @@ public final class SafetySourceStatus implements Parcelable {
default:
}
throw new IllegalArgumentException(
- String.format("Unexpected SeverityLevel for SafetySourceStatus: %s", value));
+ "Unexpected SeverityLevel for SafetySourceStatus: " + value);
}
}
diff --git a/framework-s/java/android/safetycenter/TEST_MAPPING b/framework-s/java/android/safetycenter/TEST_MAPPING
index 3985e563c..3cad386bc 100644
--- a/framework-s/java/android/safetycenter/TEST_MAPPING
+++ b/framework-s/java/android/safetycenter/TEST_MAPPING
@@ -1,7 +1,7 @@
{
- "presubmit": [
+ "imports": [
{
- "name": "CtsSafetyCenterTestCases"
+ "path": "packages/modules/Permission/SafetyCenter"
}
]
}
diff --git a/framework-s/java/android/safetycenter/config/BuilderUtils.java b/framework-s/java/android/safetycenter/config/BuilderUtils.java
index b8b6e276f..b6ccced62 100644
--- a/framework-s/java/android/safetycenter/config/BuilderUtils.java
+++ b/framework-s/java/android/safetycenter/config/BuilderUtils.java
@@ -25,7 +25,9 @@ import android.content.res.Resources;
import androidx.annotation.RequiresApi;
+import java.util.Collection;
import java.util.Objects;
+import java.util.regex.Pattern;
@RequiresApi(TIRAMISU)
final class BuilderUtils {
@@ -39,12 +41,12 @@ final class BuilderUtils {
boolean prohibited,
@Nullable Object defaultValue) {
if (attribute == null && required) {
- throw new IllegalStateException(String.format("Required attribute %s missing", name));
+ throwRequiredAttributeMissing(name);
}
boolean nonDefaultValueProvided = !Objects.equals(attribute, defaultValue);
boolean checkProhibited = prohibited && nonDefaultValueProvided;
if (attribute != null && checkProhibited) {
- throw new IllegalStateException(String.format("Prohibited attribute %s present", name));
+ throwProhibitedAttributePresent(name);
}
}
@@ -56,6 +58,17 @@ final class BuilderUtils {
validateAttribute(attribute, name, required, prohibited, null);
}
+ static void validateId(
+ @Nullable String id,
+ @NonNull String name,
+ boolean required,
+ boolean prohibited) {
+ validateAttribute(id, name, required, prohibited, null);
+ if (!Pattern.compile("[0-9a-zA-Z_]+").matcher(id).matches()) {
+ throw new IllegalStateException("Attribute " + name + " invalid");
+ }
+ }
+
@AnyRes
static int validateResId(
@Nullable @AnyRes Integer value,
@@ -67,7 +80,7 @@ final class BuilderUtils {
return Resources.ID_NULL;
}
if (required && value == Resources.ID_NULL) {
- throw new IllegalStateException(String.format("Required attribute %s invalid", name));
+ throwRequiredAttributeInvalid(name);
}
return value;
}
@@ -89,7 +102,7 @@ final class BuilderUtils {
found |= (value == validValues[i]);
}
if (!found) {
- throw new IllegalStateException(String.format("Attribute %s invalid", name));
+ throw new IllegalStateException("Attribute " + name + " invalid");
}
return value;
}
@@ -119,4 +132,37 @@ final class BuilderUtils {
}
return value;
}
+
+ /**
+ * Validates a collection argument from a builder.
+ *
+ * <ul>
+ * <li>If {@code required}, a non-empty collection must be supplied.
+ * <li>If {@code prohibited}, an empty collection must be supplied.
+ * </ul>
+ */
+ static <T> void validateCollection(
+ @NonNull Collection<T> value,
+ @NonNull String name,
+ boolean required,
+ boolean prohibited) {
+ if (value.isEmpty() && required) {
+ throwRequiredAttributeMissing(name);
+ }
+ if (!value.isEmpty() && prohibited) {
+ throwProhibitedAttributePresent(name);
+ }
+ }
+
+ static void throwRequiredAttributeMissing(@NonNull String attribute) {
+ throw new IllegalStateException("Required attribute " + attribute + " missing");
+ }
+
+ static void throwProhibitedAttributePresent(@NonNull String attribute) {
+ throw new IllegalStateException("Prohibited attribute " + attribute + " present");
+ }
+
+ static void throwRequiredAttributeInvalid(@NonNull String attribute) {
+ throw new IllegalStateException("Required attribute " + attribute + " invalid");
+ }
}
diff --git a/framework-s/java/android/safetycenter/config/SafetyCenterConfig.java b/framework-s/java/android/safetycenter/config/SafetyCenterConfig.java
index de5518fd8..c94cedbd6 100644
--- a/framework-s/java/android/safetycenter/config/SafetyCenterConfig.java
+++ b/framework-s/java/android/safetycenter/config/SafetyCenterConfig.java
@@ -17,6 +17,7 @@
package android.safetycenter.config;
import static android.os.Build.VERSION_CODES.TIRAMISU;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static java.util.Collections.unmodifiableList;
import static java.util.Objects.requireNonNull;
@@ -28,6 +29,8 @@ import android.os.Parcelable;
import androidx.annotation.RequiresApi;
+import com.android.modules.utils.build.SdkLevel;
+
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -115,6 +118,16 @@ public final class SafetyCenterConfig implements Parcelable {
/** Creates a {@link Builder} for a {@link SafetyCenterConfig}. */
public Builder() {}
+ /** Creates a {@link Builder} with the values from the given {@link SafetyCenterConfig}. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder(@NonNull SafetyCenterConfig safetyCenterConfig) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ requireNonNull(safetyCenterConfig);
+ mSafetySourcesGroups.addAll(safetyCenterConfig.mSafetySourcesGroups);
+ }
+
/**
* Adds a {@link SafetySourcesGroup} to the Safety Center configuration.
*
@@ -129,8 +142,8 @@ public final class SafetyCenterConfig implements Parcelable {
/**
* Creates the {@link SafetyCenterConfig} defined by this {@link Builder}.
*
- * <p>Throws an {@link IllegalStateException} if any constraint on the Safety Center
- * configuration is violated.
+ * @throws IllegalStateException if any constraint on the Safety Center configuration is
+ * violated
*/
@NonNull
public SafetyCenterConfig build() {
@@ -147,7 +160,7 @@ public final class SafetyCenterConfig implements Parcelable {
String groupId = safetySourcesGroup.getId();
if (safetySourcesGroupsIds.contains(groupId)) {
throw new IllegalStateException(
- String.format("Duplicate id %s among safety sources groups", groupId));
+ "Duplicate id " + groupId + " among safety sources groups");
}
safetySourcesGroupsIds.add(groupId);
List<SafetySource> safetySources = safetySourcesGroup.getSafetySources();
@@ -157,7 +170,7 @@ public final class SafetyCenterConfig implements Parcelable {
String sourceId = staticSafetySource.getId();
if (safetySourceIds.contains(sourceId)) {
throw new IllegalStateException(
- String.format("Duplicate id %s among safety sources", sourceId));
+ "Duplicate id " + sourceId + " among safety sources");
}
safetySourceIds.add(sourceId);
}
diff --git a/framework-s/java/android/safetycenter/config/SafetySource.java b/framework-s/java/android/safetycenter/config/SafetySource.java
index 6734331c1..fddb8b622 100644
--- a/framework-s/java/android/safetycenter/config/SafetySource.java
+++ b/framework-s/java/android/safetycenter/config/SafetySource.java
@@ -17,6 +17,9 @@
package android.safetycenter.config;
import static android.os.Build.VERSION_CODES.TIRAMISU;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+
+import static java.util.Objects.requireNonNull;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -26,12 +29,17 @@ import android.annotation.SystemApi;
import android.content.res.Resources;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.ArraySet;
import androidx.annotation.RequiresApi;
+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.Set;
/**
* Data class used to represent the initial configuration of a safety source.
@@ -152,20 +160,29 @@ public final class SafetySource implements Parcelable {
@Override
public SafetySource createFromParcel(Parcel in) {
int type = in.readInt();
- return new Builder(type)
- .setId(in.readString())
- .setPackageName(in.readString())
- .setTitleResId(in.readInt())
- .setTitleForWorkResId(in.readInt())
- .setSummaryResId(in.readInt())
- .setIntentAction(in.readString())
- .setProfile(in.readInt())
- .setInitialDisplayState(in.readInt())
- .setMaxSeverityLevel(in.readInt())
- .setSearchTermsResId(in.readInt())
- .setLoggingAllowed(in.readBoolean())
- .setRefreshOnPageOpenAllowed(in.readBoolean())
- .build();
+ Builder builder =
+ new Builder(type)
+ .setId(in.readString())
+ .setPackageName(in.readString())
+ .setTitleResId(in.readInt())
+ .setTitleForWorkResId(in.readInt())
+ .setSummaryResId(in.readInt())
+ .setIntentAction(in.readString())
+ .setProfile(in.readInt())
+ .setInitialDisplayState(in.readInt())
+ .setMaxSeverityLevel(in.readInt())
+ .setSearchTermsResId(in.readInt())
+ .setLoggingAllowed(in.readBoolean())
+ .setRefreshOnPageOpenAllowed(in.readBoolean());
+ if (SdkLevel.isAtLeastU()) {
+ builder.setNotificationsAllowed(in.readBoolean());
+ builder.setDeduplicationGroup(in.readString());
+ List<String> certs = in.createStringArrayList();
+ for (int i = 0; i < certs.size(); i++) {
+ builder.addPackageCertificateHash(certs.get(i));
+ }
+ }
+ return builder.build();
}
@Override
@@ -187,6 +204,9 @@ public final class SafetySource implements Parcelable {
@StringRes private final int mSearchTermsResId;
private final boolean mLoggingAllowed;
private final boolean mRefreshOnPageOpenAllowed;
+ private final boolean mNotificationsAllowed;
+ @Nullable final String mDeduplicationGroup;
+ @NonNull private final Set<String> mPackageCertificateHashes;
private SafetySource(
@SafetySourceType int type,
@@ -201,7 +221,10 @@ public final class SafetySource implements Parcelable {
int maxSeverityLevel,
@StringRes int searchTermsResId,
boolean loggingAllowed,
- boolean refreshOnPageOpenAllowed) {
+ boolean refreshOnPageOpenAllowed,
+ boolean notificationsAllowed,
+ @Nullable String deduplicationGroup,
+ @NonNull Set<String> packageCertificateHashes) {
mType = type;
mId = id;
mPackageName = packageName;
@@ -215,6 +238,9 @@ public final class SafetySource implements Parcelable {
mSearchTermsResId = searchTermsResId;
mLoggingAllowed = loggingAllowed;
mRefreshOnPageOpenAllowed = refreshOnPageOpenAllowed;
+ mNotificationsAllowed = notificationsAllowed;
+ mDeduplicationGroup = deduplicationGroup;
+ mPackageCertificateHashes = Set.copyOf(packageCertificateHashes);
}
/** Returns the type of this safety source. */
@@ -236,10 +262,14 @@ public final class SafetySource implements Parcelable {
/**
* Returns the package name of this safety source.
*
- * <p>This is the package that owns the source. The package will receive refresh requests and it
- * can send set requests for the source.
+ * <p>This is the package that owns the source. The package will receive refresh requests, and
+ * it can send set requests for the source. The package is also used to create an explicit
+ * pending intent from the intent action in the package context.
*
- * <p>Throws an {@link UnsupportedOperationException} if the source is of type static.
+ * @throws UnsupportedOperationException if the source is of type {@link
+ * SafetySource#SAFETY_SOURCE_TYPE_STATIC} even if the optional package name field for the
+ * source is set, for sources of type {@link SafetySource#SAFETY_SOURCE_TYPE_STATIC} use
+ * {@link SafetySource#getOptionalPackageName()}
*/
@NonNull
public String getPackageName() {
@@ -251,13 +281,36 @@ public final class SafetySource implements Parcelable {
}
/**
+ * Returns the package name of this safety source or null if undefined.
+ *
+ * <p>This is the package that owns the source.
+ *
+ * <p>The package is always defined for sources of type dynamic and issue-only. The package will
+ * receive refresh requests, and it can send set requests for sources of type dynamic and
+ * issue-only. The package is also used to create an explicit pending intent in the package
+ * context from the intent action if defined.
+ *
+ * <p>The package is optional for sources of type static. If present, the package is used to
+ * create an explicit pending intent in the package context from the intent action.
+ */
+ @Nullable
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public String getOptionalPackageName() {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ return mPackageName;
+ }
+
+ /**
* Returns the resource id of the title of this safety source.
*
* <p>The id refers to a string resource that is either accessible from any resource context or
* that is accessible from the same resource context that was used to load the Safety Center
* configuration. The id is {@link Resources#ID_NULL} when a title is not provided.
*
- * <p>Throws an {@link UnsupportedOperationException} if the source is of type issue-only.
+ * @throws UnsupportedOperationException if the source is of type {@link
+ * SafetySource#SAFETY_SOURCE_TYPE_ISSUE_ONLY}
*/
@StringRes
public int getTitleResId() {
@@ -275,8 +328,9 @@ public final class SafetySource implements Parcelable {
* that is accessible from the same resource context that was used to load the Safety Center
* configuration. The id is {@link Resources#ID_NULL} when a title for work is not provided.
*
- * <p>Throws an {@link UnsupportedOperationException} if the source is of type issue-only or if
- * the profile property of the source is set to {@link SafetySource#PROFILE_PRIMARY}.
+ * @throws UnsupportedOperationException if the source is of type {@link
+ * SafetySource#SAFETY_SOURCE_TYPE_ISSUE_ONLY} or if the profile property of the source is
+ * set to {@link SafetySource#PROFILE_PRIMARY}
*/
@StringRes
public int getTitleForWorkResId() {
@@ -298,7 +352,8 @@ public final class SafetySource implements Parcelable {
* that is accessible from the same resource context that was used to load the Safety Center
* configuration. The id is {@link Resources#ID_NULL} when a summary is not provided.
*
- * <p>Throws an {@link UnsupportedOperationException} if the source is of type issue-only.
+ * @throws UnsupportedOperationException if the source is of type {@link
+ * SafetySource#SAFETY_SOURCE_TYPE_ISSUE_ONLY}
*/
@StringRes
public int getSummaryResId() {
@@ -316,7 +371,8 @@ public final class SafetySource implements Parcelable {
* source is displayed as an entry in the Safety Center page, and if the action is set to {@code
* null} or if it does not resolve to an activity the source will be marked as disabled.
*
- * <p>Throws an {@link UnsupportedOperationException} if the source is of type issue-only.
+ * @throws UnsupportedOperationException if the source is of type {@link
+ * SafetySource#SAFETY_SOURCE_TYPE_ISSUE_ONLY}
*/
@Nullable
public String getIntentAction() {
@@ -336,8 +392,9 @@ public final class SafetySource implements Parcelable {
/**
* Returns the initial display state of this safety source.
*
- * <p>Throws an {@link UnsupportedOperationException} if the source is of type static or
- * issue-only.
+ * @throws UnsupportedOperationException if the source is of type {@link
+ * SafetySource#SAFETY_SOURCE_TYPE_STATIC} or {@link
+ * SafetySource#SAFETY_SOURCE_TYPE_ISSUE_ONLY}
*/
@InitialDisplayState
public int getInitialDisplayState() {
@@ -361,7 +418,8 @@ public final class SafetySource implements Parcelable {
* android.safetycenter.SafetySourceData#SEVERITY_LEVEL_INFORMATION} even if the maximum
* severity level is set to a lower value.
*
- * <p>Throws an {@link UnsupportedOperationException} if the source is of type static.
+ * @throws UnsupportedOperationException if the source is of type {@link
+ * SafetySource#SAFETY_SOURCE_TYPE_STATIC}
*/
public int getMaxSeverityLevel() {
if (mType == SAFETY_SOURCE_TYPE_STATIC) {
@@ -378,7 +436,8 @@ public final class SafetySource implements Parcelable {
* that is accessible from the same resource context that was used to load the Safety Center
* configuration. The id is {@link Resources#ID_NULL} when search terms are not provided.
*
- * <p>Throws an {@link UnsupportedOperationException} if the source is of type issue-only.
+ * @throws UnsupportedOperationException if the source is of type {@link
+ * SafetySource#SAFETY_SOURCE_TYPE_ISSUE_ONLY}
*/
@StringRes
public int getSearchTermsResId() {
@@ -392,7 +451,8 @@ public final class SafetySource implements Parcelable {
/**
* Returns the logging allowed property of this safety source.
*
- * <p>Throws an {@link UnsupportedOperationException} if the source is of type static.
+ * @throws UnsupportedOperationException if the source is of type {@link
+ * SafetySource#SAFETY_SOURCE_TYPE_STATIC}
*/
public boolean isLoggingAllowed() {
if (mType == SAFETY_SOURCE_TYPE_STATIC) {
@@ -408,7 +468,8 @@ public final class SafetySource implements Parcelable {
* <p>If set to {@code true}, a refresh request will be sent to the source when the Safety
* Center page is opened.
*
- * <p>Throws an {@link UnsupportedOperationException} if the source is of type static.
+ * @throws UnsupportedOperationException if the source is of type {@link
+ * SafetySource#SAFETY_SOURCE_TYPE_STATIC}
*/
public boolean isRefreshOnPageOpenAllowed() {
if (mType == SAFETY_SOURCE_TYPE_STATIC) {
@@ -418,6 +479,57 @@ public final class SafetySource implements Parcelable {
return mRefreshOnPageOpenAllowed;
}
+ /**
+ * Returns whether Safety Center may post Notifications about issues reported by this {@link
+ * SafetySource}.
+ *
+ * @see Builder#setNotificationsAllowed(boolean)
+ */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public boolean areNotificationsAllowed() {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ return mNotificationsAllowed;
+ }
+
+ /**
+ * Returns the deduplication group this source belongs to.
+ *
+ * <p>Sources which are part of the same deduplication group can coordinate to deduplicate their
+ * issues.
+ */
+ @Nullable
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public String getDeduplicationGroup() {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ return mDeduplicationGroup;
+ }
+
+ /**
+ * Returns a set of package certificate hashes representing valid signed packages that represent
+ * this {@link SafetySource}.
+ *
+ * <p>If one or more certificate hashes are set, Safety Center will validate that a package
+ * calling {@link android.safetycenter.SafetyCenterManager#setSafetySourceData} is signed with
+ * one of the certificates provided.
+ *
+ * <p>The default value is an empty {@code Set}, in which case only the package name is
+ * validated.
+ *
+ * @see Builder#addPackageCertificateHash(String)
+ */
+ @NonNull
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Set<String> getPackageCertificateHashes() {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ return mPackageCertificateHashes;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -435,7 +547,10 @@ public final class SafetySource implements Parcelable {
&& mMaxSeverityLevel == that.mMaxSeverityLevel
&& mSearchTermsResId == that.mSearchTermsResId
&& mLoggingAllowed == that.mLoggingAllowed
- && mRefreshOnPageOpenAllowed == that.mRefreshOnPageOpenAllowed;
+ && mRefreshOnPageOpenAllowed == that.mRefreshOnPageOpenAllowed
+ && mNotificationsAllowed == that.mNotificationsAllowed
+ && Objects.equals(mDeduplicationGroup, that.mDeduplicationGroup)
+ && Objects.equals(mPackageCertificateHashes, that.mPackageCertificateHashes);
}
@Override
@@ -453,7 +568,10 @@ public final class SafetySource implements Parcelable {
mMaxSeverityLevel,
mSearchTermsResId,
mLoggingAllowed,
- mRefreshOnPageOpenAllowed);
+ mRefreshOnPageOpenAllowed,
+ mNotificationsAllowed,
+ mDeduplicationGroup,
+ mPackageCertificateHashes);
}
@Override
@@ -461,21 +579,18 @@ public final class SafetySource implements Parcelable {
return "SafetySource{"
+ "mType="
+ mType
- + ", mId='"
+ + ", mId="
+ mId
- + '\''
- + ", mPackageName='"
+ + ", mPackageName="
+ mPackageName
- + '\''
+ ", mTitleResId="
+ mTitleResId
+ ", mTitleForWorkResId="
+ mTitleForWorkResId
+ ", mSummaryResId="
+ mSummaryResId
- + ", mIntentAction='"
+ + ", mIntentAction="
+ mIntentAction
- + '\''
+ ", mProfile="
+ mProfile
+ ", mInitialDisplayState="
@@ -488,6 +603,12 @@ public final class SafetySource implements Parcelable {
+ mLoggingAllowed
+ ", mRefreshOnPageOpenAllowed="
+ mRefreshOnPageOpenAllowed
+ + ", mNotificationsAllowed="
+ + mNotificationsAllowed
+ + ", mDeduplicationGroup="
+ + mDeduplicationGroup
+ + ", mPackageCertificateHashes="
+ + mPackageCertificateHashes
+ '}';
}
@@ -511,6 +632,11 @@ public final class SafetySource implements Parcelable {
dest.writeInt(mSearchTermsResId);
dest.writeBoolean(mLoggingAllowed);
dest.writeBoolean(mRefreshOnPageOpenAllowed);
+ if (SdkLevel.isAtLeastU()) {
+ dest.writeBoolean(mNotificationsAllowed);
+ dest.writeString(mDeduplicationGroup);
+ dest.writeStringList(List.copyOf(mPackageCertificateHashes));
+ }
}
/** Builder class for {@link SafetySource}. */
@@ -529,12 +655,40 @@ public final class SafetySource implements Parcelable {
@Nullable @StringRes private Integer mSearchTermsResId;
@Nullable private Boolean mLoggingAllowed;
@Nullable private Boolean mRefreshOnPageOpenAllowed;
+ @Nullable private Boolean mNotificationsAllowed;
+ @Nullable private String mDeduplicationGroup;
+ @NonNull private final ArraySet<String> mPackageCertificateHashes = new ArraySet<>();
/** Creates a {@link Builder} for a {@link SafetySource}. */
public Builder(@SafetySourceType int type) {
mType = type;
}
+ /** Creates a {@link Builder} with the values from the given {@link SafetySource}. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder(@NonNull SafetySource safetySource) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ requireNonNull(safetySource);
+ mType = safetySource.mType;
+ mId = safetySource.mId;
+ mPackageName = safetySource.mPackageName;
+ mTitleResId = safetySource.mTitleResId;
+ mTitleForWorkResId = safetySource.mTitleForWorkResId;
+ mSummaryResId = safetySource.mSummaryResId;
+ mIntentAction = safetySource.mIntentAction;
+ mProfile = safetySource.mProfile;
+ mInitialDisplayState = safetySource.mInitialDisplayState;
+ mMaxSeverityLevel = safetySource.mMaxSeverityLevel;
+ mSearchTermsResId = safetySource.mSearchTermsResId;
+ mLoggingAllowed = safetySource.mLoggingAllowed;
+ mRefreshOnPageOpenAllowed = safetySource.mRefreshOnPageOpenAllowed;
+ mNotificationsAllowed = safetySource.mNotificationsAllowed;
+ mDeduplicationGroup = safetySource.mDeduplicationGroup;
+ mPackageCertificateHashes.addAll(safetySource.mPackageCertificateHashes);
+ }
+
/**
* Sets the id of this safety source.
*
@@ -717,6 +871,61 @@ public final class SafetySource implements Parcelable {
}
/**
+ * Sets the {@link #areNotificationsAllowed()} property of this {@link SafetySource}.
+ *
+ * <p>If set to {@code true} Safety Center may post Notifications about issues reported by
+ * this source.
+ *
+ * <p>The default value is {@code false}.
+ *
+ * @see #areNotificationsAllowed()
+ */
+ @NonNull
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder setNotificationsAllowed(boolean notificationsAllowed) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ mNotificationsAllowed = notificationsAllowed;
+ return this;
+ }
+
+ /**
+ * Sets the deduplication group for this source.
+ *
+ * <p>Sources which are part of the same deduplication group can coordinate to deduplicate
+ * issues that they're sending to SafetyCenter by providing the same deduplication
+ * identifier with those issues.
+ *
+ * <p>The deduplication group property is prohibited for sources of type static.
+ */
+ @NonNull
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder setDeduplicationGroup(@Nullable String deduplicationGroup) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ mDeduplicationGroup = deduplicationGroup;
+ return this;
+ }
+
+ /**
+ * Adds a package certificate hash to the {@link #getPackageCertificateHashes()} property of
+ * this {@link SafetySource}.
+ *
+ * @see #getPackageCertificateHashes()
+ */
+ @NonNull
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder addPackageCertificateHash(@NonNull String packageCertificateHash) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ mPackageCertificateHashes.add(packageCertificateHash);
+ return this;
+ }
+
+ /**
* Creates the {@link SafetySource} defined by this {@link Builder}.
*
* <p>Throws an {@link IllegalStateException} if any constraint on the safety source is
@@ -724,19 +933,25 @@ public final class SafetySource implements Parcelable {
*/
@NonNull
public SafetySource build() {
- if (mType != SAFETY_SOURCE_TYPE_STATIC
- && mType != SAFETY_SOURCE_TYPE_DYNAMIC
- && mType != SAFETY_SOURCE_TYPE_ISSUE_ONLY) {
+ int type = mType;
+ if (type != SAFETY_SOURCE_TYPE_STATIC
+ && type != SAFETY_SOURCE_TYPE_DYNAMIC
+ && type != SAFETY_SOURCE_TYPE_ISSUE_ONLY) {
throw new IllegalStateException("Unexpected type");
}
- boolean isStatic = mType == SAFETY_SOURCE_TYPE_STATIC;
- boolean isDynamic = mType == SAFETY_SOURCE_TYPE_DYNAMIC;
- boolean isIssueOnly = mType == SAFETY_SOURCE_TYPE_ISSUE_ONLY;
+ boolean isStatic = type == SAFETY_SOURCE_TYPE_STATIC;
+ boolean isDynamic = type == SAFETY_SOURCE_TYPE_DYNAMIC;
+ boolean isIssueOnly = type == SAFETY_SOURCE_TYPE_ISSUE_ONLY;
- BuilderUtils.validateAttribute(mId, "id", true, false);
+ String id = mId;
+ BuilderUtils.validateId(id, "id", true, false);
+ String packageName = mPackageName;
BuilderUtils.validateAttribute(
- mPackageName, "packageName", isDynamic || isIssueOnly, isStatic);
+ packageName,
+ "packageName",
+ isDynamic || isIssueOnly,
+ isStatic && !SdkLevel.isAtLeastU());
int initialDisplayState =
BuilderUtils.validateIntDef(
@@ -784,8 +999,9 @@ public final class SafetySource implements Parcelable {
BuilderUtils.validateResId(
mSummaryResId, "summary", isDynamicNotHidden, isIssueOnly);
+ String intentAction = mIntentAction;
BuilderUtils.validateAttribute(
- mIntentAction,
+ intentAction,
"intentAction",
(isDynamic && isEnabled) || isStatic,
isIssueOnly);
@@ -810,20 +1026,41 @@ public final class SafetySource implements Parcelable {
isStatic,
false);
+ String deduplicationGroup = mDeduplicationGroup;
+ boolean notificationsAllowed = false;
+ Set<String> packageCertificateHashes = Set.copyOf(mPackageCertificateHashes);
+ if (SdkLevel.isAtLeastU()) {
+ notificationsAllowed =
+ BuilderUtils.validateBoolean(
+ mNotificationsAllowed,
+ "notificationsAllowed",
+ false,
+ isStatic,
+ false);
+
+ BuilderUtils.validateAttribute(
+ deduplicationGroup, "deduplicationGroup", false, isStatic);
+ BuilderUtils.validateCollection(
+ packageCertificateHashes, "packageCertificateHashes", false, isStatic);
+ }
+
return new SafetySource(
- mType,
- mId,
- mPackageName,
+ type,
+ id,
+ packageName,
titleResId,
titleForWorkResId,
summaryResId,
- mIntentAction,
+ intentAction,
profile,
initialDisplayState,
maxSeverityLevel,
searchTermsResId,
loggingAllowed,
- refreshOnPageOpenAllowed);
+ refreshOnPageOpenAllowed,
+ notificationsAllowed,
+ deduplicationGroup,
+ packageCertificateHashes);
}
}
}
diff --git a/framework-s/java/android/safetycenter/config/SafetySourcesGroup.java b/framework-s/java/android/safetycenter/config/SafetySourcesGroup.java
index 5c5b58f58..1bbe25bbb 100644
--- a/framework-s/java/android/safetycenter/config/SafetySourcesGroup.java
+++ b/framework-s/java/android/safetycenter/config/SafetySourcesGroup.java
@@ -17,6 +17,7 @@
package android.safetycenter.config;
import static android.os.Build.VERSION_CODES.TIRAMISU;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static java.util.Collections.unmodifiableList;
import static java.util.Objects.requireNonNull;
@@ -25,6 +26,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.content.res.Resources;
import android.os.Parcel;
@@ -32,6 +34,8 @@ import android.os.Parcelable;
import androidx.annotation.RequiresApi;
+import com.android.modules.utils.build.SdkLevel;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -50,16 +54,39 @@ public final class SafetySourcesGroup implements Parcelable {
/**
* Indicates that the safety sources group should be displayed as a collapsible group with an
* icon (stateless or stateful) and an optional default summary.
+ *
+ * @deprecated use {@link #SAFETY_SOURCES_GROUP_TYPE_STATEFUL} instead.
*/
public static final int SAFETY_SOURCES_GROUP_TYPE_COLLAPSIBLE = 0;
/**
+ * Indicates that the safety sources group should be displayed as a group that may contribute to
+ * the overall Safety Center status. This is indicated by a group stateful icon. If all sources
+ * in the group have an unspecified status then a stateless group icon might be applied.
+ */
+ public static final int SAFETY_SOURCES_GROUP_TYPE_STATEFUL =
+ SAFETY_SOURCES_GROUP_TYPE_COLLAPSIBLE;
+
+ /**
* Indicates that the safety sources group should be displayed as a rigid group with no icon and
* no summary.
+ *
+ * @deprecated use {@link #SAFETY_SOURCES_GROUP_TYPE_STATELESS} instead.
*/
public static final int SAFETY_SOURCES_GROUP_TYPE_RIGID = 1;
- /** Indicates that the safety sources group should not be displayed. */
+ /**
+ * Indicates that the safety sources group should be displayed as a group that does not
+ * contribute to the overall Safety Center status. All sources of type dynamic in the group can
+ * only report an unspecified status. The stateless icon and summary may be ignored and not be
+ * displayed.
+ */
+ public static final int SAFETY_SOURCES_GROUP_TYPE_STATELESS = SAFETY_SOURCES_GROUP_TYPE_RIGID;
+
+ /**
+ * Indicates that the safety sources group should not be displayed. All sources in the group
+ * must be of type issue-only.
+ */
public static final int SAFETY_SOURCES_GROUP_TYPE_HIDDEN = 2;
/**
@@ -67,24 +94,27 @@ public final class SafetySourcesGroup implements Parcelable {
*
* @hide
*/
+ @SuppressLint("UniqueConstants") // Intentionally renaming the COLLAPSIBLE and RIGID constants.
@Retention(RetentionPolicy.SOURCE)
@IntDef(
prefix = "SAFETY_SOURCES_GROUP_TYPE_",
value = {
SAFETY_SOURCES_GROUP_TYPE_COLLAPSIBLE,
+ SAFETY_SOURCES_GROUP_TYPE_STATEFUL,
SAFETY_SOURCES_GROUP_TYPE_RIGID,
+ SAFETY_SOURCES_GROUP_TYPE_STATELESS,
SAFETY_SOURCES_GROUP_TYPE_HIDDEN
})
public @interface SafetySourceGroupType {}
/**
- * Indicates that the safety sources group will not be displayed with any special icon when all
- * the sources contained in it are stateless.
+ * Indicates that no special icon will be displayed by a safety sources group when all the
+ * sources contained in it are stateless.
*/
public static final int STATELESS_ICON_TYPE_NONE = 0;
/**
- * Indicates that the safety sources group will be displayed with the privacy icon when all the
+ * Indicates that the privacy icon will be displayed by a safety sources group when all the
* sources contained in it are stateless.
*/
public static final int STATELESS_ICON_TYPE_PRIVACY = 1;
@@ -116,6 +146,9 @@ public final class SafetySourcesGroup implements Parcelable {
for (int i = 0; i < safetySources.size(); i++) {
builder.addSafetySource(safetySources.get(i));
}
+ if (SdkLevel.isAtLeastU()) {
+ builder.setType(in.readInt());
+ }
return builder.build();
}
@@ -125,6 +158,7 @@ public final class SafetySourcesGroup implements Parcelable {
}
};
+ @SafetySourceGroupType private final int mType;
@NonNull private final String mId;
@StringRes private final int mTitleResId;
@StringRes private final int mSummaryResId;
@@ -132,11 +166,13 @@ public final class SafetySourcesGroup implements Parcelable {
@NonNull private final List<SafetySource> mSafetySources;
private SafetySourcesGroup(
+ @SafetySourceGroupType int type,
@NonNull String id,
@StringRes int titleResId,
@StringRes int summaryResId,
@StatelessIconType int statelessIconType,
@NonNull List<SafetySource> safetySources) {
+ mType = type;
mId = id;
mTitleResId = titleResId;
mSummaryResId = summaryResId;
@@ -144,23 +180,10 @@ public final class SafetySourcesGroup implements Parcelable {
mSafetySources = safetySources;
}
- /**
- * Returns the type of this safety sources group.
- *
- * <p>The type is inferred according to the state of certain fields. If no title is provided
- * when building the group, the group is of type hidden. If a title is provided but no summary
- * or stateless icon are provided when building the group, the group is of type rigid.
- * Otherwise, the group is of type collapsible.
- */
+ /** Returns the type of this safety sources group. */
@SafetySourceGroupType
public int getType() {
- if (mTitleResId == Resources.ID_NULL) {
- return SAFETY_SOURCES_GROUP_TYPE_HIDDEN;
- }
- if (mSummaryResId != Resources.ID_NULL || mStatelessIconType != STATELESS_ICON_TYPE_NONE) {
- return SAFETY_SOURCES_GROUP_TYPE_COLLAPSIBLE;
- }
- return SAFETY_SOURCES_GROUP_TYPE_RIGID;
+ return mType;
}
/**
@@ -224,7 +247,8 @@ public final class SafetySourcesGroup implements Parcelable {
if (this == o) return true;
if (!(o instanceof SafetySourcesGroup)) return false;
SafetySourcesGroup that = (SafetySourcesGroup) o;
- return Objects.equals(mId, that.mId)
+ return mType == that.mType
+ && Objects.equals(mId, that.mId)
&& mTitleResId == that.mTitleResId
&& mSummaryResId == that.mSummaryResId
&& mStatelessIconType == that.mStatelessIconType
@@ -233,15 +257,17 @@ public final class SafetySourcesGroup implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(mId, mTitleResId, mSummaryResId, mStatelessIconType, mSafetySources);
+ return Objects.hash(
+ mType, mId, mTitleResId, mSummaryResId, mStatelessIconType, mSafetySources);
}
@Override
public String toString() {
return "SafetySourcesGroup{"
- + "mId='"
+ + "mType="
+ + mType
+ + ", mId="
+ mId
- + '\''
+ ", mTitleResId="
+ mTitleResId
+ ", mSummaryResId="
@@ -265,6 +291,9 @@ public final class SafetySourcesGroup implements Parcelable {
dest.writeInt(mSummaryResId);
dest.writeInt(mStatelessIconType);
dest.writeTypedList(mSafetySources);
+ if (SdkLevel.isAtLeastU()) {
+ dest.writeInt(mType);
+ }
}
/** Builder class for {@link SafetySourcesGroup}. */
@@ -272,6 +301,7 @@ public final class SafetySourcesGroup implements Parcelable {
private final List<SafetySource> mSafetySources = new ArrayList<>();
+ @Nullable @SafetySourceGroupType private Integer mType;
@Nullable private String mId;
@Nullable @StringRes private Integer mTitleResId;
@Nullable @StringRes private Integer mSummaryResId;
@@ -280,6 +310,37 @@ public final class SafetySourcesGroup implements Parcelable {
/** Creates a {@link Builder} for a {@link SafetySourcesGroup}. */
public Builder() {}
+ /** Creates a {@link Builder} with the values from the given {@link SafetySourcesGroup}. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder(@NonNull SafetySourcesGroup original) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException();
+ }
+ requireNonNull(original);
+ mSafetySources.addAll(original.mSafetySources);
+ mType = original.mType;
+ mId = original.mId;
+ mTitleResId = original.mTitleResId;
+ mSummaryResId = original.mSummaryResId;
+ mStatelessIconType = original.mStatelessIconType;
+ }
+
+ /**
+ * Sets the type of this safety sources group.
+ *
+ * <p>If the type is not explicitly set, the type is inferred according to the state of
+ * certain fields. If no title is provided when building the group, the group is of type
+ * hidden. If a title is provided but no summary or stateless icon are provided when
+ * building the group, the group is of type stateless. Otherwise, the group is of type
+ * stateful.
+ */
+ @NonNull
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public Builder setType(@SafetySourceGroupType int type) {
+ mType = type;
+ return this;
+ }
+
/**
* Sets the id of this safety sources group.
*
@@ -347,27 +408,20 @@ public final class SafetySourcesGroup implements Parcelable {
/**
* Creates the {@link SafetySourcesGroup} defined by this {@link Builder}.
*
- * <p>Throws an {@link IllegalStateException} if any constraint on the safety sources group
- * is violated.
+ * @throws IllegalStateException if any constraint on the safety sources group is violated
*/
@NonNull
public SafetySourcesGroup build() {
- BuilderUtils.validateAttribute(mId, "id", true, false);
+ String id = mId;
+ BuilderUtils.validateId(id, "id", true, false);
+
List<SafetySource> safetySources = unmodifiableList(new ArrayList<>(mSafetySources));
if (safetySources.isEmpty()) {
throw new IllegalStateException("Safety sources group empty");
}
- boolean titleRequired = false;
- int safetySourcesSize = safetySources.size();
- for (int i = 0; i < safetySourcesSize; i++) {
- int type = safetySources.get(i).getType();
- if (type != SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY) {
- titleRequired = true;
- break;
- }
- }
- int titleResId = BuilderUtils.validateResId(mTitleResId, "title", titleRequired, false);
+
int summaryResId = BuilderUtils.validateResId(mSummaryResId, "summary", false, false);
+
int statelessIconType =
BuilderUtils.validateIntDef(
mStatelessIconType,
@@ -377,8 +431,53 @@ public final class SafetySourcesGroup implements Parcelable {
STATELESS_ICON_TYPE_NONE,
STATELESS_ICON_TYPE_NONE,
STATELESS_ICON_TYPE_PRIVACY);
+
+ boolean hasOnlyIssueOnlySources = true;
+ int safetySourcesSize = safetySources.size();
+ for (int i = 0; i < safetySourcesSize; i++) {
+ int type = safetySources.get(i).getType();
+ if (type != SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY) {
+ hasOnlyIssueOnlySources = false;
+ break;
+ }
+ }
+
+ int inferredGroupType = SAFETY_SOURCES_GROUP_TYPE_STATELESS;
+ if (hasOnlyIssueOnlySources) {
+ inferredGroupType = SAFETY_SOURCES_GROUP_TYPE_HIDDEN;
+ } else if (summaryResId != Resources.ID_NULL
+ || statelessIconType != STATELESS_ICON_TYPE_NONE) {
+ inferredGroupType = SAFETY_SOURCES_GROUP_TYPE_STATEFUL;
+ }
+ int type =
+ BuilderUtils.validateIntDef(
+ mType,
+ "type",
+ false,
+ false,
+ inferredGroupType,
+ SAFETY_SOURCES_GROUP_TYPE_STATEFUL,
+ SAFETY_SOURCES_GROUP_TYPE_STATELESS,
+ SAFETY_SOURCES_GROUP_TYPE_HIDDEN);
+ if (type == SAFETY_SOURCES_GROUP_TYPE_HIDDEN && !hasOnlyIssueOnlySources) {
+ throw new IllegalStateException(
+ "Safety sources groups of type hidden can only contain sources of type "
+ + "issue-only");
+ }
+ if (type != SAFETY_SOURCES_GROUP_TYPE_HIDDEN && hasOnlyIssueOnlySources) {
+ throw new IllegalStateException(
+ "Safety sources groups containing only sources of type issue-only must be "
+ + "of type hidden");
+ }
+
+ boolean isStateful = type == SAFETY_SOURCES_GROUP_TYPE_STATEFUL;
+ boolean isStateless = type == SAFETY_SOURCES_GROUP_TYPE_STATELESS;
+ int titleResId =
+ BuilderUtils.validateResId(
+ mTitleResId, "title", isStateful || isStateless, false);
+
return new SafetySourcesGroup(
- mId, titleResId, summaryResId, statelessIconType, safetySources);
+ type, id, titleResId, summaryResId, statelessIconType, safetySources);
}
}
}
diff --git a/framework-s/java/android/safetycenter/config/safety_center_config-v34.xsd b/framework-s/java/android/safetycenter/config/safety_center_config-v34.xsd
new file mode 100644
index 000000000..01497799a
--- /dev/null
+++ b/framework-s/java/android/safetycenter/config/safety_center_config-v34.xsd
@@ -0,0 +1,217 @@
+<?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.
+ -->
+<!-- This file contains comments that define constraints that cannot be covered by the XSD language -->
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ version="1.0">
+
+ <xsd:element name="safety-center-config" type="safety-center-config"/>
+
+ <xsd:complexType name="safety-center-config">
+ <xsd:sequence>
+ <xsd:element name="safety-sources-config" type="safety-sources-config"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="safety-sources-config">
+ <xsd:sequence>
+ <xsd:element
+ name="safety-sources-group" type="safety-sources-group"
+ minOccurs="1" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="safety-sources-group">
+ <xsd:choice minOccurs="1" maxOccurs="unbounded">
+ <xsd:element name="dynamic-safety-source" type="dynamic-safety-source"/>
+ <xsd:element name="static-safety-source" type="static-safety-source"/>
+ <xsd:element name="issue-only-safety-source" type="issue-only-safety-source"/>
+ </xsd:choice>
+ <!-- id must be unique among safety sources groups -->
+ <xsd:attribute name="id" type="idOrStringResourceName" use="required"/>
+ <!-- title is required unless the group contains issue only and/or internal sources -->
+ <xsd:attribute name="title" type="runtimeStringResourceName"/>
+ <xsd:attribute name="summary" type="runtimeStringResourceName"/>
+ <xsd:attribute name="statelessIconType" type="statelessIconTypeOrStringResourceName"
+ default="none"/>
+ <!-- type is inferred from other attributes and the group content if omitted -->
+ <xsd:attribute name="type" type="groupTypeOrStringResourceName"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="dynamic-safety-source">
+ <!-- id must be unique among safety sources -->
+ <xsd:attribute name="id" type="idOrStringResourceName" use="required"/>
+ <xsd:attribute name="packageName" type="stringOrStringResourceName" use="required"/>
+ <!-- optional comma-separated set of certficate hashes, if provided will be used for validation. -->
+ <xsd:attribute name="packageCertificateHashes" type="stringOrStringResourceName"/>
+ <!-- title is required if initialDisplayState is not set to hidden or if searchTerms are provided -->
+ <xsd:attribute name="title" type="runtimeStringResourceName"/>
+ <!-- titleForWork is required if profile is set to all_profiles, and initialDisplayState is not set to hidden or if searchTerms are provided -->
+ <!-- titleForWork is prohibited if profile is set to primary_profile_only -->
+ <xsd:attribute name="titleForWork" type="runtimeStringResourceName"/>
+ <!-- summary is required if initialDisplayState is not set to hidden -->
+ <xsd:attribute name="summary" type="runtimeStringResourceName"/>
+ <!-- intentAction is required if initialDisplayState is set to enabled -->
+ <xsd:attribute name="intentAction" type="stringOrStringResourceName"/>
+ <xsd:attribute name="profile" type="profile" use="required"/>
+ <xsd:attribute name="initialDisplayState" type="initialDisplayStateOrStringResourceName"
+ default="enabled"/>
+ <xsd:attribute name="maxSeverityLevel" type="intOrStringResourceName" default="2147483647"/>
+ <xsd:attribute name="searchTerms" type="runtimeStringResourceName"/>
+ <xsd:attribute name="loggingAllowed" type="booleanOrStringResourceName" default="true"/>
+ <xsd:attribute name="refreshOnPageOpenAllowed" type="booleanOrStringResourceName"
+ default="false"/>
+ <xsd:attribute name="notificationsAllowed" type="booleanOrStringResourceName"
+ default="false"/>
+ <xsd:attribute name="deduplicationGroup" type="stringOrStringResourceName"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="issue-only-safety-source">
+ <!-- id must be unique among safety sources -->
+ <xsd:attribute name="id" type="idOrStringResourceName" use="required"/>
+ <xsd:attribute name="packageName" type="stringOrStringResourceName" use="required"/>
+ <!-- optional comma-separated set of certficate hashes, if provided will be used for validation. -->
+ <xsd:attribute name="packageCertificateHashes" type="stringOrStringResourceName"/>
+ <xsd:attribute name="profile" type="profileOrStringResourceName" use="required"/>
+ <xsd:attribute name="maxSeverityLevel" type="intOrStringResourceName" default="2147483647"/>
+ <xsd:attribute name="loggingAllowed" type="booleanOrStringResourceName" default="true"/>
+ <xsd:attribute name="refreshOnPageOpenAllowed" type="booleanOrStringResourceName"
+ default="false"/>
+ <xsd:attribute name="notificationsAllowed" type="booleanOrStringResourceName"
+ default="false"/>
+ <xsd:attribute name="deduplicationGroup" type="stringOrStringResourceName"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="static-safety-source">
+ <!-- id must be unique among safety sources -->
+ <xsd:attribute name="id" type="idOrStringResourceName" use="required"/>
+ <xsd:attribute name="packageName" type="stringOrStringResourceName"/>
+ <xsd:attribute name="title" type="runtimeStringResourceName" use="required"/>
+ <!-- titleForWork is required if profile is set to all_profiles -->
+ <!-- titleForWork is prohibited if profile is set to primary_profile_only -->
+ <xsd:attribute name="titleForWork" type="runtimeStringResourceName"/>
+ <xsd:attribute name="summary" type="runtimeStringResourceName"/>
+ <xsd:attribute name="intentAction" type="stringOrStringResourceName" use="required"/>
+ <xsd:attribute name="profile" type="profileOrStringResourceName" use="required"/>
+ <xsd:attribute name="searchTerms" type="runtimeStringResourceName"/>
+ </xsd:complexType>
+
+ <xsd:simpleType name="intOrStringResourceName">
+ <!-- String resource names will be resolved only once at parse time. -->
+ <!-- Locale changes and device config changes will be ignored. -->
+ <!-- The value of the string resource must be of type xsd:int. -->
+ <xsd:union memberTypes="stringResourceName xsd:int"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="booleanOrStringResourceName">
+ <!-- String resource names will be resolved only once at parse time. -->
+ <!-- Locale changes and device config changes will be ignored. -->
+ <!-- The value of the string resource must be of type xsd:boolean. -->
+ <xsd:union memberTypes="stringResourceName xsd:boolean"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="stringOrStringResourceName">
+ <!-- String resource names will be resolved only once at parse time. -->
+ <!-- Locale changes and device config changes will be ignored. -->
+ <!-- The value of the string resource must be of type xsd:string. -->
+ <xsd:union memberTypes="stringResourceName xsd:string"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="idOrStringResourceName">
+ <!-- String resource names will be resolved only once at parse time. -->
+ <!-- Locale changes and device config changes will be ignored. -->
+ <!-- The value of the string resource must be of type xsd:string. -->
+ <xsd:union memberTypes="stringResourceName id"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="id">
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="[0-9a-zA-Z_-]+"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="statelessIconTypeOrStringResourceName">
+ <!-- String resource names will be resolved only once at parse time. -->
+ <!-- Locale changes and device config changes will be ignored. -->
+ <!-- The value of the string resource must be of type statelessIconType. -->
+ <xsd:union memberTypes="stringResourceName statelessIconType"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="statelessIconType">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="none"/>
+ <xsd:enumeration value="privacy"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="profileOrStringResourceName">
+ <!-- String resource names will be resolved only once at parse time. -->
+ <!-- Locale changes and device config changes will be ignored. -->
+ <!-- The value of the string resource must be of type profile. -->
+ <xsd:union memberTypes="stringResourceName profile"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="profile">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="primary_profile_only"/>
+ <xsd:enumeration value="all_profiles"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="initialDisplayStateOrStringResourceName">
+ <!-- String resource names will be resolved only once at parse time. -->
+ <!-- Locale changes and device config changes will be ignored. -->
+ <!-- The value of the string resource must be of type initialDisplayState. -->
+ <xsd:union memberTypes="stringResourceName initialDisplayState"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="initialDisplayState">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="enabled"/>
+ <xsd:enumeration value="disabled"/>
+ <xsd:enumeration value="hidden"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="groupTypeOrStringResourceName">
+ <!-- String resource names will be resolved only once at parse time. -->
+ <!-- Locale changes and device config changes will be ignored. -->
+ <!-- The value of the string resource must be of type groupType. -->
+ <xsd:union memberTypes="stringResourceName groupType"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="groupType">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="stateless"/>
+ <xsd:enumeration value="stateful"/>
+ <xsd:enumeration value="hidden"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="runtimeStringResourceName">
+ <!-- String resource names will be resolved at runtime whenever the string value is used. -->
+ <xsd:union memberTypes="stringResourceName"/>
+ </xsd:simpleType>
+
+ <!-- String resource names will be ignored for any attribute not directly or indirectly marked as stringResourceName. -->
+ <!-- A stringResourceName is a fully qualified resource name of the form "@package:string/entry". Package is required. -->
+ <xsd:simpleType name="stringResourceName">
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="@([a-z]+\.)*[a-z]+:string/.+"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+</xsd:schema>
diff --git a/framework-s/java/android/safetycenter/config/safety_center_config.xsd b/framework-s/java/android/safetycenter/config/safety_center_config.xsd
index 8549df80f..283b21217 100644
--- a/framework-s/java/android/safetycenter/config/safety_center_config.xsd
+++ b/framework-s/java/android/safetycenter/config/safety_center_config.xsd
@@ -41,16 +41,17 @@
<xsd:element name="issue-only-safety-source" type="issue-only-safety-source"/>
</xsd:choice>
<!-- id must be unique among safety sources groups -->
- <xsd:attribute name="id" type="stringOrStringResourceName" use="required"/>
+ <xsd:attribute name="id" type="idOrStringResourceName" use="required"/>
<!-- title is required unless the group contains issue only and/or internal sources -->
<xsd:attribute name="title" type="runtimeStringResourceName"/>
<xsd:attribute name="summary" type="runtimeStringResourceName"/>
- <xsd:attribute name="statelessIconType" type="statelessIconTypeOrStringResourceName" default="none"/>
+ <xsd:attribute name="statelessIconType" type="statelessIconTypeOrStringResourceName"
+ default="none"/>
</xsd:complexType>
<xsd:complexType name="dynamic-safety-source">
<!-- id must be unique among safety sources -->
- <xsd:attribute name="id" type="stringOrStringResourceName" use="required"/>
+ <xsd:attribute name="id" type="idOrStringResourceName" use="required"/>
<xsd:attribute name="packageName" type="stringOrStringResourceName" use="required"/>
<!-- title is required if initialDisplayState is not set to hidden or if searchTerms are provided -->
<xsd:attribute name="title" type="runtimeStringResourceName"/>
@@ -62,26 +63,29 @@
<!-- intentAction is required if initialDisplayState is set to enabled -->
<xsd:attribute name="intentAction" type="stringOrStringResourceName"/>
<xsd:attribute name="profile" type="profile" use="required"/>
- <xsd:attribute name="initialDisplayState" type="initialDisplayStateOrStringResourceName" default="enabled"/>
+ <xsd:attribute name="initialDisplayState" type="initialDisplayStateOrStringResourceName"
+ default="enabled"/>
<xsd:attribute name="maxSeverityLevel" type="intOrStringResourceName" default="2147483647"/>
<xsd:attribute name="searchTerms" type="runtimeStringResourceName"/>
<xsd:attribute name="loggingAllowed" type="booleanOrStringResourceName" default="true"/>
- <xsd:attribute name="refreshOnPageOpenAllowed" type="booleanOrStringResourceName" default="false"/>
+ <xsd:attribute name="refreshOnPageOpenAllowed" type="booleanOrStringResourceName"
+ default="false"/>
</xsd:complexType>
<xsd:complexType name="issue-only-safety-source">
<!-- id must be unique among safety sources -->
- <xsd:attribute name="id" type="stringOrStringResourceName" use="required"/>
+ <xsd:attribute name="id" type="idOrStringResourceName" use="required"/>
<xsd:attribute name="packageName" type="stringOrStringResourceName" use="required"/>
<xsd:attribute name="profile" type="profileOrStringResourceName" use="required"/>
<xsd:attribute name="maxSeverityLevel" type="intOrStringResourceName" default="2147483647"/>
<xsd:attribute name="loggingAllowed" type="booleanOrStringResourceName" default="true"/>
- <xsd:attribute name="refreshOnPageOpenAllowed" type="booleanOrStringResourceName" default="false"/>
+ <xsd:attribute name="refreshOnPageOpenAllowed" type="booleanOrStringResourceName"
+ default="false"/>
</xsd:complexType>
<xsd:complexType name="static-safety-source">
<!-- id must be unique among safety sources -->
- <xsd:attribute name="id" type="stringOrStringResourceName" use="required"/>
+ <xsd:attribute name="id" type="idOrStringResourceName" use="required"/>
<xsd:attribute name="title" type="runtimeStringResourceName" use="required"/>
<!-- titleForWork is required if profile is set to all_profiles -->
<!-- titleForWork is prohibited if profile is set to primary_profile_only -->
@@ -96,28 +100,41 @@
<!-- String resource names will be resolved only once at parse time. -->
<!-- Locale changes and device config changes will be ignored. -->
<!-- The value of the string resource must be of type xsd:int. -->
- <xsd:union memberTypes="stringResourceName xsd:int" />
+ <xsd:union memberTypes="stringResourceName xsd:int"/>
</xsd:simpleType>
<xsd:simpleType name="booleanOrStringResourceName">
<!-- String resource names will be resolved only once at parse time. -->
<!-- Locale changes and device config changes will be ignored. -->
<!-- The value of the string resource must be of type xsd:boolean. -->
- <xsd:union memberTypes="stringResourceName xsd:boolean" />
+ <xsd:union memberTypes="stringResourceName xsd:boolean"/>
</xsd:simpleType>
<xsd:simpleType name="stringOrStringResourceName">
<!-- String resource names will be resolved only once at parse time. -->
<!-- Locale changes and device config changes will be ignored. -->
<!-- The value of the string resource must be of type xsd:string. -->
- <xsd:union memberTypes="stringResourceName xsd:string" />
+ <xsd:union memberTypes="stringResourceName xsd:string"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="idOrStringResourceName">
+ <!-- String resource names will be resolved only once at parse time. -->
+ <!-- Locale changes and device config changes will be ignored. -->
+ <!-- The value of the string resource must be of type xsd:string. -->
+ <xsd:union memberTypes="stringResourceName id"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="id">
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="[0-9a-zA-Z_-]+"/>
+ </xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="statelessIconTypeOrStringResourceName">
<!-- String resource names will be resolved only once at parse time. -->
<!-- Locale changes and device config changes will be ignored. -->
<!-- The value of the string resource must be of type statelessIconType. -->
- <xsd:union memberTypes="stringResourceName statelessIconType" />
+ <xsd:union memberTypes="stringResourceName statelessIconType"/>
</xsd:simpleType>
<xsd:simpleType name="statelessIconType">
@@ -131,7 +148,7 @@
<!-- String resource names will be resolved only once at parse time. -->
<!-- Locale changes and device config changes will be ignored. -->
<!-- The value of the string resource must be of type profile. -->
- <xsd:union memberTypes="stringResourceName profile" />
+ <xsd:union memberTypes="stringResourceName profile"/>
</xsd:simpleType>
<xsd:simpleType name="profile">
@@ -145,7 +162,7 @@
<!-- String resource names will be resolved only once at parse time. -->
<!-- Locale changes and device config changes will be ignored. -->
<!-- The value of the string resource must be of type initialDisplayState. -->
- <xsd:union memberTypes="stringResourceName initialDisplayState" />
+ <xsd:union memberTypes="stringResourceName initialDisplayState"/>
</xsd:simpleType>
<xsd:simpleType name="initialDisplayState">
@@ -158,7 +175,7 @@
<xsd:simpleType name="runtimeStringResourceName">
<!-- String resource names will be resolved at runtime whenever the string value is used. -->
- <xsd:union memberTypes="stringResourceName" />
+ <xsd:union memberTypes="stringResourceName"/>
</xsd:simpleType>
<!-- String resource names will be ignored for any attribute not directly or indirectly marked as stringResourceName. -->
diff --git a/framework-s/java/android/safetylabel/SafetyLabelConstants.java b/framework-s/java/android/safetylabel/SafetyLabelConstants.java
new file mode 100644
index 000000000..8e8cb0ec9
--- /dev/null
+++ b/framework-s/java/android/safetylabel/SafetyLabelConstants.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.safetylabel;
+
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+
+import android.annotation.SystemApi;
+
+import androidx.annotation.RequiresApi;
+
+/**
+ * Constants relating to the Safety Label feature.
+ *
+ * @hide
+ */
+@SystemApi
+@RequiresApi(UPSIDE_DOWN_CAKE)
+public final class SafetyLabelConstants {
+
+ /**
+ * Constant to be used as Device Config flag determining whether the Permission Rationale
+ * feature is enabled.
+ *
+ * <p>When this flag is enabled, permission rationale messaging will be displayed in permission
+ * settings and the runtime permissions grant dialog.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static final String PERMISSION_RATIONALE_ENABLED = "permission_rationale_enabled";
+
+ /**
+ * Constant to be used as Device Config flag determining whether the Safety Label Change
+ * Notifications feature is enabled.
+ *
+ * <p>When this flag is enabled, a system notification will be sent to users if any apps they
+ * have installed have made recent updates to their data sharing policy in their app safety
+ * labels.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public static final String SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED =
+ "safety_label_change_notifications_enabled";
+
+ private SafetyLabelConstants() {}
+}
diff --git a/framework-s/lint-baseline.xml b/framework-s/lint-baseline.xml
new file mode 100644
index 000000000..b91b959e4
--- /dev/null
+++ b/framework-s/lint-baseline.xml
@@ -0,0 +1,37 @@
+<?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">
+
+ <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=" ~~~~~~~">
+ <location
+ file="frameworks/base/core/java/com/android/internal/infra/ServiceConnector.java"
+ line="707"
+ column="53"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 31 (current min is 30): `android.content.Context#getUser`"
+ errorLine1=' .append(mIntent).append(", user: ").append(mContext.getUser().getIdentifier())'
+ errorLine2=" ~~~~~~~">
+ <location
+ file="frameworks/base/core/java/com/android/internal/infra/ServiceConnector.java"
+ line="688"
+ column="73"/>
+ </issue>
+
+ <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=" ~">
+ <location
+ file="frameworks/base/core/java/com/android/internal/infra/ServiceConnector.java"
+ line="576"
+ column="26"/>
+ </issue>
+
+</issues> \ No newline at end of file
diff --git a/jarjar-rules.txt b/jarjar-rules.txt
deleted file mode 100644
index 9e3932842..000000000
--- a/jarjar-rules.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-rule android.os.HandlerExecutor 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
-rule com.android.role.*Proto com.android.permission.jarjar.@0
-rule kotlin.** com.android.permission.jarjar.@0
diff --git a/ktfmt_includes.txt b/ktfmt_includes.txt
new file mode 100644
index 000000000..40d8f07d9
--- /dev/null
+++ b/ktfmt_includes.txt
@@ -0,0 +1,2 @@
++SafetyCenter
++tests
diff --git a/permissions/com.android.permissioncontroller.xml b/permissions/com.android.permissioncontroller.xml
index 453b47478..957a29ee0 100644
--- a/permissions/com.android.permissioncontroller.xml
+++ b/permissions/com.android.permissioncontroller.xml
@@ -32,5 +32,7 @@
<permission name="android.permission.READ_SAFETY_CENTER_STATUS" />
<permission name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
<permission name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS" />
+ <permission name="android.permission.START_TASKS_FROM_RECENTS" />
+ <permission name="android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK" />
</privapp-permissions>
</permissions>
diff --git a/service/Android.bp b/service/Android.bp
index 64c05afb4..96b8fbb96 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -20,30 +20,23 @@ filegroup {
name: "service-permission-java-sources",
srcs: [
"java/**/*.java",
- // Exclude Kotlin sources for T.
- //"java/**/*.kt",
+ "java/**/*.kt",
],
path: "java",
visibility: ["//visibility:private"],
}
-filegroup {
- name: "service-permission-streaming-proto-sources",
- srcs: [
- "proto/role_service.proto",
- ],
- visibility: ["//frameworks/base"],
-}
-
java_library {
- name: "service-permission-streaming-proto-java-gen",
+ name: "service-permission-proto-stream",
proto: {
type: "stream",
include_dirs: [
"external/protobuf/src",
],
},
- srcs: [":service-permission-streaming-proto-sources"],
+ srcs: [
+ "proto/role_service.proto",
+ ],
installable: false,
min_sdk_version: "30",
sdk_version: "system_server_current",
@@ -58,6 +51,8 @@ java_library {
srcs: [":service-permission-shared-srcs"],
libs: [
"framework-annotations-lib",
+ ],
+ static_libs: [
"framework-permission-s-shared",
],
apex_available: [
@@ -79,7 +74,6 @@ java_sdk_library {
"//frameworks/base/apex/permission/tests",
"//frameworks/base/services/tests/mockingservicestests",
"//frameworks/base/services/tests/PackageManagerServiceTests/server",
- "//frameworks/base/services/tests/servicestests",
"//packages/modules/Permission/tests/apex",
],
srcs: [
@@ -93,24 +87,33 @@ java_sdk_library {
//"framework-permission",
"framework-permission-s.impl",
"framework-permission-s-shared",
+ "framework-statsd.stubs.module_lib",
+ "jsr305",
// Soong fails to automatically add this dependency because all the
// *.kt sources are inside a filegroup.
- // Exclude Kotlin sources for T.
- //"kotlin-annotations",
+ "kotlin-annotations",
+ "safety-center-annotations",
],
static_libs: [
- // Exclude Kotlin sources for T.
- //"kotlin-stdlib",
+ "kotlin-stdlib",
"modules-utils-backgroundthread",
+ "modules-utils-build",
"modules-utils-os",
"safety-center-config",
+ "safety-center-internal-data",
+ "safety-center-pending-intents",
+ "safety-center-persistence",
"safety-center-resources-lib",
"service-permission-shared",
- "service-permission-streaming-proto-java-gen",
+ "service-permission-statsd",
+ "service-permission-proto-stream",
],
+ errorprone: {
+ javacflags: ["-Xep:GuardedBy:ERROR"],
+ },
exclude_kotlinc_generated_files: true,
- jarjar_rules: ":permission-jarjar-rules",
+ jarjar_rules: "jarjar-rules.txt",
kotlincflags: [
"-Werror",
"-Xjvm-default=all",
@@ -135,3 +138,27 @@ java_sdk_library {
"com.android.safetycenter",
],
}
+
+genrule {
+ name: "statslog-service-permission-java-gen",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --java $(out) --module permissioncontroller" +
+ " --javaPackage com.android.permission" +
+ " --javaClass PermissionStatsLog --minApiLevel 29",
+ out: ["com/android/permission/PermissionStatsLog.java"],
+}
+
+java_library {
+ name: "service-permission-statsd",
+ srcs: [
+ ":statslog-service-permission-java-gen",
+ ],
+ libs: [
+ "framework-statsd.stubs.module_lib",
+ ],
+ apex_available: [
+ "com.android.permission",
+ ],
+ min_sdk_version: "30",
+ sdk_version: "system_server_current",
+}
diff --git a/service/jarjar-rules.txt b/service/jarjar-rules.txt
new file mode 100644
index 000000000..2b8765cf5
--- /dev/null
+++ b/service/jarjar-rules.txt
@@ -0,0 +1,14 @@
+rule android.os.HandlerExecutor 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
+rule com.android.role.*Proto com.android.permission.jarjar.@0
+# TODO(b/236200992): Revisit addition of rule com.android.safetycenter.annotations,
+# com.android.safetycenter.internaldata, com.android.safetycenter.pendingintents and
+# com.android.safetycenter.resources
+rule com.android.safetycenter.annotations.** com.android.permission.jarjar.@0
+rule com.android.safetycenter.internaldata.** com.android.permission.jarjar.@0
+rule com.android.safetycenter.pendingintents.** com.android.permission.jarjar.@0
+rule com.android.safetycenter.resources.** com.android.permission.jarjar.@0
+rule com.google.protobuf.** com.android.permission.jarjar.@0
+rule kotlin.** com.android.permission.jarjar.@0
diff --git a/service/java/com/android/permission/compat/UserHandleCompat.java b/service/java/com/android/permission/compat/UserHandleCompat.java
index 7c711d301..1901aa997 100644
--- a/service/java/com/android/permission/compat/UserHandleCompat.java
+++ b/service/java/com/android/permission/compat/UserHandleCompat.java
@@ -45,4 +45,15 @@ public final class UserHandleCompat {
public static int getUserId(int uid) {
return UserHandle.getUserHandleForUid(uid).getIdentifier();
}
+
+ /**
+ * Get the UID from the give user ID and app ID
+ *
+ * @param userId the user ID
+ * @param appId the app ID
+ * @return the UID
+ */
+ public static int getUid(@UserIdInt int userId, int appId) {
+ return UserHandle.of(userId).getUid(appId);
+ }
}
diff --git a/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java b/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
index 9ba37af45..f3ba5aaef 100644
--- a/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
+++ b/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
@@ -20,12 +20,17 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ApexEnvironment;
import android.content.pm.PackageManager;
+import android.os.FileUtils;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Log;
import android.util.Xml;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.build.SdkLevel;
+import com.android.server.security.FileIntegrity;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -53,6 +58,8 @@ public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPers
private static final String APEX_MODULE_NAME = "com.android.permission";
private static final String RUNTIME_PERMISSIONS_FILE_NAME = "runtime-permissions.xml";
+ private static final String RUNTIME_PERMISSIONS_RESERVE_COPY_FILE_NAME =
+ RUNTIME_PERMISSIONS_FILE_NAME + ".reservecopy";
private static final String TAG_PACKAGE = "package";
private static final String TAG_PERMISSION = "permission";
@@ -65,6 +72,27 @@ public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPers
private static final String ATTRIBUTE_NAME = "name";
private static final String ATTRIBUTE_VERSION = "version";
+ @VisibleForTesting
+ interface Injector {
+ void enableFsVerity(@NonNull File file) throws IOException;
+ }
+
+ @NonNull
+ private final Injector mInjector;
+
+ RuntimePermissionsPersistenceImpl() {
+ this(file -> {
+ if (SdkLevel.isAtLeastU()) {
+ FileIntegrity.setUpFsVerity(file);
+ }
+ });
+ }
+
+ @VisibleForTesting
+ RuntimePermissionsPersistenceImpl(@NonNull Injector injector) {
+ mInjector = injector;
+ }
+
@Nullable
@Override
public RuntimePermissionsState readForUser(@NonNull UserHandle user) {
@@ -76,8 +104,20 @@ public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPers
} catch (FileNotFoundException e) {
Log.i(LOG_TAG, "runtime-permissions.xml not found");
return null;
- } catch (XmlPullParserException | IOException e) {
- throw new IllegalStateException("Failed to read runtime-permissions.xml: " + file , e);
+ } catch (Exception e) {
+ File reserveFile = getReserveCopyFile(user);
+ Log.wtf(LOG_TAG, "Reading from reserve copy: " + reserveFile, e);
+ try (FileInputStream inputStream = new AtomicFile(reserveFile).openRead()) {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(inputStream, null);
+ return parseXml(parser);
+ } catch (Exception exceptionReadingReserveFile) {
+ Log.e(LOG_TAG, "Failed to read reserve copy: " + reserveFile,
+ exceptionReadingReserveFile);
+ // Reserve copy failed, rethrow the original exception wrapped as runtime.
+ throw new IllegalStateException("Failed to read runtime-permissions.xml: " + file,
+ e);
+ }
}
}
@@ -174,6 +214,9 @@ public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPers
@Override
public void writeForUser(@NonNull RuntimePermissionsState runtimePermissions,
@NonNull UserHandle user) {
+ File reserveFile = getReserveCopyFile(user);
+ reserveFile.delete();
+
File file = getFile(user);
AtomicFile atomicFile = new AtomicFile(file);
FileOutputStream outputStream = null;
@@ -192,9 +235,25 @@ public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPers
Log.wtf(LOG_TAG, "Failed to write runtime-permissions.xml, restoring backup: " + file,
e);
atomicFile.failWrite(outputStream);
+ return;
} finally {
IoUtils.closeQuietly(outputStream);
}
+
+ try (FileInputStream in = new FileInputStream(file);
+ FileOutputStream out = new FileOutputStream(reserveFile)) {
+ FileUtils.copy(in, out);
+ out.getFD().sync();
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Failed to write reserve copy: " + reserveFile, e);
+ }
+
+ try {
+ mInjector.enableFsVerity(file);
+ mInjector.enableFsVerity(reserveFile);
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Failed to verity-protect runtime-permissions", e);
+ }
}
private static void serializeRuntimePermissions(@NonNull XmlSerializer serializer,
@@ -253,12 +312,21 @@ public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPers
@Override
public void deleteForUser(@NonNull UserHandle user) {
getFile(user).delete();
+ getReserveCopyFile(user).delete();
}
+ @VisibleForTesting
@NonNull
- private static File getFile(@NonNull UserHandle user) {
+ static File getFile(@NonNull UserHandle user) {
ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment(APEX_MODULE_NAME);
File dataDirectory = apexEnvironment.getDeviceProtectedDataDirForUser(user);
return new File(dataDirectory, RUNTIME_PERMISSIONS_FILE_NAME);
}
+
+ @NonNull
+ private static File getReserveCopyFile(@NonNull UserHandle user) {
+ ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment(APEX_MODULE_NAME);
+ File dataDirectory = apexEnvironment.getDeviceProtectedDataDirForUser(user);
+ return new File(dataDirectory, RUNTIME_PERMISSIONS_RESERVE_COPY_FILE_NAME);
+ }
}
diff --git a/service/java/com/android/permission/util/PackageUtils.java b/service/java/com/android/permission/util/PackageUtils.java
index 91f6bccd6..32eead8e8 100644
--- a/service/java/com/android/permission/util/PackageUtils.java
+++ b/service/java/com/android/permission/util/PackageUtils.java
@@ -19,12 +19,15 @@ package com.android.permission.util;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Binder;
import android.os.UserHandle;
-/**
- * Utility class for dealing with packages.
- */
+import java.util.List;
+
+/** Utility class for dealing with packages. */
public final class PackageUtils {
private PackageUtils() {}
@@ -33,8 +36,8 @@ public final class PackageUtils {
*
* @see PackageManager#canPackageQuery
*/
- public static boolean canCallingOrSelfPackageQuery(@NonNull String packageName,
- @UserIdInt int userId, @NonNull Context context) {
+ public static boolean canCallingOrSelfPackageQuery(
+ @NonNull String packageName, @UserIdInt int userId, @NonNull Context context) {
final Context userContext = context.createContextAsUser(UserHandle.of(userId), 0);
final PackageManager userPackageManager = userContext.getPackageManager();
try {
@@ -44,4 +47,39 @@ public final class PackageUtils {
return false;
}
}
+
+ /**
+ * Returns the activities {@link ResolveInfo} that match the given {@link Intent} for the given
+ * {@code flags} and {@code userId}.
+ */
+ @NonNull
+ public static List<ResolveInfo> queryUnfilteredIntentActivitiesAsUser(
+ @NonNull Intent intent, int flags, @UserIdInt int userId, @NonNull Context context) {
+ PackageManager packageManager = context.getPackageManager();
+ // This call requires the INTERACT_ACROSS_USERS permission.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ return packageManager.queryIntentActivitiesAsUser(intent, flags, UserHandle.of(userId));
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ /**
+ * Returns the broadcasts {@link ResolveInfo} that match the given {@link Intent} for the given
+ * {@code flags} and {@code userId}.
+ */
+ @NonNull
+ public static List<ResolveInfo> queryUnfilteredBroadcastReceiversAsUser(
+ @NonNull Intent intent, int flags, @UserIdInt int userId, @NonNull Context context) {
+ PackageManager packageManager = context.getPackageManager();
+ // This call requires the INTERACT_ACROSS_USERS permission.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ return packageManager.queryBroadcastReceiversAsUser(
+ intent, flags, UserHandle.of(userId));
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
}
diff --git a/service/java/com/android/permission/util/PermissionUtils.java b/service/java/com/android/permission/util/PermissionUtils.java
deleted file mode 100644
index 0d03bae94..000000000
--- a/service/java/com/android/permission/util/PermissionUtils.java
+++ /dev/null
@@ -1,56 +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.permission.util;
-
-import android.annotation.NonNull;
-import android.annotation.UserIdInt;
-import android.content.Context;
-import android.os.Binder;
-import android.os.Process;
-import android.os.UserHandle;
-import android.os.UserManager;
-
-import com.android.internal.util.Preconditions;
-import com.android.permission.compat.UserHandleCompat;
-
-/** Utility class to deal with Android permissions. */
-public final class PermissionUtils {
-
- private PermissionUtils() {}
-
- /** Enforces cross user permission for the calling UID and the given {@code userId}. */
- public static void enforceCrossUserPermission(@UserIdInt int userId, boolean allowAll,
- @NonNull String message, @NonNull Context context) {
- final int callingUid = Binder.getCallingUid();
- final int callingUserId = UserHandleCompat.getUserId(callingUid);
- if (userId == callingUserId) {
- return;
- }
- Preconditions.checkArgument(userId >= UserHandleCompat.USER_SYSTEM
- || (allowAll && userId == UserHandleCompat.USER_ALL), "Invalid user " + userId);
- context.enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
- if (callingUid == Process.SHELL_UID && userId >= UserHandleCompat.USER_SYSTEM) {
- UserManager userManager = context.getSystemService(UserManager.class);
- if (userManager.hasUserRestrictionForUser(UserManager.DISALLOW_DEBUGGING_FEATURES,
- UserHandle.of(userId))) {
- throw new SecurityException("Shell does not have permission to access user "
- + userId);
- }
- }
- }
-}
diff --git a/service/java/com/android/permission/util/UserUtils.java b/service/java/com/android/permission/util/UserUtils.java
new file mode 100644
index 000000000..8205be239
--- /dev/null
+++ b/service/java/com/android/permission/util/UserUtils.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.permission.util;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import com.android.internal.util.Preconditions;
+import com.android.permission.compat.UserHandleCompat;
+
+import java.util.List;
+
+/** Utility class to deal with Android users. */
+public final class UserUtils {
+
+ private UserUtils() {}
+
+ /** Enforces cross user permission for the calling UID and the given {@code userId}. */
+ public static void enforceCrossUserPermission(
+ @UserIdInt int userId,
+ boolean allowAll,
+ @NonNull String message,
+ @NonNull Context context) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandleCompat.getUserId(callingUid);
+ if (userId == callingUserId) {
+ return;
+ }
+ Preconditions.checkArgument(
+ userId >= UserHandleCompat.USER_SYSTEM
+ || (allowAll && userId == UserHandleCompat.USER_ALL),
+ "Invalid user " + userId);
+ context.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
+ if (callingUid != Process.SHELL_UID || userId < UserHandleCompat.USER_SYSTEM) {
+ return;
+ }
+ UserManager userManager = context.getSystemService(UserManager.class);
+ if (userManager.hasUserRestrictionForUser(
+ UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.of(userId))) {
+ throw new SecurityException("Shell does not have permission to access user " + userId);
+ }
+ }
+
+ /** Returns whether a given {@code userId} corresponds to an existing user. */
+ public static boolean isUserExistent(@UserIdInt int userId, @NonNull Context context) {
+ return getUserHandles(context).contains(UserHandle.of(userId));
+ }
+
+ /** Returns all the alive users on the device. */
+ @NonNull
+ public static List<UserHandle> getUserHandles(@NonNull Context context) {
+ UserManager userManager = context.getSystemService(UserManager.class);
+ // This call requires the MANAGE_USERS permission.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return userManager.getUserHandles(true);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /** Returns whether a given {@code userId} corresponds to a managed profile. */
+ public static boolean isManagedProfile(@UserIdInt int userId, @NonNull Context context) {
+ UserManager userManager = context.getSystemService(UserManager.class);
+ // This call requires the QUERY_USERS permission.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return userManager.isManagedProfile(userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Returns whether a given {@code userId} corresponds to a running managed profile, i.e. the
+ * user is running and the quiet mode is not enabled.
+ */
+ public static boolean isProfileRunning(@UserIdInt int userId, @NonNull Context context) {
+ UserManager userManager = context.getSystemService(UserManager.class);
+ // This call requires the QUERY_USERS permission
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return userManager.isUserRunning(UserHandle.of(userId))
+ && !userManager.isQuietModeEnabled(UserHandle.of(userId));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+}
diff --git a/service/java/com/android/role/RoleService.java b/service/java/com/android/role/RoleService.java
index af119392d..485be4e72 100644
--- a/service/java/com/android/role/RoleService.java
+++ b/service/java/com/android/role/RoleService.java
@@ -41,7 +41,6 @@ import android.os.RemoteCallback;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.os.UserManager;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
@@ -61,8 +60,8 @@ import com.android.permission.util.ArrayUtils;
import com.android.permission.util.CollectionUtils;
import com.android.permission.util.ForegroundThread;
import com.android.permission.util.PackageUtils;
-import com.android.permission.util.PermissionUtils;
import com.android.permission.util.ThrottledRunnable;
+import com.android.permission.util.UserUtils;
import com.android.server.LocalManagerRegistry;
import com.android.server.SystemService;
import com.android.server.role.RoleServicePlatformHelper;
@@ -94,10 +93,18 @@ public class RoleService extends SystemService implements RoleUserState.Callback
private static final long GRANT_DEFAULT_ROLES_INTERVAL_MILLIS = 1000;
+ private static final String[] DEFAULT_APPLICATION_ROLES = {
+ RoleManager.ROLE_ASSISTANT,
+ RoleManager.ROLE_BROWSER,
+ RoleManager.ROLE_CALL_REDIRECTION,
+ RoleManager.ROLE_CALL_SCREENING,
+ RoleManager.ROLE_DIALER,
+ RoleManager.ROLE_HOME,
+ RoleManager.ROLE_SMS,
+ };
+
@NonNull
private final AppOpsManager mAppOpsManager;
- @NonNull
- private final UserManager mUserManager;
@NonNull
private final Object mLock = new Object();
@@ -149,7 +156,6 @@ public class RoleService extends SystemService implements RoleUserState.Callback
RoleControllerManager.initializeRemoteServiceComponentName(context);
mAppOpsManager = context.getSystemService(AppOpsManager.class);
- mUserManager = context.getSystemService(UserManager.class);
LocalManagerRegistry.addManager(RoleManagerLocal.class, new Local());
@@ -276,15 +282,9 @@ public class RoleService extends SystemService implements RoleUserState.Callback
RoleControllerManager controller = mControllers.get(userId);
if (controller == null) {
Context systemContext = getContext();
- Context context;
- try {
- context = systemContext.createPackageContextAsUser(
- systemContext.getPackageName(), 0, UserHandle.of(userId));
- } catch (PackageManager.NameNotFoundException e) {
- throw new RuntimeException(e);
- }
+ Context userContext = systemContext.createContextAsUser(UserHandle.of(userId), 0);
controller = RoleControllerManager.createWithInitializedRemoteServiceComponentName(
- ForegroundThread.getHandler(), context);
+ ForegroundThread.getHandler(), userContext);
mControllers.put(userId, controller);
}
return controller;
@@ -397,9 +397,9 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@NonNull
@Override
public List<String> getRoleHoldersAsUser(@NonNull String roleName, @UserIdInt int userId) {
- PermissionUtils.enforceCrossUserPermission(userId, false, "getRoleHoldersAsUser",
+ UserUtils.enforceCrossUserPermission(userId, false, "getRoleHoldersAsUser",
getContext());
- if (!isUserExistent(userId)) {
+ if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return Collections.emptyList();
}
@@ -420,9 +420,9 @@ public class RoleService extends SystemService implements RoleUserState.Callback
public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
@RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
@NonNull RemoteCallback callback) {
- PermissionUtils.enforceCrossUserPermission(userId, false, "addRoleHolderAsUser",
+ UserUtils.enforceCrossUserPermission(userId, false, "addRoleHolderAsUser",
getContext());
- if (!isUserExistent(userId)) {
+ if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return;
}
@@ -442,9 +442,9 @@ public class RoleService extends SystemService implements RoleUserState.Callback
public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
@RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
@NonNull RemoteCallback callback) {
- PermissionUtils.enforceCrossUserPermission(userId, false, "removeRoleHolderAsUser",
+ UserUtils.enforceCrossUserPermission(userId, false, "removeRoleHolderAsUser",
getContext());
- if (!isUserExistent(userId)) {
+ if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return;
}
@@ -464,9 +464,9 @@ public class RoleService extends SystemService implements RoleUserState.Callback
public void clearRoleHoldersAsUser(@NonNull String roleName,
@RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
@NonNull RemoteCallback callback) {
- PermissionUtils.enforceCrossUserPermission(userId, false, "clearRoleHoldersAsUser",
+ UserUtils.enforceCrossUserPermission(userId, false, "clearRoleHoldersAsUser",
getContext());
- if (!isUserExistent(userId)) {
+ if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return;
}
@@ -481,11 +481,62 @@ public class RoleService extends SystemService implements RoleUserState.Callback
}
@Override
+ @Nullable
+ public String getDefaultApplicationAsUser(@NonNull String roleName, @UserIdInt int userId) {
+ UserUtils.enforceCrossUserPermission(userId, false, "getDefaultApplicationAsUser",
+ getContext());
+ if (!UserUtils.isUserExistent(userId, getContext())) {
+ Log.e(LOG_TAG, "user " + userId + " does not exist");
+ return null;
+ }
+
+ getContext().enforceCallingOrSelfPermission(
+ Manifest.permission.MANAGE_DEFAULT_APPLICATIONS, "getDefaultApplicationAsUser");
+
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ Preconditions.checkArgumentIsSupported(DEFAULT_APPLICATION_ROLES, roleName);
+
+ ArraySet<String> roleHolders = getOrCreateUserState(
+ userId).getRoleHolders(roleName);
+ if (CollectionUtils.isEmpty(roleHolders)) {
+ return null;
+ }
+ return roleHolders.valueAt(0);
+ }
+
+ @Override
+ public void setDefaultApplicationAsUser(@NonNull String roleName,
+ @Nullable String packageName, @RoleManager.ManageHoldersFlags int flags,
+ @UserIdInt int userId, @NonNull RemoteCallback callback) {
+ UserUtils.enforceCrossUserPermission(userId, false, "setDefaultApplicationAsUser",
+ getContext());
+ if (!UserUtils.isUserExistent(userId, getContext())) {
+ Log.e(LOG_TAG, "user " + userId + " does not exist");
+ return;
+ }
+
+ getContext().enforceCallingOrSelfPermission(
+ Manifest.permission.MANAGE_DEFAULT_APPLICATIONS, "setDefaultApplicationAsUser");
+
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ Preconditions.checkArgumentIsSupported(DEFAULT_APPLICATION_ROLES, roleName);
+ Objects.requireNonNull(callback, "callback cannot be null");
+
+ RoleControllerManager roleControllerManager = getOrCreateController(userId);
+ if (packageName != null) {
+ roleControllerManager.onAddRoleHolder(roleName, packageName, flags, callback);
+ } else {
+ roleControllerManager.onClearRoleHolders(roleName, flags, callback);
+ }
+ }
+
+ @Override
public void addOnRoleHoldersChangedListenerAsUser(
@NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) {
- PermissionUtils.enforceCrossUserPermission(userId, true,
+ UserUtils.enforceCrossUserPermission(userId, true,
"addOnRoleHoldersChangedListenerAsUser", getContext());
- if (userId != UserHandleCompat.USER_ALL && !isUserExistent(userId)) {
+ if (userId != UserHandleCompat.USER_ALL && !UserUtils.isUserExistent(userId,
+ getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return;
}
@@ -503,9 +554,10 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@Override
public void removeOnRoleHoldersChangedListenerAsUser(
@NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) {
- PermissionUtils.enforceCrossUserPermission(userId, true,
+ UserUtils.enforceCrossUserPermission(userId, true,
"removeOnRoleHoldersChangedListenerAsUser", getContext());
- if (userId != UserHandleCompat.USER_ALL && !isUserExistent(userId)) {
+ if (userId != UserHandleCompat.USER_ALL && !UserUtils.isUserExistent(userId,
+ getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return;
}
@@ -604,15 +656,6 @@ public class RoleService extends SystemService implements RoleUserState.Callback
return getOrCreateUserState(userId).getHeldRoles(packageName);
}
- private boolean isUserExistent(@UserIdInt int userId) {
- final long identity = Binder.clearCallingIdentity();
- try {
- return mUserManager.getUserHandles(true).contains(UserHandle.of(userId));
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
@Override
public int handleShellCommand(@NonNull ParcelFileDescriptor in,
@NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
@@ -671,7 +714,7 @@ public class RoleService extends SystemService implements RoleUserState.Callback
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
}
- if (!isUserExistent(userId)) {
+ if (!UserUtils.isUserExistent(userId, context)) {
return false;
}
@@ -707,8 +750,8 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@Override
public String getSmsRoleHolder(int userId) {
final Context context = getContext();
- PermissionUtils.enforceCrossUserPermission(userId, false, "getSmsRoleHolder", context);
- if (!isUserExistent(userId)) {
+ UserUtils.enforceCrossUserPermission(userId, false, "getSmsRoleHolder", context);
+ if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return null;
}
diff --git a/service/java/com/android/role/RoleShellCommand.java b/service/java/com/android/role/RoleShellCommand.java
index 357ce5f76..808a64cb4 100644
--- a/service/java/com/android/role/RoleShellCommand.java
+++ b/service/java/com/android/role/RoleShellCommand.java
@@ -29,11 +29,14 @@ import com.android.modules.utils.BasicShellCommandHandler;
import com.android.permission.compat.UserHandleCompat;
import java.io.PrintWriter;
+import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
@RequiresApi(Build.VERSION_CODES.S)
class RoleShellCommand extends BasicShellCommandHandler {
+ private static final String ROLE_HOLDER_SEPARATOR = ";";
+
@NonNull
private final IRoleManager mRoleManager;
@@ -74,6 +77,8 @@ class RoleShellCommand extends BasicShellCommandHandler {
PrintWriter pw = getOutPrintWriter();
try {
switch (cmd) {
+ case "get-role-holders":
+ return runGetRoleHolders();
case "add-role-holder":
return runAddRoleHolder();
case "remove-role-holder":
@@ -108,6 +113,15 @@ class RoleShellCommand extends BasicShellCommandHandler {
return Integer.parseInt(flags);
}
+ private int runGetRoleHolders() throws RemoteException {
+ int userId = getUserIdMaybe();
+ String roleName = getNextArgRequired();
+
+ List<String> roleHolders = mRoleManager.getRoleHoldersAsUser(roleName, userId);
+ getOutPrintWriter().println(String.join(ROLE_HOLDER_SEPARATOR, roleHolders));
+ return 0;
+ }
+
private int runAddRoleHolder() throws RemoteException {
int userId = getUserIdMaybe();
String roleName = getNextArgRequired();
@@ -155,6 +169,7 @@ class RoleShellCommand extends BasicShellCommandHandler {
pw.println(" help or -h");
pw.println(" Print this help text.");
pw.println();
+ pw.println(" get-role-holders [--user USER_ID] ROLE");
pw.println(" add-role-holder [--user USER_ID] ROLE PACKAGE [FLAGS]");
pw.println(" remove-role-holder [--user USER_ID] ROLE PACKAGE [FLAGS]");
pw.println(" clear-role-holders [--user USER_ID] ROLE [FLAGS]");
diff --git a/service/java/com/android/role/TEST_MAPPING b/service/java/com/android/role/TEST_MAPPING
index 0d7bc1476..15173a9da 100644
--- a/service/java/com/android/role/TEST_MAPPING
+++ b/service/java/com/android/role/TEST_MAPPING
@@ -1,10 +1,10 @@
{
"presubmit": [
{
- "name": "CtsStatsdHostTestCases",
+ "name": "CtsAppSecurityHostTestCases",
"options": [
{
- "include-filter": "android.cts.statsd.atom.UidAtomTests#testRoleHolder"
+ "include-filter": "android.appsecurity.cts.StatsdAppSecurityAtomTest#testRoleHolder"
}
]
},
@@ -16,5 +16,22 @@
}
]
}
+ ],
+ "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"
+ }
+ ]
+ }
]
}
diff --git a/service/java/com/android/role/persistence/RolesPersistenceImpl.java b/service/java/com/android/role/persistence/RolesPersistenceImpl.java
index f66257f13..76cf8f81f 100644
--- a/service/java/com/android/role/persistence/RolesPersistenceImpl.java
+++ b/service/java/com/android/role/persistence/RolesPersistenceImpl.java
@@ -19,6 +19,7 @@ package com.android.role.persistence;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ApexEnvironment;
+import android.os.FileUtils;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -26,7 +27,10 @@ import android.util.AtomicFile;
import android.util.Log;
import android.util.Xml;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.build.SdkLevel;
import com.android.permission.persistence.IoUtils;
+import com.android.server.security.FileIntegrity;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -54,6 +58,7 @@ public class RolesPersistenceImpl implements RolesPersistence {
private static final String APEX_MODULE_NAME = "com.android.permission";
private static final String ROLES_FILE_NAME = "roles.xml";
+ private static final String ROLES_RESERVE_COPY_FILE_NAME = ROLES_FILE_NAME + ".reservecopy";
private static final String TAG_ROLES = "roles";
private static final String TAG_ROLE = "role";
@@ -63,6 +68,27 @@ public class RolesPersistenceImpl implements RolesPersistence {
private static final String ATTRIBUTE_NAME = "name";
private static final String ATTRIBUTE_PACKAGES_HASH = "packagesHash";
+ @VisibleForTesting
+ interface Injector {
+ void enableFsVerity(@NonNull File file) throws IOException;
+ }
+
+ @NonNull
+ private final Injector mInjector;
+
+ RolesPersistenceImpl() {
+ this(file -> {
+ if (SdkLevel.isAtLeastU()) {
+ FileIntegrity.setUpFsVerity(file);
+ }
+ });
+ }
+
+ @VisibleForTesting
+ RolesPersistenceImpl(@NonNull Injector injector) {
+ mInjector = injector;
+ }
+
@Nullable
@Override
public RolesState readForUser(@NonNull UserHandle user) {
@@ -74,8 +100,19 @@ public class RolesPersistenceImpl implements RolesPersistence {
} catch (FileNotFoundException e) {
Log.i(LOG_TAG, "roles.xml not found");
return null;
- } catch (XmlPullParserException | IOException e) {
- throw new IllegalStateException("Failed to read roles.xml: " + file , e);
+ } catch (Exception e) {
+ File reserveFile = getReserveCopyFile(user);
+ Log.wtf(LOG_TAG, "Reading from reserve copy: " + reserveFile, e);
+ try (FileInputStream inputStream = new AtomicFile(reserveFile).openRead()) {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(inputStream, null);
+ return parseXml(parser);
+ } catch (Exception exceptionReadingReserveFile) {
+ Log.e(LOG_TAG, "Failed to read reserve copy: " + reserveFile,
+ exceptionReadingReserveFile);
+ // Reserve copy failed, rethrow the original exception wrapped as runtime.
+ throw new IllegalStateException("Failed to read roles.xml: " + file , e);
+ }
}
}
@@ -147,6 +184,9 @@ public class RolesPersistenceImpl implements RolesPersistence {
@Override
public void writeForUser(@NonNull RolesState roles, @NonNull UserHandle user) {
+ File reserveFile = getReserveCopyFile(user);
+ reserveFile.delete();
+
File file = getFile(user);
AtomicFile atomicFile = new AtomicFile(file);
FileOutputStream outputStream = null;
@@ -166,9 +206,25 @@ public class RolesPersistenceImpl implements RolesPersistence {
Log.wtf(LOG_TAG, "Failed to write roles.xml, restoring backup: " + file,
e);
atomicFile.failWrite(outputStream);
+ return;
} finally {
IoUtils.closeQuietly(outputStream);
}
+
+ try (FileInputStream in = new FileInputStream(file);
+ FileOutputStream out = new FileOutputStream(reserveFile)) {
+ FileUtils.copy(in, out);
+ out.getFD().sync();
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Failed to write reserve copy: " + reserveFile, e);
+ }
+
+ try {
+ mInjector.enableFsVerity(file);
+ mInjector.enableFsVerity(reserveFile);
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Failed to verity-protect roles", e);
+ }
}
private static void serializeRoles(@NonNull XmlSerializer serializer,
@@ -207,12 +263,21 @@ public class RolesPersistenceImpl implements RolesPersistence {
@Override
public void deleteForUser(@NonNull UserHandle user) {
getFile(user).delete();
+ getReserveCopyFile(user).delete();
}
+ @VisibleForTesting
@NonNull
- private static File getFile(@NonNull UserHandle user) {
+ static File getFile(@NonNull UserHandle user) {
ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment(APEX_MODULE_NAME);
File dataDirectory = apexEnvironment.getDeviceProtectedDataDirForUser(user);
return new File(dataDirectory, ROLES_FILE_NAME);
}
+
+ @NonNull
+ private static File getReserveCopyFile(@NonNull UserHandle user) {
+ ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment(APEX_MODULE_NAME);
+ File dataDirectory = apexEnvironment.getDeviceProtectedDataDirForUser(user);
+ return new File(dataDirectory, ROLES_RESERVE_COPY_FILE_NAME);
+ }
}
diff --git a/service/java/com/android/safetycenter/ApiLock.java b/service/java/com/android/safetycenter/ApiLock.java
new file mode 100644
index 000000000..91466d3d5
--- /dev/null
+++ b/service/java/com/android/safetycenter/ApiLock.java
@@ -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 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.
+ *
+ * <p>This lock is instantiated once by the {@link SafetyCenterService} and guards any access to the
+ * Safety Center mutable state.
+ *
+ * @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
new file mode 100644
index 000000000..25cab343f
--- /dev/null
+++ b/service/java/com/android/safetycenter/DevicePolicyResources.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 com.android.safetycenter;
+
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.StringRes;
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyResourcesManager;
+import android.content.Context;
+import android.os.Binder;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.safetycenter.resources.SafetyCenterResourcesContext;
+
+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.";
+ private static final String WORK_PROFILE_PAUSED_TITLE = "WORK_PROFILE_PAUSED";
+
+ private DevicePolicyResources() {}
+
+ /**
+ * Returns the updated string for the given {@code safetySourceId} by calling {@link
+ * DevicePolicyResourcesManager#getString}.
+ */
+ static String getSafetySourceWorkString(
+ SafetyCenterResourcesContext safetyCenterResourcesContext,
+ String safetySourceId,
+ @StringRes int workResId) {
+ return getEnterpriseString(
+ safetyCenterResourcesContext,
+ safetySourceId,
+ () -> safetyCenterResourcesContext.getString(workResId));
+ }
+
+ /**
+ * Returns the updated string for the {@code work_profile_paused} string by calling {@link
+ * DevicePolicyResourcesManager#getString}.
+ */
+ static String getWorkProfilePausedString(
+ SafetyCenterResourcesContext safetyCenterResourcesContext) {
+ return getEnterpriseString(
+ safetyCenterResourcesContext,
+ WORK_PROFILE_PAUSED_TITLE,
+ () -> safetyCenterResourcesContext.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
+ // necessarily match the caller’s package when making Binder calls, so the calling identity
+ // has to be cleared.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ return requireNonNull(context.getSystemService(DevicePolicyManager.class))
+ .getResources()
+ .getString(SAFETY_CENTER_PREFIX + devicePolicyIdentifier, defaultValueLoader);
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+}
diff --git a/service/java/com/android/safetycenter/PendingIntentFactory.java b/service/java/com/android/safetycenter/PendingIntentFactory.java
new file mode 100644
index 000000000..8c447c477
--- /dev/null
+++ b/service/java/com/android/safetycenter/PendingIntentFactory.java
@@ -0,0 +1,246 @@
+/*
+ * 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;
+
+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.PackageManager;
+import android.content.pm.PackageManager.ResolveInfoFlags;
+import android.content.pm.ResolveInfo;
+import android.os.Binder;
+import android.os.UserHandle;
+import android.util.Log;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.safetycenter.resources.SafetyCenterResourcesContext;
+
+import java.util.Arrays;
+
+/**
+ * Helps build or retrieve {@link PendingIntent} instances.
+ *
+ * @hide
+ */
+@RequiresApi(TIRAMISU)
+public final class PendingIntentFactory {
+
+ private static final String TAG = "PendingIntentFactory";
+
+ private static final int DEFAULT_REQUEST_CODE = 0;
+
+ private static final String IS_SETTINGS_HOMEPAGE = "is_from_settings_homepage";
+
+ private final Context mContext;
+ private final SafetyCenterResourcesContext mSafetyCenterResourcesContext;
+
+ PendingIntentFactory(
+ Context context, SafetyCenterResourcesContext safetyCenterResourcesContext) {
+ mContext = context;
+ mSafetyCenterResourcesContext = safetyCenterResourcesContext;
+ }
+
+ /**
+ * 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>The {@code PendingIntent} is associated with a specific source given by {@code sourceId}.
+ *
+ * <p>Returns {@code null} if the required {@link PendingIntent} cannot be created or if there
+ * is no valid target for the given {@code intentAction}.
+ */
+ @Nullable
+ PendingIntent getPendingIntent(
+ String sourceId,
+ @Nullable String intentAction,
+ String packageName,
+ @UserIdInt int userId,
+ boolean isQuietModeEnabled) {
+ if (intentAction == null) {
+ return null;
+ }
+ Context packageContext = createPackageContextAsUser(mContext, packageName, userId);
+ if (packageContext == null) {
+ return null;
+ }
+ Intent intent = createIntent(packageContext, sourceId, intentAction, isQuietModeEnabled);
+ if (intent == null) {
+ return null;
+ }
+ return getActivityPendingIntent(
+ packageContext, DEFAULT_REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE);
+ }
+
+ @Nullable
+ private Intent createIntent(
+ Context packageContext,
+ String sourceId,
+ String intentAction,
+ boolean isQuietModeEnabled) {
+ Intent intent = new Intent(intentAction);
+
+ if (shouldAddSettingsHomepageExtra(sourceId)) {
+ // Identify this intent as coming from Settings. Because this intent is actually coming
+ // from Safety Center, which is served by PermissionController, this is useful to
+ // indicate that it is presented as part of the Settings app.
+ //
+ // In particular, the AOSP Settings app uses this to ensure that two-pane mode works
+ // correctly.
+ intent.putExtra(IS_SETTINGS_HOMEPAGE, true);
+ // Given we've added an extra to this intent, set an ID on it to ensure that it is not
+ // considered equal to the same intent without the extra. PendingIntents are cached
+ // using Intent equality as the key, and we want to make sure the extra is propagated.
+ intent.setIdentifier("with_settings_homepage_extra");
+ }
+
+ // 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)) {
+ 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) {
+ return explicitIntent;
+ }
+
+ return null;
+ }
+
+ private boolean shouldAddSettingsHomepageExtra(String sourceId) {
+ return Arrays.asList(
+ mSafetyCenterResourcesContext
+ .getStringByName("config_useSettingsHomepageIntentExtra")
+ .split(","))
+ .contains(sourceId);
+ }
+
+ private static boolean intentResolves(Context packageContext, Intent intent) {
+ return resolveActivity(packageContext, intent) != null;
+ }
+
+ @Nullable
+ private static ResolveInfo resolveActivity(Context packageContext, Intent intent) {
+ PackageManager packageManager = packageContext.getPackageManager();
+ // This call requires the INTERACT_ACROSS_USERS permission as the `packageContext` could
+ // belong to another user.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ return packageManager.resolveActivity(intent, ResolveInfoFlags.of(0));
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ /**
+ * Creates a {@link PendingIntent} to start an Activity from the given {@code packageContext}.
+ *
+ * <p>This function can only return {@code null} if the {@link PendingIntent#FLAG_NO_CREATE}
+ * flag is passed in.
+ */
+ @Nullable
+ public static PendingIntent getNullableActivityPendingIntent(
+ Context packageContext, int requestCode, Intent intent, int flags) {
+ // This call requires Binder identity to be cleared for getIntentSender() to be allowed to
+ // send as another package.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ return PendingIntent.getActivity(packageContext, requestCode, intent, flags);
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ /**
+ * Creates a {@link PendingIntent} to start an Activity from the given {@code packageContext}.
+ *
+ * <p>{@code flags} must not include {@link PendingIntent#FLAG_NO_CREATE}
+ */
+ public static PendingIntent getActivityPendingIntent(
+ Context packageContext, int requestCode, Intent intent, int flags) {
+ if ((flags & PendingIntent.FLAG_NO_CREATE) != 0) {
+ throw new IllegalArgumentException("flags must not include FLAG_NO_CREATE");
+ }
+ return requireNonNull(
+ getNullableActivityPendingIntent(packageContext, requestCode, intent, flags));
+ }
+
+ /**
+ * Creates a non-protected broadcast {@link PendingIntent} which can only be received by the
+ * system. Use this method to create PendingIntents to be received by Context-registered
+ * receivers, for example for notification-related callbacks.
+ *
+ * <p>{@code flags} must include {@link PendingIntent#FLAG_IMMUTABLE} and must not include
+ * {@link PendingIntent#FLAG_NO_CREATE}
+ */
+ public static PendingIntent getNonProtectedSystemOnlyBroadcastPendingIntent(
+ Context context, int requestCode, Intent intent, int flags) {
+ if ((flags & PendingIntent.FLAG_IMMUTABLE) == 0) {
+ throw new IllegalArgumentException("flags must include FLAG_IMMUTABLE");
+ }
+ if ((flags & PendingIntent.FLAG_NO_CREATE) != 0) {
+ throw new IllegalArgumentException("flags must not include FLAG_NO_CREATE");
+ }
+ intent.setPackage("android");
+ // This call is needed to be allowed to send the broadcast as the "android" package.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ return PendingIntent.getBroadcast(context, requestCode, intent, flags);
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ /** Creates a {@link Context} for the given {@code packageName} and {@code userId}. */
+ @Nullable
+ public static Context createPackageContextAsUser(
+ Context context, String packageName, @UserIdInt int userId) {
+ // This call requires the INTERACT_ACROSS_USERS permission.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ return context.createPackageContextAsUser(packageName, 0, UserHandle.of(userId));
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Package name " + packageName + " not found", e);
+ return null;
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+}
diff --git a/service/java/com/android/safetycenter/RefreshReasons.java b/service/java/com/android/safetycenter/RefreshReasons.java
new file mode 100644
index 000000000..ee318c7fd
--- /dev/null
+++ b/service/java/com/android/safetycenter/RefreshReasons.java
@@ -0,0 +1,106 @@
+/*
+ * 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;
+
+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;
+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;
+import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_PAGE_OPEN;
+import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_PERIODIC;
+import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_RESCAN_BUTTON_CLICK;
+import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_SAFETY_CENTER_ENABLED;
+
+import android.annotation.TargetApi;
+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";
+
+ private RefreshReasons() {}
+
+ /**
+ * Validates the given {@link RefreshReason}, and throws an {@link IllegalArgumentException} in
+ * case of unexpected value.
+ */
+ static void validate(@RefreshReason int refreshReason) {
+ switch (refreshReason) {
+ case REFRESH_REASON_RESCAN_BUTTON_CLICK:
+ case REFRESH_REASON_PAGE_OPEN:
+ case REFRESH_REASON_DEVICE_REBOOT:
+ case REFRESH_REASON_DEVICE_LOCALE_CHANGE:
+ case REFRESH_REASON_SAFETY_CENTER_ENABLED:
+ case REFRESH_REASON_OTHER:
+ return;
+ }
+ if (SdkLevel.isAtLeastU() && refreshReason == REFRESH_REASON_PERIODIC) {
+ return;
+ }
+ throw new IllegalArgumentException("Unexpected refresh reason: " + refreshReason);
+ }
+
+ /** Converts the given {@link RefreshReason} to a {@link RefreshRequestType}. */
+ @TargetApi(UPSIDE_DOWN_CAKE)
+ @RefreshRequestType
+ static int toRefreshRequestType(@RefreshReason int refreshReason) {
+ switch (refreshReason) {
+ case REFRESH_REASON_RESCAN_BUTTON_CLICK:
+ return EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA;
+ case REFRESH_REASON_PAGE_OPEN:
+ case REFRESH_REASON_DEVICE_REBOOT:
+ case REFRESH_REASON_DEVICE_LOCALE_CHANGE:
+ case REFRESH_REASON_SAFETY_CENTER_ENABLED:
+ case REFRESH_REASON_OTHER:
+ case REFRESH_REASON_PERIODIC:
+ return EXTRA_REFRESH_REQUEST_TYPE_GET_DATA;
+ }
+ Log.w(TAG, "Unexpected refresh reason: " + refreshReason);
+ return EXTRA_REFRESH_REQUEST_TYPE_GET_DATA;
+ }
+
+ /**
+ * Returns {@code true} if the given {@link RefreshReason} corresponds to a background refresh.
+ */
+ @TargetApi(UPSIDE_DOWN_CAKE)
+ static boolean isBackgroundRefresh(@RefreshReason int refreshReason) {
+ switch (refreshReason) {
+ case REFRESH_REASON_DEVICE_REBOOT:
+ case REFRESH_REASON_DEVICE_LOCALE_CHANGE:
+ case REFRESH_REASON_SAFETY_CENTER_ENABLED:
+ case REFRESH_REASON_OTHER:
+ case REFRESH_REASON_PERIODIC:
+ return true;
+ case REFRESH_REASON_PAGE_OPEN:
+ case REFRESH_REASON_RESCAN_BUTTON_CLICK:
+ return false;
+ }
+ Log.w(TAG, "Unexpected refresh reason: " + refreshReason);
+ return false;
+ }
+}
diff --git a/service/java/com/android/safetycenter/SafetyCenterBroadcastDispatcher.java b/service/java/com/android/safetycenter/SafetyCenterBroadcastDispatcher.java
new file mode 100644
index 000000000..e8e6befe5
--- /dev/null
+++ b/service/java/com/android/safetycenter/SafetyCenterBroadcastDispatcher.java
@@ -0,0 +1,405 @@
+/*
+ * 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;
+
+import static android.Manifest.permission.READ_SAFETY_CENTER_STATUS;
+import static android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE;
+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;
+import static android.safetycenter.SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED;
+import static android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID;
+import static android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE;
+import static android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCE_IDS;
+import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_PAGE_OPEN;
+import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_SAFETY_CENTER_ENABLED;
+
+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;
+import android.content.Intent;
+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 com.android.permission.util.PackageUtils;
+import com.android.safetycenter.SafetyCenterConfigReader.Broadcast;
+import com.android.safetycenter.data.SafetyCenterDataManager;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
+/**
+ * A class that dispatches SafetyCenter broadcasts.
+ *
+ * <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";
+
+ private final Context mContext;
+ private final SafetyCenterConfigReader mSafetyCenterConfigReader;
+ private final SafetyCenterRefreshTracker mSafetyCenterRefreshTracker;
+ private final SafetyCenterDataManager mSafetyCenterDataManager;
+
+ SafetyCenterBroadcastDispatcher(
+ Context context,
+ SafetyCenterConfigReader safetyCenterConfigReader,
+ SafetyCenterRefreshTracker safetyCenterRefreshTracker,
+ SafetyCenterDataManager safetyCenterDataManager) {
+ mContext = context;
+ mSafetyCenterConfigReader = safetyCenterConfigReader;
+ mSafetyCenterRefreshTracker = safetyCenterRefreshTracker;
+ mSafetyCenterDataManager = safetyCenterDataManager;
+ }
+
+ /**
+ * Triggers a refresh of safety sources by sending them broadcasts with action {@link
+ * SafetyCenterManager#ACTION_REFRESH_SAFETY_SOURCES}, and returns the associated broadcast id.
+ *
+ * <p>Returns {@code null} if no broadcast was sent.
+ *
+ * @param safetySourceIds list of IDs to specify the safety sources to be refreshed or a {@code
+ * null} value to refresh all safety sources.
+ */
+ @Nullable
+ String sendRefreshSafetySources(
+ @RefreshReason int refreshReason,
+ UserProfileGroup userProfileGroup,
+ @Nullable List<String> safetySourceIds) {
+ List<Broadcast> broadcasts = mSafetyCenterConfigReader.getBroadcasts();
+ BroadcastOptions broadcastOptions = createBroadcastOptions();
+
+ String broadcastId =
+ mSafetyCenterRefreshTracker.reportRefreshInProgress(
+ refreshReason, userProfileGroup);
+ boolean hasSentAtLeastOneBroadcast = false;
+
+ for (int i = 0; i < broadcasts.size(); i++) {
+ Broadcast broadcast = broadcasts.get(i);
+
+ hasSentAtLeastOneBroadcast |=
+ sendRefreshSafetySourcesBroadcast(
+ broadcast,
+ broadcastOptions,
+ refreshReason,
+ userProfileGroup,
+ broadcastId,
+ safetySourceIds);
+ }
+
+ if (!hasSentAtLeastOneBroadcast) {
+ mSafetyCenterRefreshTracker.clearRefresh(broadcastId);
+ return null;
+ }
+
+ return broadcastId;
+ }
+
+ private boolean sendRefreshSafetySourcesBroadcast(
+ Broadcast broadcast,
+ BroadcastOptions broadcastOptions,
+ @RefreshReason int refreshReason,
+ UserProfileGroup userProfileGroup,
+ 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 =
+ getUserIdsToSourceIds(broadcast, userProfileGroup, refreshReason);
+
+ for (int i = 0; i < userIdsToSourceIds.size(); i++) {
+ int userId = userIdsToSourceIds.keyAt(i);
+ List<String> sourceIds = userIdsToSourceIds.valueAt(i);
+
+ if (!deniedSourceIds.isEmpty()) {
+ sourceIds = new ArrayList<>(sourceIds);
+ sourceIds.removeAll(deniedSourceIds);
+ }
+
+ if (requiredSourceIds != null) {
+ sourceIds = new ArrayList<>(sourceIds);
+ sourceIds.retainAll(requiredSourceIds);
+ }
+
+ if (sourceIds.isEmpty()) {
+ continue;
+ }
+
+ Intent intent = createRefreshIntent(requestType, packageName, sourceIds, broadcastId);
+ boolean broadcastWasSent =
+ sendBroadcastIfResolves(intent, UserHandle.of(userId), broadcastOptions);
+ if (broadcastWasSent) {
+ mSafetyCenterRefreshTracker.reportSourceRefreshesInFlight(
+ broadcastId, sourceIds, userId);
+ }
+ hasSentAtLeastOneBroadcast |= broadcastWasSent;
+ }
+
+ return hasSentAtLeastOneBroadcast;
+ }
+
+ /**
+ * Triggers an {@link SafetyCenterManager#ACTION_SAFETY_CENTER_ENABLED_CHANGED} broadcast for
+ * all safety sources.
+ *
+ * <p>This method also sends an implicit broadcast globally (which requires the {@link
+ * android.Manifest.permission#READ_SAFETY_CENTER_STATUS} permission).
+ */
+ // TODO(b/227310195): Consider adding a boolean extra to the intent instead of having clients
+ // rely on SafetyCenterManager#isSafetyCenterEnabled()?
+ void sendEnabledChanged() {
+ List<Broadcast> broadcasts = mSafetyCenterConfigReader.getBroadcasts();
+ BroadcastOptions broadcastOptions = createBroadcastOptions();
+ List<UserProfileGroup> userProfileGroups =
+ UserProfileGroup.getAllUserProfileGroups(mContext);
+
+ for (int i = 0; i < broadcasts.size(); i++) {
+ Broadcast broadcast = broadcasts.get(i);
+
+ sendEnabledChangedBroadcast(broadcast, broadcastOptions, userProfileGroups);
+ }
+
+ Intent implicitIntent = createImplicitEnabledChangedIntent();
+ sendBroadcast(implicitIntent, UserHandle.SYSTEM, READ_SAFETY_CENTER_STATUS, null);
+ }
+
+ private void sendEnabledChangedBroadcast(
+ Broadcast broadcast,
+ 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);
+
+ for (int j = 0; j < userIdsToSourceIds.size(); j++) {
+ int userId = userIdsToSourceIds.keyAt(j);
+
+ sendBroadcastIfResolves(intent, UserHandle.of(userId), broadcastOptions);
+ }
+ }
+ }
+
+ private boolean sendBroadcastIfResolves(
+ Intent intent, UserHandle userHandle, @Nullable BroadcastOptions broadcastOptions) {
+ if (!doesBroadcastResolve(intent, userHandle)) {
+ Log.w(
+ TAG,
+ "No receiver for intent targeting "
+ + intent.getPackage()
+ + " and user "
+ + userHandle);
+ return false;
+ }
+ Log.v(
+ TAG,
+ "Found receiver for intent targeting "
+ + intent.getPackage()
+ + " and user "
+ + userHandle);
+ 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,
+ String permission,
+ @Nullable BroadcastOptions broadcastOptions) {
+ // This call requires the INTERACT_ACROSS_USERS permission.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ mContext.sendBroadcastAsUser(
+ intent,
+ userHandle,
+ permission,
+ broadcastOptions == null ? null : broadcastOptions.toBundle());
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ private boolean doesBroadcastResolve(Intent broadcastIntent, UserHandle userHandle) {
+ return !PackageUtils.queryUnfilteredBroadcastReceiversAsUser(
+ broadcastIntent, 0, userHandle.getIdentifier(), mContext)
+ .isEmpty();
+ }
+
+ private static Intent createExplicitEnabledChangedIntent(String packageName) {
+ return createImplicitEnabledChangedIntent().setPackage(packageName);
+ }
+
+ private static Intent createImplicitEnabledChangedIntent() {
+ return createBroadcastIntent(ACTION_SAFETY_CENTER_ENABLED_CHANGED);
+ }
+
+ private static Intent createRefreshIntent(
+ @RefreshRequestType int requestType,
+ 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);
+ }
+
+ private static Intent createBroadcastIntent(String intentAction) {
+ return new Intent(intentAction).setFlags(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();
+ // This call requires the START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ broadcastOptions.setTemporaryAppAllowlist(
+ allowListDuration.toMillis(),
+ TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ REASON_REFRESH_SAFETY_SOURCES,
+ "Safety Center is requesting data from safety sources");
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ return broadcastOptions;
+ }
+
+ /** Returns the list of source IDs for which refreshing is denied for the given reason. */
+ private static Set<String> getRefreshDeniedSourceIds(@RefreshReason int refreshReason) {
+ if (RefreshReasons.isBackgroundRefresh(refreshReason)) {
+ return SafetyCenterFlags.getBackgroundRefreshDeniedSourceIds();
+ } else {
+ return Collections.emptySet();
+ }
+ }
+
+ /**
+ * Returns a flattened mapping from user IDs to lists of source IDs for those users. The map is
+ * in the form of a {@link SparseArray} where the int keys are user IDs and the values are the
+ * lists of source IDs.
+ *
+ * <p>The set of user IDs (keys) is the profile parent user ID of {@code userProfileGroup} plus
+ * the (possibly empty) set of running managed profile user IDs in that group.
+ *
+ * <p>Every value present is a non-empty list, but the overall result may be empty.
+ */
+ private SparseArray<List<String>> getUserIdsToSourceIds(
+ Broadcast broadcast,
+ UserProfileGroup userProfileGroup,
+ @RefreshReason int refreshReason) {
+ int[] managedProfileIds = userProfileGroup.getManagedRunningProfilesUserIds();
+ SparseArray<List<String>> result = new SparseArray<>(managedProfileIds.length + 1);
+ List<String> profileParentSources =
+ getSourceIdsForRefreshReason(
+ refreshReason,
+ broadcast.getSourceIdsForProfileParent(),
+ broadcast.getSourceIdsForProfileParentOnPageOpen(),
+ userProfileGroup.getProfileParentUserId());
+
+ if (!profileParentSources.isEmpty()) {
+ result.put(userProfileGroup.getProfileParentUserId(), profileParentSources);
+ }
+
+ for (int i = 0; i < managedProfileIds.length; i++) {
+ List<String> managedProfileSources =
+ getSourceIdsForRefreshReason(
+ refreshReason,
+ broadcast.getSourceIdsForManagedProfiles(),
+ broadcast.getSourceIdsForManagedProfilesOnPageOpen(),
+ managedProfileIds[i]);
+
+ if (!managedProfileSources.isEmpty()) {
+ result.put(managedProfileIds[i], managedProfileSources);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns the sources to refresh for the given {@code refreshReason}.
+ *
+ * <p>For {@link SafetyCenterManager#REFRESH_REASON_PAGE_OPEN}, returns a copy of {@code
+ * allSourceIds} filtered to contain only sources that have refreshOnPageOpenAllowed in the XML
+ * config, or are in the safety_center_override_refresh_on_page_open_sources flag, or don't have
+ * any {@link SafetySourceData} provided.
+ */
+ private List<String> getSourceIdsForRefreshReason(
+ @RefreshReason int refreshReason,
+ List<String> allSourceIds,
+ List<String> pageOpenSourceIds,
+ @UserIdInt int userId) {
+ if (refreshReason != REFRESH_REASON_PAGE_OPEN) {
+ return allSourceIds;
+ }
+
+ List<String> sourceIds = new ArrayList<>();
+
+ ArraySet<String> flagAllowListedSourceIds =
+ SafetyCenterFlags.getOverrideRefreshOnPageOpenSourceIds();
+
+ for (int i = 0; i < allSourceIds.size(); i++) {
+ String sourceId = allSourceIds.get(i);
+ if (pageOpenSourceIds.contains(sourceId)
+ || flagAllowListedSourceIds.contains(sourceId)
+ || mSafetyCenterDataManager.getSafetySourceDataInternal(
+ SafetySourceKey.of(sourceId, userId))
+ == null) {
+ sourceIds.add(sourceId);
+ }
+ }
+
+ return unmodifiableList(sourceIds);
+ }
+}
diff --git a/service/java/com/android/safetycenter/SafetyCenterConfigReader.java b/service/java/com/android/safetycenter/SafetyCenterConfigReader.java
index d341ebd35..92959a47d 100644
--- a/service/java/com/android/safetycenter/SafetyCenterConfigReader.java
+++ b/service/java/com/android/safetycenter/SafetyCenterConfigReader.java
@@ -18,12 +18,15 @@ package com.android.safetycenter;
import static android.os.Build.VERSION_CODES.TIRAMISU;
-import android.annotation.NonNull;
+import static java.util.Collections.unmodifiableList;
+import static java.util.Objects.requireNonNull;
+
import android.annotation.Nullable;
-import android.annotation.StringRes;
-import android.content.Context;
import android.content.res.Resources;
import android.safetycenter.config.SafetyCenterConfig;
+import android.safetycenter.config.SafetySource;
+import android.safetycenter.config.SafetySourcesGroup;
+import android.util.ArrayMap;
import android.util.Log;
import androidx.annotation.RequiresApi;
@@ -33,88 +36,205 @@ import com.android.safetycenter.config.SafetyCenterConfigParser;
import com.android.safetycenter.resources.SafetyCenterResourcesContext;
import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import javax.annotation.concurrent.NotThreadSafe;
/**
- * A class that reads the {@link SafetyCenterConfig} from the associated {@link
- * SafetyCenterResourcesContext}.
+ * A class that reads the {@link SafetyCenterConfig} and allows overriding it for tests.
+ *
+ * <p>This class isn't thread safe. Thread safety must be handled by the caller.
+ *
+ * @hide
*/
@RequiresApi(TIRAMISU)
-final class SafetyCenterConfigReader {
+@NotThreadSafe
+public final class SafetyCenterConfigReader {
private static final String TAG = "SafetyCenterConfigReade";
- private final Object mSafetyCenterConfigLock = new Object();
- @NonNull private final SafetyCenterResourcesContext mSafetyCenterResourcesContext;
+ private final SafetyCenterResourcesContext mSafetyCenterResourcesContext;
+
+ @Nullable private SafetyCenterConfigInternal mConfigInternalFromXml;
- @Nullable private SafetyCenterConfig mSafetyCenterConfig;
+ @Nullable private SafetyCenterConfigInternal mConfigInternalOverrideForTests;
+
+ /** Creates a {@link SafetyCenterConfigReader} from a {@link SafetyCenterResourcesContext}. */
+ SafetyCenterConfigReader(SafetyCenterResourcesContext safetyCenterResourcesContext) {
+ mSafetyCenterResourcesContext = safetyCenterResourcesContext;
+ }
/**
- * Creates a {@link SafetyCenterConfigReader} from a {@link Context} object by wrapping it into
- * a {@link SafetyCenterResourcesContext}.
+ * Loads the {@link SafetyCenterConfig} from the XML file defined in {@code
+ * safety_center_config.xml}; and returns whether this was successful.
+ *
+ * <p>This method must be called prior to any other call to this class. This call must also be
+ * successful; interacting with this class requires checking that the boolean value returned by
+ * this method was {@code true}.
*/
- SafetyCenterConfigReader(@NonNull Context context) {
- mSafetyCenterResourcesContext = new SafetyCenterResourcesContext(context);
+ boolean loadConfig() {
+ SafetyCenterConfig safetyCenterConfig = readSafetyCenterConfig();
+ if (safetyCenterConfig == null) {
+ return false;
+ }
+ mConfigInternalFromXml = SafetyCenterConfigInternal.from(safetyCenterConfig);
+ return true;
}
/**
- * Returns the {@link SafetyCenterConfig} read by {@link #loadSafetyCenterConfig()}.
+ * Sets an override {@link SafetyCenterConfig} for tests.
*
- * <p>Returns {@code null} if {@link #loadSafetyCenterConfig()} was never called or if there was
- * an issue when reading the {@link SafetyCenterConfig}.
+ * <p>When set, information provided by this class will be based on the overridden {@link
+ * SafetyCenterConfig}.
*/
- @Nullable
+ void setConfigOverrideForTests(SafetyCenterConfig safetyCenterConfig) {
+ mConfigInternalOverrideForTests = SafetyCenterConfigInternal.from(safetyCenterConfig);
+ }
+
+ /**
+ * Clears the {@link SafetyCenterConfig} override set by {@link
+ * #setConfigOverrideForTests(SafetyCenterConfig)}, if any.
+ */
+ void clearConfigOverrideForTests() {
+ mConfigInternalOverrideForTests = null;
+ }
+
+ /** Returns the currently active {@link SafetyCenterConfig}. */
SafetyCenterConfig getSafetyCenterConfig() {
- if (mSafetyCenterConfig == null) {
- synchronized (mSafetyCenterConfigLock) {
- return mSafetyCenterConfig;
- }
- }
- return mSafetyCenterConfig;
+ return getCurrentConfigInternal().getSafetyCenterConfig();
+ }
+
+ /** Returns the groups of {@link SafetySource}, in the order expected by the UI. */
+ public List<SafetySourcesGroup> getSafetySourcesGroups() {
+ return getCurrentConfigInternal().getSafetyCenterConfig().getSafetySourcesGroups();
}
/**
- * Returns a {@link String} resource from the given {@code stringId}, using the {@link
- * SafetyCenterResourcesContext}.
+ * Returns the groups of {@link SafetySource}, filtering out any sources where {@link
+ * SafetySources#isLoggable(SafetySource)} is false (and any resultingly empty groups).
+ */
+ public List<SafetySourcesGroup> getLoggableSafetySourcesGroups() {
+ return getCurrentConfigInternal().getLoggableSourcesGroups();
+ }
+
+ /**
+ * Returns the {@link ExternalSafetySource} associated with the {@code safetySourceId}, if any.
*
- * <p>Returns {@code null} if the resources cannot be accessed or if {@code stringId} is equal
- * to {@link Resources#ID_NULL}. Otherwise, throws a {@link Resources.NotFoundException} if the
- * {@code stringId} is invalid.
+ * <p>The returned {@link SafetySource} can either be associated with the XML or overridden
+ * {@link SafetyCenterConfig}; {@link #isExternalSafetySourceActive(String, String)} can be used
+ * to check if it is associated with the current {@link SafetyCenterConfig}. This is to continue
+ * allowing sources from the XML config to interact with SafetCenter during tests (but their
+ * calls will be no-oped).
+ *
+ * <p>The {@code callingPackageName} can help break the tie when the source is available in both
+ * the overridden config and the "real" config. Otherwise, the test config is preferred. This is
+ * to support overriding "real" sources in tests while ensuring package checks continue to pass
+ * for "real" sources that interact with our APIs.
*/
@Nullable
- String readStringResource(@StringRes int stringId) {
- if (stringId == Resources.ID_NULL) {
- return null;
+ public ExternalSafetySource getExternalSafetySource(
+ String safetySourceId, String callingPackageName) {
+ SafetyCenterConfigInternal currentConfig = getCurrentConfigInternal();
+ SafetyCenterConfigInternal xmlConfig = requireNonNull(mConfigInternalFromXml);
+ if (currentConfig == xmlConfig) {
+ // No override, access source directly.
+ return currentConfig.getExternalSafetySources().get(safetySourceId);
}
- Resources resources = mSafetyCenterResourcesContext.getResources();
- if (resources == null) {
- return null;
+ ExternalSafetySource externalSafetySourceInTestConfig =
+ currentConfig.getExternalSafetySources().get(safetySourceId);
+ ExternalSafetySource externalSafetySourceInRealConfig =
+ xmlConfig.getExternalSafetySources().get(safetySourceId);
+
+ if (externalSafetySourceInTestConfig != null
+ && Objects.equals(
+ externalSafetySourceInTestConfig.getSafetySource().getPackageName(),
+ callingPackageName)) {
+ return externalSafetySourceInTestConfig;
+ }
+
+ if (externalSafetySourceInRealConfig != null
+ && Objects.equals(
+ externalSafetySourceInRealConfig.getSafetySource().getPackageName(),
+ callingPackageName)) {
+ return externalSafetySourceInRealConfig;
+ }
+
+ if (externalSafetySourceInTestConfig != null) {
+ return externalSafetySourceInTestConfig;
}
- return resources.getString(stringId);
+ return externalSafetySourceInRealConfig;
}
/**
- * Loads the {@link SafetyCenterConfig} for it to be available when calling {@link
- * #getSafetyCenterConfig()}.
+ * Returns whether the {@code safetySourceId} is associated with an {@link ExternalSafetySource}
+ * that is currently active.
+ *
+ * <p>The source may either be "active" or "inactive". An active source is a source that is
+ * currently expected to interact with our API and may affect Safety Center status. An inactive
+ * 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.
*/
- void loadSafetyCenterConfig() {
- synchronized (mSafetyCenterConfigLock) {
- mSafetyCenterConfig = readSafetyCenterConfig();
+ public boolean isExternalSafetySourceActive(String safetySourceId, String callingPackageName) {
+ ExternalSafetySource externalSafetySourceInCurrentConfig =
+ getCurrentConfigInternal().getExternalSafetySources().get(safetySourceId);
+ if (externalSafetySourceInCurrentConfig == null) {
+ return false;
}
+ return Objects.equals(
+ externalSafetySourceInCurrentConfig.getSafetySource().getPackageName(),
+ callingPackageName);
+ }
+
+ /**
+ * Returns whether the {@code safetySourceId} is associated with an {@link ExternalSafetySource}
+ * that is in the real config XML file (i.e. not being overridden).
+ */
+ public boolean isExternalSafetySourceFromRealConfig(String safetySourceId) {
+ return requireNonNull(mConfigInternalFromXml)
+ .getExternalSafetySources()
+ .containsKey(safetySourceId);
+ }
+
+ /**
+ * Returns the {@link Broadcast} defined in the {@link SafetyCenterConfig}, with all the sources
+ * that they should handle and the profile on which they should be dispatched.
+ */
+ List<Broadcast> getBroadcasts() {
+ return getCurrentConfigInternal().getBroadcasts();
+ }
+
+ private SafetyCenterConfigInternal getCurrentConfigInternal() {
+ // We require the XML config must be loaded successfully for SafetyCenterManager APIs to
+ // function, regardless of whether the config is subsequently overridden.
+ requireNonNull(mConfigInternalFromXml);
+
+ if (mConfigInternalOverrideForTests == null) {
+ return mConfigInternalFromXml;
+ }
+
+ return mConfigInternalOverrideForTests;
}
@Nullable
private SafetyCenterConfig readSafetyCenterConfig() {
InputStream in = mSafetyCenterResourcesContext.getSafetyCenterConfig();
if (in == null) {
- Log.e(TAG, "Cannot get safety center config file");
+ 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");
+ Log.e(TAG, "Cannot get safety center resources, safety center will be disabled.");
return null;
}
@@ -124,8 +244,339 @@ final class SafetyCenterConfigReader {
Log.i(TAG, "SafetyCenterConfig read successfully");
return safetyCenterConfig;
} catch (ParseException e) {
- Log.e(TAG, "Cannot read SafetyCenterConfig", e);
+ Log.e(TAG, "Cannot read SafetyCenterConfig, safety center will be disabled.", e);
return null;
}
}
+
+ /** Dumps state for debugging purposes. */
+ void dump(PrintWriter fout) {
+ fout.println("XML CONFIG");
+ fout.println("\t" + mConfigInternalFromXml);
+ fout.println();
+ fout.println("OVERRIDE CONFIG");
+ fout.println("\t" + mConfigInternalOverrideForTests);
+ fout.println();
+ }
+
+ /** A wrapper class around the parsed XML config. */
+ private static final class SafetyCenterConfigInternal {
+
+ private final SafetyCenterConfig mConfig;
+ private final ArrayMap<String, ExternalSafetySource> mExternalSafetySources;
+ private final List<SafetySourcesGroup> mLoggableSourcesGroups;
+ private final List<Broadcast> mBroadcasts;
+
+ private SafetyCenterConfigInternal(
+ SafetyCenterConfig safetyCenterConfig,
+ ArrayMap<String, ExternalSafetySource> externalSafetySources,
+ List<SafetySourcesGroup> loggableSourcesGroups,
+ List<Broadcast> broadcasts) {
+ mConfig = safetyCenterConfig;
+ mExternalSafetySources = externalSafetySources;
+ mLoggableSourcesGroups = loggableSourcesGroups;
+ mBroadcasts = broadcasts;
+ }
+
+ private SafetyCenterConfig getSafetyCenterConfig() {
+ return mConfig;
+ }
+
+ private ArrayMap<String, ExternalSafetySource> getExternalSafetySources() {
+ return mExternalSafetySources;
+ }
+
+ private List<SafetySourcesGroup> getLoggableSourcesGroups() {
+ return mLoggableSourcesGroups;
+ }
+
+ private List<Broadcast> getBroadcasts() {
+ return mBroadcasts;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SafetyCenterConfigInternal)) return false;
+ SafetyCenterConfigInternal configInternal = (SafetyCenterConfigInternal) o;
+ return mConfig.equals(configInternal.mConfig);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mConfig);
+ }
+
+ @Override
+ public String toString() {
+ return "SafetyCenterConfigInternal{"
+ + "mConfig="
+ + mConfig
+ + ", mExternalSafetySources="
+ + mExternalSafetySources
+ + ", mLoggableSourcesGroups="
+ + mLoggableSourcesGroups
+ + ", mBroadcasts="
+ + mBroadcasts
+ + '}';
+ }
+
+ private static SafetyCenterConfigInternal from(SafetyCenterConfig safetyCenterConfig) {
+ return new SafetyCenterConfigInternal(
+ safetyCenterConfig,
+ extractExternalSafetySources(safetyCenterConfig),
+ extractLoggableSafetySourcesGroups(safetyCenterConfig),
+ unmodifiableList(extractBroadcasts(safetyCenterConfig)));
+ }
+
+ private static ArrayMap<String, ExternalSafetySource> extractExternalSafetySources(
+ SafetyCenterConfig safetyCenterConfig) {
+ ArrayMap<String, ExternalSafetySource> externalSafetySources = new ArrayMap<>();
+ List<SafetySourcesGroup> safetySourcesGroups =
+ safetyCenterConfig.getSafetySourcesGroups();
+ for (int i = 0; i < safetySourcesGroups.size(); i++) {
+ SafetySourcesGroup safetySourcesGroup = safetySourcesGroups.get(i);
+
+ List<SafetySource> safetySources = safetySourcesGroup.getSafetySources();
+ for (int j = 0; j < safetySources.size(); j++) {
+ SafetySource safetySource = safetySources.get(j);
+
+ if (!SafetySources.isExternal(safetySource)) {
+ continue;
+ }
+
+ boolean hasEntryInStatelessGroup =
+ safetySource.getType() == SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC
+ && safetySourcesGroup.getType()
+ == SafetySourcesGroup
+ .SAFETY_SOURCES_GROUP_TYPE_STATELESS;
+
+ externalSafetySources.put(
+ safetySource.getId(),
+ new ExternalSafetySource(safetySource, hasEntryInStatelessGroup));
+ }
+ }
+
+ return externalSafetySources;
+ }
+
+ private static List<SafetySourcesGroup> extractLoggableSafetySourcesGroups(
+ SafetyCenterConfig safetyCenterConfig) {
+ List<SafetySourcesGroup> originalGroups = safetyCenterConfig.getSafetySourcesGroups();
+ List<SafetySourcesGroup> filteredGroups = new ArrayList<>(originalGroups.size());
+
+ for (int i = 0; i < originalGroups.size(); i++) {
+ SafetySourcesGroup originalGroup = originalGroups.get(i);
+
+ SafetySourcesGroup.Builder filteredGroupBuilder =
+ SafetySourcesGroups.copyToBuilderWithoutSources(originalGroup);
+ List<SafetySource> originalSources = originalGroup.getSafetySources();
+ for (int j = 0; j < originalSources.size(); j++) {
+ SafetySource source = originalSources.get(j);
+
+ if (SafetySources.isLoggable(source)) {
+ filteredGroupBuilder.addSafetySource(source);
+ }
+ }
+
+ SafetySourcesGroup filteredGroup = filteredGroupBuilder.build();
+ if (!filteredGroup.getSafetySources().isEmpty()) {
+ filteredGroups.add(filteredGroup);
+ }
+ }
+
+ return filteredGroups;
+ }
+
+ private static List<Broadcast> extractBroadcasts(SafetyCenterConfig safetyCenterConfig) {
+ ArrayMap<String, Broadcast> packageNameToBroadcast = new ArrayMap<>();
+ List<Broadcast> broadcasts = new ArrayList<>();
+ List<SafetySourcesGroup> safetySourcesGroups =
+ safetyCenterConfig.getSafetySourcesGroups();
+ for (int i = 0; i < safetySourcesGroups.size(); i++) {
+ SafetySourcesGroup safetySourcesGroup = safetySourcesGroups.get(i);
+
+ List<SafetySource> safetySources = safetySourcesGroup.getSafetySources();
+ for (int j = 0; j < safetySources.size(); j++) {
+ SafetySource safetySource = safetySources.get(j);
+
+ if (!SafetySources.isExternal(safetySource)) {
+ continue;
+ }
+
+ Broadcast broadcast = packageNameToBroadcast.get(safetySource.getPackageName());
+ if (broadcast == null) {
+ broadcast = new Broadcast(safetySource.getPackageName());
+ packageNameToBroadcast.put(safetySource.getPackageName(), broadcast);
+ broadcasts.add(broadcast);
+ }
+ broadcast.mSourceIdsForProfileParent.add(safetySource.getId());
+ if (safetySource.isRefreshOnPageOpenAllowed()) {
+ broadcast.mSourceIdsForProfileParentOnPageOpen.add(safetySource.getId());
+ }
+ boolean needsManagedProfilesBroadcast =
+ SafetySources.supportsManagedProfiles(safetySource);
+ if (needsManagedProfilesBroadcast) {
+ broadcast.mSourceIdsForManagedProfiles.add(safetySource.getId());
+ if (safetySource.isRefreshOnPageOpenAllowed()) {
+ broadcast.mSourceIdsForManagedProfilesOnPageOpen.add(
+ safetySource.getId());
+ }
+ }
+ }
+ }
+
+ return broadcasts;
+ }
+ }
+
+ /**
+ * A wrapper class around a {@link SafetySource} that is providing data externally.
+ *
+ * @hide
+ */
+ public static final class ExternalSafetySource {
+ private final SafetySource mSafetySource;
+ private final boolean mHasEntryInStatelessGroup;
+
+ private ExternalSafetySource(SafetySource safetySource, boolean hasEntryInStatelessGroup) {
+ mSafetySource = safetySource;
+ mHasEntryInStatelessGroup = hasEntryInStatelessGroup;
+ }
+
+ /** Returns the external {@link SafetySource}. */
+ public SafetySource getSafetySource() {
+ return mSafetySource;
+ }
+
+ /**
+ * Returns whether the external {@link SafetySource} has an entry in a stateless {@link
+ * SafetySourcesGroup}.
+ */
+ public boolean hasEntryInStatelessGroup() {
+ return mHasEntryInStatelessGroup;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof ExternalSafetySource)) return false;
+ ExternalSafetySource that = (ExternalSafetySource) o;
+ return mHasEntryInStatelessGroup == that.mHasEntryInStatelessGroup
+ && mSafetySource.equals(that.mSafetySource);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSafetySource, mHasEntryInStatelessGroup);
+ }
+
+ @Override
+ public String toString() {
+ return "ExternalSafetySource{"
+ + "mSafetySource="
+ + mSafetySource
+ + ", mHasEntryInStatelessGroup="
+ + mHasEntryInStatelessGroup
+ + '}';
+ }
+ }
+
+ /** A class that represents a broadcast to be sent to safety sources. */
+ static final class Broadcast {
+
+ private final String mPackageName;
+
+ private final List<String> mSourceIdsForProfileParent = new ArrayList<>();
+ private final List<String> mSourceIdsForProfileParentOnPageOpen = new ArrayList<>();
+ private final List<String> mSourceIdsForManagedProfiles = new ArrayList<>();
+ private final List<String> mSourceIdsForManagedProfilesOnPageOpen = new ArrayList<>();
+
+ private Broadcast(String packageName) {
+ mPackageName = packageName;
+ }
+
+ /** Returns the package name to dispatch the broadcast to. */
+ String getPackageName() {
+ return mPackageName;
+ }
+
+ /**
+ * Returns the safety source ids associated with this broadcast in the profile owner.
+ *
+ * <p>If this list is empty, there are no sources to dispatch to in the profile owner.
+ */
+ List<String> getSourceIdsForProfileParent() {
+ return unmodifiableList(mSourceIdsForProfileParent);
+ }
+
+ /**
+ * Returns the safety source ids associated with this broadcast in the profile owner that
+ * have refreshOnPageOpenAllowed set to true in the XML config.
+ *
+ * <p>If this list is empty, there are no sources to dispatch to in the profile owner.
+ */
+ List<String> getSourceIdsForProfileParentOnPageOpen() {
+ return unmodifiableList(mSourceIdsForProfileParentOnPageOpen);
+ }
+
+ /**
+ * Returns the safety source ids associated with this broadcast in the managed profile(s).
+ *
+ * <p>If this list is empty, there are no sources to dispatch to in the managed profile(s).
+ */
+ List<String> getSourceIdsForManagedProfiles() {
+ return unmodifiableList(mSourceIdsForManagedProfiles);
+ }
+
+ /**
+ * Returns the safety source ids associated with this broadcast in the managed profile(s)
+ * that have refreshOnPageOpenAllowed set to true in the XML config.
+ *
+ * <p>If this list is empty, there are no sources to dispatch to in the managed profile(s).
+ */
+ List<String> getSourceIdsForManagedProfilesOnPageOpen() {
+ return unmodifiableList(mSourceIdsForManagedProfilesOnPageOpen);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Broadcast)) return false;
+ Broadcast that = (Broadcast) o;
+ return mPackageName.equals(that.mPackageName)
+ && mSourceIdsForProfileParent.equals(that.mSourceIdsForProfileParent)
+ && mSourceIdsForProfileParentOnPageOpen.equals(
+ that.mSourceIdsForProfileParentOnPageOpen)
+ && mSourceIdsForManagedProfiles.equals(that.mSourceIdsForManagedProfiles)
+ && mSourceIdsForManagedProfilesOnPageOpen.equals(
+ that.mSourceIdsForManagedProfilesOnPageOpen);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mPackageName,
+ mSourceIdsForProfileParent,
+ mSourceIdsForProfileParentOnPageOpen,
+ mSourceIdsForManagedProfiles,
+ mSourceIdsForManagedProfilesOnPageOpen);
+ }
+
+ @Override
+ public String toString() {
+ return "Broadcast{"
+ + "mPackageName='"
+ + mPackageName
+ + "', mSourceIdsForProfileParent="
+ + mSourceIdsForProfileParent
+ + ", mSourceIdsForProfileParentOnPageOpen="
+ + mSourceIdsForProfileParentOnPageOpen
+ + ", mSourceIdsForManagedProfiles="
+ + mSourceIdsForManagedProfiles
+ + ", mSourceIdsForManagedProfilesOnPageOpen="
+ + mSourceIdsForManagedProfilesOnPageOpen
+ + '}';
+ }
+ }
}
diff --git a/service/java/com/android/safetycenter/SafetyCenterDataChangeNotifier.java b/service/java/com/android/safetycenter/SafetyCenterDataChangeNotifier.java
new file mode 100644
index 000000000..e8bf2626a
--- /dev/null
+++ b/service/java/com/android/safetycenter/SafetyCenterDataChangeNotifier.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.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;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
+/**
+ * Knows how to update classes that need to know about any change in SafetyCenter data, which in
+ * this context entails any state change that happened in the data subpackage.
+ *
+ * @hide
+ */
+@RequiresApi(TIRAMISU)
+@NotThreadSafe
+public final class SafetyCenterDataChangeNotifier {
+
+ private final SafetyCenterNotificationSender mSafetyCenterNotificationSender;
+ private final SafetyCenterListeners mSafetyCenterListeners;
+
+ /** Initializes a new instance of {@link SafetyCenterDataChangeNotifier}. */
+ SafetyCenterDataChangeNotifier(
+ SafetyCenterNotificationSender safetyCenterNotificationSender,
+ SafetyCenterListeners safetyCenterListeners) {
+ mSafetyCenterNotificationSender = safetyCenterNotificationSender;
+ mSafetyCenterListeners = safetyCenterListeners;
+ }
+
+ /** Updates classes that depend on data changes (changes of state in the data subpackage). */
+ public void updateDataConsumers(UserProfileGroup userProfileGroup, @UserIdInt int userId) {
+ mSafetyCenterNotificationSender.updateNotifications(userId);
+ mSafetyCenterListeners.deliverDataForUserProfileGroup(userProfileGroup);
+ }
+
+ /** Updates classes that depend on data changes (changes of state in the data subpackage). */
+ void updateDataConsumers(UserProfileGroup userProfileGroup) {
+ mSafetyCenterNotificationSender.updateNotifications(userProfileGroup);
+ mSafetyCenterListeners.deliverDataForUserProfileGroup(userProfileGroup);
+ }
+
+ /** Updates classes that depend on data changes (changes of state in the data subpackage). */
+ void updateDataConsumers(List<UserProfileGroup> userProfileGroups) {
+ for (int i = 0; i < userProfileGroups.size(); i++) {
+ updateDataConsumers(userProfileGroups.get(i));
+ }
+ }
+}
diff --git a/service/java/com/android/safetycenter/SafetyCenterDataFactory.java b/service/java/com/android/safetycenter/SafetyCenterDataFactory.java
new file mode 100644
index 000000000..fe4a1ee43
--- /dev/null
+++ b/service/java/com/android/safetycenter/SafetyCenterDataFactory.java
@@ -0,0 +1,1347 @@
+/*
+ * 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;
+
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+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.UserIdInt;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.icu.text.ListFormatter;
+import android.icu.text.MessageFormat;
+import android.icu.util.ULocale;
+import android.os.Bundle;
+import android.safetycenter.SafetyCenterData;
+import android.safetycenter.SafetyCenterEntry;
+import android.safetycenter.SafetyCenterEntryGroup;
+import android.safetycenter.SafetyCenterEntryOrGroup;
+import android.safetycenter.SafetyCenterIssue;
+import android.safetycenter.SafetyCenterIssue.Action.ConfirmationDialogDetails;
+import android.safetycenter.SafetyCenterStaticEntry;
+import android.safetycenter.SafetyCenterStaticEntryGroup;
+import android.safetycenter.SafetyCenterStatus;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceIssue;
+import android.safetycenter.SafetySourceStatus;
+import android.safetycenter.config.SafetyCenterConfig;
+import android.safetycenter.config.SafetySource;
+import android.safetycenter.config.SafetySourcesGroup;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.modules.utils.build.SdkLevel;
+import com.android.permission.util.UserUtils;
+import com.android.safetycenter.data.SafetyCenterDataManager;
+import com.android.safetycenter.internaldata.SafetyCenterBundles;
+import com.android.safetycenter.internaldata.SafetyCenterEntryId;
+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 java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
+/**
+ * Aggregates {@link SafetySourceData} to build {@link SafetyCenterData} instances which are shared
+ * with Safety Center listeners, including PermissionController.
+ *
+ * <p>This class isn't thread safe. Thread safety must be handled by the caller.
+ *
+ * @hide
+ */
+@RequiresApi(TIRAMISU)
+@NotThreadSafe
+public final class SafetyCenterDataFactory {
+
+ private static final String TAG = "SafetyCenterDataFactory";
+
+ private static final String ANDROID_LOCK_SCREEN_SOURCES_GROUP_ID = "AndroidLockScreenSources";
+
+ private final Context mContext;
+ private final SafetyCenterResourcesContext mSafetyCenterResourcesContext;
+ private final SafetyCenterConfigReader mSafetyCenterConfigReader;
+ private final SafetyCenterRefreshTracker mSafetyCenterRefreshTracker;
+ private final PendingIntentFactory mPendingIntentFactory;
+
+ private final SafetyCenterDataManager mSafetyCenterDataManager;
+
+ SafetyCenterDataFactory(
+ Context context,
+ SafetyCenterResourcesContext safetyCenterResourcesContext,
+ SafetyCenterConfigReader safetyCenterConfigReader,
+ SafetyCenterRefreshTracker safetyCenterRefreshTracker,
+ PendingIntentFactory pendingIntentFactory,
+ SafetyCenterDataManager safetyCenterDataManager) {
+ mContext = context;
+ mSafetyCenterResourcesContext = safetyCenterResourcesContext;
+ mSafetyCenterConfigReader = safetyCenterConfigReader;
+ mSafetyCenterRefreshTracker = safetyCenterRefreshTracker;
+ mPendingIntentFactory = pendingIntentFactory;
+ mSafetyCenterDataManager = safetyCenterDataManager;
+ }
+
+ /**
+ * Returns a default {@link SafetyCenterData} object to be returned when the API is disabled.
+ */
+ static SafetyCenterData getDefaultSafetyCenterData() {
+ SafetyCenterStatus defaultSafetyCenterStatus =
+ new SafetyCenterStatus.Builder("", "")
+ .setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ .build();
+ if (SdkLevel.isAtLeastU()) {
+ return new SafetyCenterData.Builder(defaultSafetyCenterStatus).build();
+ } else {
+ return new SafetyCenterData(
+ defaultSafetyCenterStatus, emptyList(), emptyList(), emptyList());
+ }
+ }
+
+ /**
+ * Returns the current {@link SafetyCenterData} for the given {@code packageName} and {@link
+ * UserProfileGroup}, aggregated from all the {@link SafetySourceData} set so far.
+ *
+ * <p>If a {@link SafetySourceData} was not set, the default value from the {@link
+ * SafetyCenterConfig} is used.
+ */
+ SafetyCenterData assembleSafetyCenterData(
+ String packageName, UserProfileGroup userProfileGroup) {
+ return assembleSafetyCenterData(packageName, userProfileGroup, getAllGroups());
+ }
+
+ /**
+ * Returns the current {@link SafetyCenterData} for the given {@code packageName} and {@link
+ * UserProfileGroup}, aggregated from {@link SafetySourceData} set by the specified {@link
+ * SafetySourcesGroup}s.
+ *
+ * <p>If a {@link SafetySourceData} was not set, the default value from the {@link
+ * SafetyCenterConfig} is used.
+ */
+ public SafetyCenterData assembleSafetyCenterData(
+ String packageName,
+ UserProfileGroup userProfileGroup,
+ List<SafetySourcesGroup> safetySourcesGroups) {
+ List<SafetyCenterEntryOrGroup> safetyCenterEntryOrGroups = new ArrayList<>();
+ List<SafetyCenterStaticEntryGroup> safetyCenterStaticEntryGroups = new ArrayList<>();
+ SafetyCenterOverallState safetyCenterOverallState = new SafetyCenterOverallState();
+ Bundle staticEntriesToIds = new Bundle();
+
+ for (int i = 0; i < safetySourcesGroups.size(); i++) {
+ SafetySourcesGroup safetySourcesGroup = safetySourcesGroups.get(i);
+
+ int safetySourcesGroupType = safetySourcesGroup.getType();
+ switch (safetySourcesGroupType) {
+ case SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATEFUL:
+ addSafetyCenterEntryGroup(
+ safetyCenterOverallState,
+ safetyCenterEntryOrGroups,
+ safetySourcesGroup,
+ packageName,
+ userProfileGroup);
+ break;
+ case SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATELESS:
+ addSafetyCenterStaticEntryGroup(
+ staticEntriesToIds,
+ safetyCenterOverallState,
+ safetyCenterStaticEntryGroups,
+ safetySourcesGroup,
+ packageName,
+ userProfileGroup);
+ break;
+ case SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_HIDDEN:
+ break;
+ default:
+ Log.w(TAG, "Unexpected SafetySourceGroupType: " + safetySourcesGroupType);
+ break;
+ }
+ }
+
+ List<SafetySourceIssueInfo> issuesInfo =
+ mSafetyCenterDataManager.getIssuesDedupedSortedDescFor(userProfileGroup);
+
+ List<SafetyCenterIssue> safetyCenterIssues = new ArrayList<>();
+ List<SafetyCenterIssue> safetyCenterDismissedIssues = new ArrayList<>();
+ SafetySourceIssueInfo topNonDismissedIssueInfo = null;
+ int numTipIssues = 0;
+ int numAutomaticIssues = 0;
+ Bundle issuesToGroups = new Bundle();
+
+ for (int i = 0; i < issuesInfo.size(); i++) {
+ SafetySourceIssueInfo issueInfo = issuesInfo.get(i);
+ SafetyCenterIssue safetyCenterIssue =
+ toSafetyCenterIssue(
+ issueInfo.getSafetySourceIssue(),
+ issueInfo.getSafetySourcesGroup(),
+ issueInfo.getSafetyCenterIssueKey());
+
+ if (mSafetyCenterDataManager.isIssueDismissed(
+ issueInfo.getSafetyCenterIssueKey(),
+ issueInfo.getSafetySourceIssue().getSeverityLevel())) {
+ safetyCenterDismissedIssues.add(safetyCenterIssue);
+ } else {
+ safetyCenterIssues.add(safetyCenterIssue);
+ safetyCenterOverallState.addIssueOverallSeverityLevel(
+ toSafetyCenterStatusOverallSeverityLevel(
+ issueInfo.getSafetySourceIssue().getSeverityLevel()));
+ if (topNonDismissedIssueInfo == null) {
+ topNonDismissedIssueInfo = issueInfo;
+ }
+ if (isTip(issueInfo.getSafetySourceIssue())) {
+ numTipIssues++;
+ } else if (isAutomatic(issueInfo.getSafetySourceIssue())) {
+ numAutomaticIssues++;
+ }
+ }
+
+ if (SdkLevel.isAtLeastU()) {
+ updateIssuesToGroups(
+ issuesToGroups,
+ issueInfo.getSafetyCenterIssueKey(),
+ safetyCenterIssue.getId());
+ }
+ }
+
+ int refreshStatus = mSafetyCenterRefreshTracker.getRefreshStatus();
+ SafetyCenterStatus safetyCenterStatus =
+ new SafetyCenterStatus.Builder(
+ getSafetyCenterStatusTitle(
+ safetyCenterOverallState.getOverallSeverityLevel(),
+ topNonDismissedIssueInfo,
+ refreshStatus,
+ safetyCenterOverallState.hasSettingsToReview()),
+ getSafetyCenterStatusSummary(
+ safetyCenterOverallState,
+ topNonDismissedIssueInfo,
+ refreshStatus,
+ numTipIssues,
+ numAutomaticIssues,
+ safetyCenterIssues.size()))
+ .setSeverityLevel(safetyCenterOverallState.getOverallSeverityLevel())
+ .setRefreshStatus(refreshStatus)
+ .build();
+
+ if (SdkLevel.isAtLeastU()) {
+ SafetyCenterData.Builder builder = new SafetyCenterData.Builder(safetyCenterStatus);
+ for (int i = 0; i < safetyCenterIssues.size(); i++) {
+ builder.addIssue(safetyCenterIssues.get(i));
+ }
+ for (int i = 0; i < safetyCenterEntryOrGroups.size(); i++) {
+ builder.addEntryOrGroup(safetyCenterEntryOrGroups.get(i));
+ }
+ for (int i = 0; i < safetyCenterStaticEntryGroups.size(); i++) {
+ builder.addStaticEntryGroup(safetyCenterStaticEntryGroups.get(i));
+ }
+ for (int i = 0; i < safetyCenterDismissedIssues.size(); i++) {
+ builder.addDismissedIssue(safetyCenterDismissedIssues.get(i));
+ }
+
+ Bundle extras = new Bundle();
+ if (!issuesToGroups.isEmpty()) {
+ extras.putBundle(ISSUES_TO_GROUPS_BUNDLE_KEY, issuesToGroups);
+ }
+ if (!staticEntriesToIds.isEmpty()) {
+ extras.putBundle(STATIC_ENTRIES_TO_IDS_BUNDLE_KEY, staticEntriesToIds);
+ }
+ if (!issuesToGroups.isEmpty() || !staticEntriesToIds.isEmpty()) {
+ builder.setExtras(extras);
+ }
+
+ return builder.build();
+ } else {
+ return new SafetyCenterData(
+ safetyCenterStatus,
+ safetyCenterIssues,
+ safetyCenterEntryOrGroups,
+ safetyCenterStaticEntryGroups);
+ }
+ }
+
+ private List<SafetySourcesGroup> getAllGroups() {
+ return mSafetyCenterConfigReader.getSafetySourcesGroups();
+ }
+
+ private void updateIssuesToGroups(
+ Bundle issuesToGroups, SafetyCenterIssueKey issueKey, String safetyCenterIssueId) {
+ Set<String> groups = mSafetyCenterDataManager.getGroupMappingFor(issueKey);
+ if (!groups.isEmpty()) {
+ issuesToGroups.putStringArrayList(safetyCenterIssueId, new ArrayList<>(groups));
+ }
+ }
+
+ private SafetyCenterIssue toSafetyCenterIssue(
+ SafetySourceIssue safetySourceIssue,
+ SafetySourcesGroup safetySourcesGroup,
+ SafetyCenterIssueKey safetyCenterIssueKey) {
+ SafetyCenterIssueId safetyCenterIssueId =
+ SafetyCenterIssueId.newBuilder()
+ .setSafetyCenterIssueKey(safetyCenterIssueKey)
+ .setIssueTypeId(safetySourceIssue.getIssueTypeId())
+ .build();
+
+ List<SafetySourceIssue.Action> safetySourceIssueActions = safetySourceIssue.getActions();
+ List<SafetyCenterIssue.Action> safetyCenterIssueActions =
+ new ArrayList<>(safetySourceIssueActions.size());
+ for (int i = 0; i < safetySourceIssueActions.size(); i++) {
+ SafetySourceIssue.Action safetySourceIssueAction = safetySourceIssueActions.get(i);
+
+ safetyCenterIssueActions.add(
+ toSafetyCenterIssueAction(
+ safetySourceIssueAction,
+ safetyCenterIssueId.getSafetyCenterIssueKey()));
+ }
+
+ int safetyCenterIssueSeverityLevel =
+ toSafetyCenterIssueSeverityLevel(safetySourceIssue.getSeverityLevel());
+ SafetyCenterIssue.Builder safetyCenterIssueBuilder =
+ new SafetyCenterIssue.Builder(
+ SafetyCenterIds.encodeToString(safetyCenterIssueId),
+ safetySourceIssue.getTitle(),
+ safetySourceIssue.getSummary())
+ .setSeverityLevel(safetyCenterIssueSeverityLevel)
+ .setShouldConfirmDismissal(
+ safetyCenterIssueSeverityLevel
+ > SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK)
+ .setSubtitle(safetySourceIssue.getSubtitle())
+ .setActions(safetyCenterIssueActions);
+ if (SdkLevel.isAtLeastU()) {
+ CharSequence issueAttributionTitle =
+ TextUtils.isEmpty(safetySourceIssue.getAttributionTitle())
+ ? mSafetyCenterResourcesContext.getOptionalString(
+ safetySourcesGroup.getTitleResId())
+ : safetySourceIssue.getAttributionTitle();
+ safetyCenterIssueBuilder.setAttributionTitle(issueAttributionTitle);
+ safetyCenterIssueBuilder.setGroupId(safetySourcesGroup.getId());
+ }
+ return safetyCenterIssueBuilder.build();
+ }
+
+ private SafetyCenterIssue.Action toSafetyCenterIssueAction(
+ SafetySourceIssue.Action safetySourceIssueAction,
+ SafetyCenterIssueKey safetyCenterIssueKey) {
+ SafetyCenterIssueActionId safetyCenterIssueActionId =
+ SafetyCenterIssueActionId.newBuilder()
+ .setSafetyCenterIssueKey(safetyCenterIssueKey)
+ .setSafetySourceIssueActionId(safetySourceIssueAction.getId())
+ .build();
+
+ SafetyCenterIssue.Action.Builder builder =
+ new SafetyCenterIssue.Action.Builder(
+ SafetyCenterIds.encodeToString(safetyCenterIssueActionId),
+ safetySourceIssueAction.getLabel(),
+ safetySourceIssueAction.getPendingIntent())
+ .setSuccessMessage(safetySourceIssueAction.getSuccessMessage())
+ .setIsInFlight(
+ mSafetyCenterDataManager.actionIsInFlight(
+ safetyCenterIssueActionId))
+ .setWillResolve(safetySourceIssueAction.willResolve());
+ if (SdkLevel.isAtLeastU()) {
+ if (safetySourceIssueAction.getConfirmationDialogDetails() != null) {
+ SafetySourceIssue.Action.ConfirmationDialogDetails detailsFrom =
+ safetySourceIssueAction.getConfirmationDialogDetails();
+ ConfirmationDialogDetails detailsTo =
+ new ConfirmationDialogDetails(
+ detailsFrom.getTitle(),
+ detailsFrom.getText(),
+ detailsFrom.getAcceptButtonText(),
+ detailsFrom.getDenyButtonText());
+ builder.setConfirmationDialogDetails(detailsTo);
+ }
+ }
+ return builder.build();
+ }
+
+ private void addSafetyCenterEntryGroup(
+ SafetyCenterOverallState safetyCenterOverallState,
+ List<SafetyCenterEntryOrGroup> safetyCenterEntryOrGroups,
+ SafetySourcesGroup safetySourcesGroup,
+ String defaultPackageName,
+ UserProfileGroup userProfileGroup) {
+ int groupSafetyCenterEntryLevel = SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED;
+
+ List<SafetySource> safetySources = safetySourcesGroup.getSafetySources();
+ List<SafetyCenterEntry> entries = new ArrayList<>(safetySources.size());
+ for (int i = 0; i < safetySources.size(); i++) {
+ SafetySource safetySource = safetySources.get(i);
+
+ groupSafetyCenterEntryLevel =
+ mergeSafetyCenterEntrySeverityLevels(
+ groupSafetyCenterEntryLevel,
+ addSafetyCenterEntry(
+ safetyCenterOverallState,
+ entries,
+ safetySource,
+ defaultPackageName,
+ userProfileGroup.getProfileParentUserId(),
+ false,
+ false));
+
+ if (!SafetySources.supportsManagedProfiles(safetySource)) {
+ continue;
+ }
+
+ int[] managedProfilesUserIds = userProfileGroup.getManagedProfilesUserIds();
+ for (int j = 0; j < managedProfilesUserIds.length; j++) {
+ int managedProfileUserId = managedProfilesUserIds[j];
+ boolean isManagedUserRunning =
+ userProfileGroup.isManagedUserRunning(managedProfileUserId);
+
+ groupSafetyCenterEntryLevel =
+ mergeSafetyCenterEntrySeverityLevels(
+ groupSafetyCenterEntryLevel,
+ addSafetyCenterEntry(
+ safetyCenterOverallState,
+ entries,
+ safetySource,
+ defaultPackageName,
+ managedProfileUserId,
+ true,
+ isManagedUserRunning));
+ }
+ }
+
+ if (entries.size() == 0) {
+ return;
+ }
+
+ if (!SafetyCenterFlags.getShowSubpages() && entries.size() == 1) {
+ safetyCenterEntryOrGroups.add(new SafetyCenterEntryOrGroup(entries.get(0)));
+ return;
+ }
+
+ CharSequence groupSummary =
+ getSafetyCenterEntryGroupSummary(
+ safetySourcesGroup, groupSafetyCenterEntryLevel, entries);
+ safetyCenterEntryOrGroups.add(
+ new SafetyCenterEntryOrGroup(
+ new SafetyCenterEntryGroup.Builder(
+ safetySourcesGroup.getId(),
+ mSafetyCenterResourcesContext.getString(
+ safetySourcesGroup.getTitleResId()))
+ .setSeverityLevel(groupSafetyCenterEntryLevel)
+ .setSummary(groupSummary)
+ .setEntries(entries)
+ .setSeverityUnspecifiedIconType(
+ toGroupSeverityUnspecifiedIconType(
+ safetySourcesGroup.getStatelessIconType()))
+ .build()));
+ }
+
+ @SafetyCenterEntry.EntrySeverityLevel
+ private static int mergeSafetyCenterEntrySeverityLevels(
+ @SafetyCenterEntry.EntrySeverityLevel int left,
+ @SafetyCenterEntry.EntrySeverityLevel int right) {
+ if (left > SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK
+ || right > SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK) {
+ return Math.max(left, right);
+ }
+ if (left == SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN
+ || right == SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN) {
+ return SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN;
+ }
+ return Math.max(left, right);
+ }
+
+ @Nullable
+ private CharSequence getSafetyCenterEntryGroupSummary(
+ SafetySourcesGroup safetySourcesGroup,
+ @SafetyCenterEntry.EntrySeverityLevel int groupSafetyCenterEntryLevel,
+ List<SafetyCenterEntry> entries) {
+ switch (groupSafetyCenterEntryLevel) {
+ case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING:
+ case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION:
+ case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK:
+ for (int i = 0; i < entries.size(); i++) {
+ SafetyCenterEntry entry = entries.get(i);
+
+ CharSequence entrySummary = entry.getSummary();
+ if (entry.getSeverityLevel() != groupSafetyCenterEntryLevel
+ || entrySummary == null) {
+ continue;
+ }
+
+ if (groupSafetyCenterEntryLevel > SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK) {
+ return entrySummary;
+ }
+
+ SafetySourceKey key = toSafetySourceKey(entry.getId());
+ SafetySourceData safetySourceData =
+ mSafetyCenterDataManager.getSafetySourceDataInternal(key);
+ boolean hasIssues =
+ safetySourceData != null && !safetySourceData.getIssues().isEmpty();
+
+ if (hasIssues) {
+ return entrySummary;
+ }
+ }
+
+ return getDefaultGroupSummary(safetySourcesGroup, entries);
+ case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED:
+ return getDefaultGroupSummary(safetySourcesGroup, entries);
+ case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN:
+ 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 mSafetyCenterResourcesContext.getStringByName("group_unknown_summary");
+ }
+
+ Log.w(
+ TAG,
+ "Unexpected SafetyCenterEntry.EntrySeverityLevel for SafetyCenterEntryGroup: "
+ + groupSafetyCenterEntryLevel);
+ return getDefaultGroupSummary(safetySourcesGroup, entries);
+ }
+
+ @Nullable
+ private CharSequence getDefaultGroupSummary(
+ SafetySourcesGroup safetySourcesGroup, List<SafetyCenterEntry> entries) {
+ CharSequence groupSummary =
+ mSafetyCenterResourcesContext.getOptionalString(
+ safetySourcesGroup.getSummaryResId());
+
+ if (safetySourcesGroup.getId().equals(ANDROID_LOCK_SCREEN_SOURCES_GROUP_ID)
+ && TextUtils.isEmpty(groupSummary)) {
+ List<CharSequence> titles = new ArrayList<>();
+ for (int i = 0; i < entries.size(); i++) {
+ SafetyCenterEntry entry = entries.get(i);
+ SafetyCenterEntryId entryId = SafetyCenterIds.entryIdFromString(entry.getId());
+
+ if (UserUtils.isManagedProfile(entryId.getUserId(), mContext)) {
+ continue;
+ }
+
+ titles.add(entry.getTitle());
+ }
+ groupSummary =
+ ListFormatter.getInstance(
+ ULocale.getDefault(ULocale.Category.FORMAT),
+ ListFormatter.Type.AND,
+ ListFormatter.Width.NARROW)
+ .format(titles);
+ }
+
+ return groupSummary;
+ }
+
+ @SafetyCenterEntry.EntrySeverityLevel
+ private int addSafetyCenterEntry(
+ SafetyCenterOverallState safetyCenterOverallState,
+ List<SafetyCenterEntry> entries,
+ SafetySource safetySource,
+ String defaultPackageName,
+ @UserIdInt int userId,
+ boolean isUserManaged,
+ boolean isManagedUserRunning) {
+ SafetyCenterEntry safetyCenterEntry =
+ toSafetyCenterEntry(
+ safetySource,
+ defaultPackageName,
+ userId,
+ isUserManaged,
+ isManagedUserRunning);
+ if (safetyCenterEntry == null) {
+ return SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED;
+ }
+
+ safetyCenterOverallState.addEntryOverallSeverityLevel(
+ entryToSafetyCenterStatusOverallSeverityLevel(
+ safetyCenterEntry.getSeverityLevel()));
+ entries.add(safetyCenterEntry);
+
+ return safetyCenterEntry.getSeverityLevel();
+ }
+
+ @Nullable
+ private SafetyCenterEntry toSafetyCenterEntry(
+ SafetySource safetySource,
+ String defaultPackageName,
+ @UserIdInt int userId,
+ boolean isUserManaged,
+ boolean isManagedUserRunning) {
+ switch (safetySource.getType()) {
+ case SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY:
+ return null;
+ case SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC:
+ SafetySourceKey key = SafetySourceKey.of(safetySource.getId(), userId);
+ SafetySourceStatus safetySourceStatus =
+ getSafetySourceStatus(
+ mSafetyCenterDataManager.getSafetySourceDataInternal(key));
+ boolean inQuietMode = isUserManaged && !isManagedUserRunning;
+ if (safetySourceStatus == null) {
+ int severityLevel =
+ inQuietMode
+ ? SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED
+ : SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN;
+ return toDefaultSafetyCenterEntry(
+ safetySource,
+ safetySource.getPackageName(),
+ severityLevel,
+ SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION,
+ userId,
+ isUserManaged,
+ isManagedUserRunning);
+ }
+ PendingIntent sourceProvidedPendingIntent =
+ inQuietMode ? null : safetySourceStatus.getPendingIntent();
+ PendingIntent entryPendingIntent =
+ sourceProvidedPendingIntent != null
+ ? sourceProvidedPendingIntent
+ : mPendingIntentFactory.getPendingIntent(
+ safetySource.getId(),
+ safetySource.getIntentAction(),
+ safetySource.getPackageName(),
+ userId,
+ inQuietMode);
+ boolean enabled =
+ safetySourceStatus.isEnabled()
+ && !inQuietMode
+ && entryPendingIntent != null;
+ SafetyCenterEntryId safetyCenterEntryId =
+ SafetyCenterEntryId.newBuilder()
+ .setSafetySourceId(safetySource.getId())
+ .setUserId(userId)
+ .build();
+ int severityUnspecifiedIconType =
+ SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION;
+ int severityLevel =
+ enabled
+ ? toSafetyCenterEntrySeverityLevel(
+ safetySourceStatus.getSeverityLevel())
+ : SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED;
+ SafetyCenterEntry.Builder builder =
+ new SafetyCenterEntry.Builder(
+ SafetyCenterIds.encodeToString(safetyCenterEntryId),
+ safetySourceStatus.getTitle())
+ .setSeverityLevel(severityLevel)
+ .setSummary(
+ inQuietMode
+ ? DevicePolicyResources.getWorkProfilePausedString(
+ mSafetyCenterResourcesContext)
+ : safetySourceStatus.getSummary())
+ .setEnabled(enabled)
+ .setSeverityUnspecifiedIconType(severityUnspecifiedIconType)
+ .setPendingIntent(entryPendingIntent);
+ SafetySourceStatus.IconAction iconAction = safetySourceStatus.getIconAction();
+ if (iconAction == null) {
+ return builder.build();
+ }
+ return builder.setIconAction(
+ new SafetyCenterEntry.IconAction(
+ toSafetyCenterEntryIconActionType(iconAction.getIconType()),
+ iconAction.getPendingIntent()))
+ .build();
+ case SafetySource.SAFETY_SOURCE_TYPE_STATIC:
+ return toDefaultSafetyCenterEntry(
+ safetySource,
+ getStaticSourcePackageNameOrDefault(safetySource, defaultPackageName),
+ SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED,
+ SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON,
+ userId,
+ isUserManaged,
+ isManagedUserRunning);
+ }
+ Log.w(
+ TAG,
+ "Unknown safety source type found in collapsible group: " + safetySource.getType());
+ return null;
+ }
+
+ @Nullable
+ private SafetyCenterEntry toDefaultSafetyCenterEntry(
+ SafetySource safetySource,
+ String packageName,
+ @SafetyCenterEntry.EntrySeverityLevel int entrySeverityLevel,
+ @SafetyCenterEntry.SeverityUnspecifiedIconType int severityUnspecifiedIconType,
+ @UserIdInt int userId,
+ boolean isUserManaged,
+ boolean isManagedUserRunning) {
+ if (SafetySources.isDefaultEntryHidden(safetySource)) {
+ return null;
+ }
+
+ SafetyCenterEntryId safetyCenterEntryId =
+ SafetyCenterEntryId.newBuilder()
+ .setSafetySourceId(safetySource.getId())
+ .setUserId(userId)
+ .build();
+ boolean isQuietModeEnabled = isUserManaged && !isManagedUserRunning;
+ PendingIntent pendingIntent =
+ mPendingIntentFactory.getPendingIntent(
+ safetySource.getId(),
+ safetySource.getIntentAction(),
+ packageName,
+ userId,
+ isQuietModeEnabled);
+ boolean enabled =
+ pendingIntent != null && !SafetySources.isDefaultEntryDisabled(safetySource);
+ CharSequence title =
+ isUserManaged
+ ? DevicePolicyResources.getSafetySourceWorkString(
+ mSafetyCenterResourcesContext,
+ safetySource.getId(),
+ safetySource.getTitleForWorkResId())
+ : mSafetyCenterResourcesContext.getString(safetySource.getTitleResId());
+ CharSequence summary =
+ mSafetyCenterDataManager.sourceHasError(
+ SafetySourceKey.of(safetySource.getId(), userId))
+ ? getRefreshErrorString(1)
+ : mSafetyCenterResourcesContext.getOptionalString(
+ safetySource.getSummaryResId());
+ if (isQuietModeEnabled) {
+ enabled = false;
+ summary =
+ DevicePolicyResources.getWorkProfilePausedString(mSafetyCenterResourcesContext);
+ }
+ return new SafetyCenterEntry.Builder(
+ SafetyCenterIds.encodeToString(safetyCenterEntryId), title)
+ .setSeverityLevel(entrySeverityLevel)
+ .setSummary(summary)
+ .setEnabled(enabled)
+ .setPendingIntent(pendingIntent)
+ .setSeverityUnspecifiedIconType(severityUnspecifiedIconType)
+ .build();
+ }
+
+ private void addSafetyCenterStaticEntryGroup(
+ Bundle staticEntriesToIds,
+ SafetyCenterOverallState safetyCenterOverallState,
+ List<SafetyCenterStaticEntryGroup> safetyCenterStaticEntryGroups,
+ SafetySourcesGroup safetySourcesGroup,
+ String defaultPackageName,
+ UserProfileGroup userProfileGroup) {
+ List<SafetySource> safetySources = safetySourcesGroup.getSafetySources();
+ List<SafetyCenterStaticEntry> staticEntries = new ArrayList<>(safetySources.size());
+ for (int i = 0; i < safetySources.size(); i++) {
+ SafetySource safetySource = safetySources.get(i);
+
+ addSafetyCenterStaticEntry(
+ staticEntriesToIds,
+ safetyCenterOverallState,
+ staticEntries,
+ safetySource,
+ defaultPackageName,
+ userProfileGroup.getProfileParentUserId(),
+ false,
+ false);
+
+ if (!SafetySources.supportsManagedProfiles(safetySource)) {
+ continue;
+ }
+
+ int[] managedProfilesUserIds = userProfileGroup.getManagedProfilesUserIds();
+ for (int j = 0; j < managedProfilesUserIds.length; j++) {
+ int managedProfileUserId = managedProfilesUserIds[j];
+ boolean isManagedUserRunning =
+ userProfileGroup.isManagedUserRunning(managedProfileUserId);
+
+ addSafetyCenterStaticEntry(
+ staticEntriesToIds,
+ safetyCenterOverallState,
+ staticEntries,
+ safetySource,
+ defaultPackageName,
+ managedProfileUserId,
+ true,
+ isManagedUserRunning);
+ }
+ }
+
+ if (staticEntries.isEmpty()) {
+ return;
+ }
+
+ safetyCenterStaticEntryGroups.add(
+ new SafetyCenterStaticEntryGroup(
+ mSafetyCenterResourcesContext.getString(safetySourcesGroup.getTitleResId()),
+ staticEntries));
+ }
+
+ private void addSafetyCenterStaticEntry(
+ Bundle staticEntriesToIds,
+ SafetyCenterOverallState safetyCenterOverallState,
+ List<SafetyCenterStaticEntry> staticEntries,
+ SafetySource safetySource,
+ String defaultPackageName,
+ @UserIdInt int userId,
+ boolean isUserManaged,
+ boolean isManagedUserRunning) {
+ SafetyCenterStaticEntry staticEntry =
+ toSafetyCenterStaticEntry(
+ safetySource,
+ defaultPackageName,
+ userId,
+ isUserManaged,
+ isManagedUserRunning);
+ if (staticEntry == null) {
+ return;
+ }
+ if (SdkLevel.isAtLeastU()) {
+ staticEntriesToIds.putString(
+ SafetyCenterBundles.toBundleKey(staticEntry),
+ SafetyCenterIds.encodeToString(
+ SafetyCenterEntryId.newBuilder()
+ .setSafetySourceId(safetySource.getId())
+ .setUserId(userId)
+ .build()));
+ }
+ boolean hasError =
+ mSafetyCenterDataManager.sourceHasError(
+ SafetySourceKey.of(safetySource.getId(), userId));
+ if (hasError) {
+ safetyCenterOverallState.addEntryOverallSeverityLevel(
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN);
+ }
+ staticEntries.add(staticEntry);
+ }
+
+ @Nullable
+ private SafetyCenterStaticEntry toSafetyCenterStaticEntry(
+ SafetySource safetySource,
+ String defaultPackageName,
+ @UserIdInt int userId,
+ boolean isUserManaged,
+ boolean isManagedUserRunning) {
+ switch (safetySource.getType()) {
+ case SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY:
+ return null;
+ case SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC:
+ SafetySourceKey key = SafetySourceKey.of(safetySource.getId(), userId);
+ SafetySourceStatus safetySourceStatus =
+ getSafetySourceStatus(
+ mSafetyCenterDataManager.getSafetySourceDataInternal(key));
+ boolean inQuietMode = isUserManaged && !isManagedUserRunning;
+ if (safetySourceStatus != null) {
+ PendingIntent sourceProvidedPendingIntent =
+ inQuietMode ? null : safetySourceStatus.getPendingIntent();
+ PendingIntent entryPendingIntent =
+ sourceProvidedPendingIntent != null
+ ? sourceProvidedPendingIntent
+ : mPendingIntentFactory.getPendingIntent(
+ safetySource.getId(),
+ safetySource.getIntentAction(),
+ safetySource.getPackageName(),
+ userId,
+ inQuietMode);
+ if (entryPendingIntent == null) {
+ // TODO(b/222838784): Decide strategy for static entries when the intent is
+ // null.
+ return null;
+ }
+ return new SafetyCenterStaticEntry.Builder(safetySourceStatus.getTitle())
+ .setSummary(
+ inQuietMode
+ ? DevicePolicyResources.getWorkProfilePausedString(
+ mSafetyCenterResourcesContext)
+ : safetySourceStatus.getSummary())
+ .setPendingIntent(entryPendingIntent)
+ .build();
+ }
+ return toDefaultSafetyCenterStaticEntry(
+ safetySource,
+ safetySource.getPackageName(),
+ userId,
+ isUserManaged,
+ isManagedUserRunning);
+ case SafetySource.SAFETY_SOURCE_TYPE_STATIC:
+ return toDefaultSafetyCenterStaticEntry(
+ safetySource,
+ getStaticSourcePackageNameOrDefault(safetySource, defaultPackageName),
+ userId,
+ isUserManaged,
+ isManagedUserRunning);
+ }
+ Log.w(TAG, "Unknown safety source type found in rigid group: " + safetySource.getType());
+ return null;
+ }
+
+ @Nullable
+ private SafetyCenterStaticEntry toDefaultSafetyCenterStaticEntry(
+ SafetySource safetySource,
+ String packageName,
+ @UserIdInt int userId,
+ boolean isUserManaged,
+ boolean isManagedUserRunning) {
+ if (SafetySources.isDefaultEntryHidden(safetySource)) {
+ return null;
+ }
+ boolean isQuietModeEnabled = isUserManaged && !isManagedUserRunning;
+ PendingIntent pendingIntent =
+ mPendingIntentFactory.getPendingIntent(
+ safetySource.getId(),
+ safetySource.getIntentAction(),
+ packageName,
+ userId,
+ isQuietModeEnabled);
+
+ if (pendingIntent == null) {
+ // TODO(b/222838784): Decide strategy for static entries when the intent is null.
+ return null;
+ }
+
+ CharSequence title =
+ isUserManaged
+ ? DevicePolicyResources.getSafetySourceWorkString(
+ mSafetyCenterResourcesContext,
+ safetySource.getId(),
+ safetySource.getTitleForWorkResId())
+ : mSafetyCenterResourcesContext.getString(safetySource.getTitleResId());
+ CharSequence summary =
+ mSafetyCenterDataManager.sourceHasError(
+ SafetySourceKey.of(safetySource.getId(), userId))
+ ? getRefreshErrorString(1)
+ : mSafetyCenterResourcesContext.getOptionalString(
+ safetySource.getSummaryResId());
+ if (isQuietModeEnabled) {
+ summary =
+ DevicePolicyResources.getWorkProfilePausedString(mSafetyCenterResourcesContext);
+ }
+ return new SafetyCenterStaticEntry.Builder(title)
+ .setSummary(summary)
+ .setPendingIntent(pendingIntent)
+ .build();
+ }
+
+ @Nullable
+ private static SafetySourceStatus getSafetySourceStatus(
+ @Nullable SafetySourceData safetySourceData) {
+ if (safetySourceData == null) {
+ return null;
+ }
+
+ return safetySourceData.getStatus();
+ }
+
+ private static String getStaticSourcePackageNameOrDefault(
+ SafetySource safetySource, String defaultPackageName) {
+ if (!SdkLevel.isAtLeastU()) {
+ return defaultPackageName;
+ }
+ String sourcePackageName = safetySource.getOptionalPackageName();
+ if (sourcePackageName == null) {
+ return defaultPackageName;
+ }
+ return sourcePackageName;
+ }
+
+ @SafetyCenterStatus.OverallSeverityLevel
+ private static int toSafetyCenterStatusOverallSeverityLevel(
+ @SafetySourceData.SeverityLevel int safetySourceSeverityLevel) {
+ switch (safetySourceSeverityLevel) {
+ case SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED:
+ case SafetySourceData.SEVERITY_LEVEL_INFORMATION:
+ return SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK;
+ case SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION:
+ return SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION;
+ case SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING:
+ return SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING;
+ }
+
+ Log.w(TAG, "Unexpected SafetySourceData.SeverityLevel: " + safetySourceSeverityLevel);
+ return SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN;
+ }
+
+ @SafetyCenterStatus.OverallSeverityLevel
+ private static int entryToSafetyCenterStatusOverallSeverityLevel(
+ @SafetyCenterEntry.EntrySeverityLevel int safetyCenterEntrySeverityLevel) {
+ switch (safetyCenterEntrySeverityLevel) {
+ case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN:
+ return SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN;
+ case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED:
+ case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK:
+ return SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK;
+ case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION:
+ return SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION;
+ case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING:
+ return SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING;
+ }
+
+ Log.w(
+ TAG,
+ "Unexpected SafetyCenterEntry.EntrySeverityLevel: "
+ + safetyCenterEntrySeverityLevel);
+ return SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN;
+ }
+
+ @SafetyCenterEntry.EntrySeverityLevel
+ private static int toSafetyCenterEntrySeverityLevel(
+ @SafetySourceData.SeverityLevel int safetySourceSeverityLevel) {
+ switch (safetySourceSeverityLevel) {
+ case SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED:
+ return SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED;
+ case SafetySourceData.SEVERITY_LEVEL_INFORMATION:
+ return SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK;
+ case SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION:
+ return SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION;
+ case SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING:
+ return SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING;
+ }
+
+ Log.w(
+ TAG,
+ "Unexpected SafetySourceData.SeverityLevel in SafetySourceStatus: "
+ + safetySourceSeverityLevel);
+ return SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN;
+ }
+
+ @SafetyCenterIssue.IssueSeverityLevel
+ private static int toSafetyCenterIssueSeverityLevel(
+ @SafetySourceData.SeverityLevel int safetySourceIssueSeverityLevel) {
+ switch (safetySourceIssueSeverityLevel) {
+ case SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED:
+ Log.w(
+ TAG,
+ "Unexpected use of SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED in "
+ + "SafetySourceIssue");
+ return SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK;
+ case SafetySourceData.SEVERITY_LEVEL_INFORMATION:
+ return SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK;
+ case SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION:
+ return SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION;
+ case SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING:
+ return SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING;
+ }
+
+ Log.w(
+ TAG,
+ "Unexpected SafetySourceData.SeverityLevel in SafetySourceIssue: "
+ + safetySourceIssueSeverityLevel);
+ return SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK;
+ }
+
+ @SafetyCenterEntry.SeverityUnspecifiedIconType
+ private static int toGroupSeverityUnspecifiedIconType(
+ @SafetySourcesGroup.StatelessIconType int statelessIconType) {
+ switch (statelessIconType) {
+ case SafetySourcesGroup.STATELESS_ICON_TYPE_NONE:
+ return SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION;
+ case SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY:
+ return SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY;
+ }
+
+ Log.w(TAG, "Unexpected SafetySourcesGroup.StatelessIconType: " + statelessIconType);
+ return SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON;
+ }
+
+ @SafetyCenterEntry.IconAction.IconActionType
+ private static int toSafetyCenterEntryIconActionType(
+ @SafetySourceStatus.IconAction.IconType int safetySourceIconActionType) {
+ switch (safetySourceIconActionType) {
+ case SafetySourceStatus.IconAction.ICON_TYPE_GEAR:
+ return SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR;
+ case SafetySourceStatus.IconAction.ICON_TYPE_INFO:
+ return SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO;
+ }
+
+ Log.w(
+ TAG,
+ "Unexpected SafetySourceStatus.IconAction.IconActionType: "
+ + safetySourceIconActionType);
+ return SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO;
+ }
+
+ private String getSafetyCenterStatusTitle(
+ @SafetyCenterStatus.OverallSeverityLevel int overallSeverityLevel,
+ @Nullable SafetySourceIssueInfo topNonDismissedIssueInfo,
+ @SafetyCenterStatus.RefreshStatus int refreshStatus,
+ boolean hasSettingsToReview) {
+ boolean overallSeverityUnknown =
+ overallSeverityLevel == SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN;
+ String refreshStatusTitle =
+ getSafetyCenterRefreshStatusTitle(refreshStatus, overallSeverityUnknown);
+ if (refreshStatusTitle != null) {
+ return refreshStatusTitle;
+ }
+ switch (overallSeverityLevel) {
+ case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN:
+ case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK:
+ if (hasSettingsToReview) {
+ return mSafetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_ok_review_title");
+ }
+ return mSafetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_ok_title");
+ case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION:
+ return getStatusTitleFromIssueCategories(
+ topNonDismissedIssueInfo,
+ "overall_severity_level_device_recommendation_title",
+ "overall_severity_level_account_recommendation_title",
+ "overall_severity_level_safety_recommendation_title",
+ "overall_severity_level_data_recommendation_title",
+ "overall_severity_level_passwords_recommendation_title",
+ "overall_severity_level_personal_recommendation_title");
+ case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING:
+ return getStatusTitleFromIssueCategories(
+ topNonDismissedIssueInfo,
+ "overall_severity_level_critical_device_warning_title",
+ "overall_severity_level_critical_account_warning_title",
+ "overall_severity_level_critical_safety_warning_title",
+ "overall_severity_level_critical_data_warning_title",
+ "overall_severity_level_critical_passwords_warning_title",
+ "overall_severity_level_critical_personal_warning_title");
+ }
+
+ Log.w(TAG, "Unexpected SafetyCenterStatus.OverallSeverityLevel: " + overallSeverityLevel);
+ return "";
+ }
+
+ private String getStatusTitleFromIssueCategories(
+ @Nullable SafetySourceIssueInfo topNonDismissedIssueInfo,
+ String deviceResourceName,
+ String accountResourceName,
+ String generalResourceName,
+ String dataResourceName,
+ String passwordsResourceName,
+ String personalSafetyResourceName) {
+ String generalString = mSafetyCenterResourcesContext.getStringByName(generalResourceName);
+ if (topNonDismissedIssueInfo == null) {
+ Log.w(TAG, "No safety center issues found in a non-green status");
+ return generalString;
+ }
+ int issueCategory = topNonDismissedIssueInfo.getSafetySourceIssue().getIssueCategory();
+ switch (issueCategory) {
+ case SafetySourceIssue.ISSUE_CATEGORY_DEVICE:
+ return mSafetyCenterResourcesContext.getStringByName(deviceResourceName);
+ case SafetySourceIssue.ISSUE_CATEGORY_ACCOUNT:
+ return mSafetyCenterResourcesContext.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);
+ }
+ }
+
+ Log.w(TAG, "Unexpected SafetySourceIssue.IssueCategory: " + issueCategory);
+ return generalString;
+ }
+
+ private String getSafetyCenterStatusSummary(
+ SafetyCenterOverallState safetyCenterOverallState,
+ @Nullable SafetySourceIssueInfo topNonDismissedIssue,
+ @SafetyCenterStatus.RefreshStatus int refreshStatus,
+ int numTipIssues,
+ int numAutomaticIssues,
+ int numIssues) {
+ String refreshStatusSummary = getSafetyCenterRefreshStatusSummary(refreshStatus);
+ if (refreshStatusSummary != null) {
+ return refreshStatusSummary;
+ }
+ int overallSeverityLevel = safetyCenterOverallState.getOverallSeverityLevel();
+ switch (overallSeverityLevel) {
+ case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN:
+ case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK:
+ if (topNonDismissedIssue == null) {
+ if (safetyCenterOverallState.hasSettingsToReview()) {
+ return mSafetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_ok_review_summary");
+ }
+ return mSafetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_ok_summary");
+ } else if (isTip(topNonDismissedIssue.getSafetySourceIssue())) {
+ return mSafetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_tip_summary", numTipIssues);
+
+ } else if (isAutomatic(topNonDismissedIssue.getSafetySourceIssue())) {
+ return mSafetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_action_taken_summary", numAutomaticIssues);
+ }
+ // Fall through.
+ case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION:
+ case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING:
+ return getIcuPluralsString("overall_severity_n_alerts_summary", numIssues);
+ }
+
+ Log.w(TAG, "Unexpected SafetyCenterStatus.OverallSeverityLevel: " + overallSeverityLevel);
+ return "";
+ }
+
+ private static boolean isTip(SafetySourceIssue safetySourceIssue) {
+ return SdkLevel.isAtLeastU()
+ && safetySourceIssue.getIssueActionability()
+ == SafetySourceIssue.ISSUE_ACTIONABILITY_TIP;
+ }
+
+ private static boolean isAutomatic(SafetySourceIssue safetySourceIssue) {
+ return SdkLevel.isAtLeastU()
+ && safetySourceIssue.getIssueActionability()
+ == SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC;
+ }
+
+ private String getRefreshErrorString(int numberOfErrorEntries) {
+ return getIcuPluralsString("refresh_error", numberOfErrorEntries);
+ }
+
+ private String getIcuPluralsString(String name, int count, Object... formatArgs) {
+ MessageFormat messageFormat =
+ new MessageFormat(
+ mSafetyCenterResourcesContext.getStringByName(name, formatArgs),
+ Locale.getDefault());
+ ArrayMap<String, Object> arguments = new ArrayMap<>();
+ arguments.put("count", count);
+ return messageFormat.format(arguments);
+ }
+
+ @Nullable
+ private String getSafetyCenterRefreshStatusTitle(
+ @SafetyCenterStatus.RefreshStatus int refreshStatus, boolean overallSeverityUnknown) {
+ switch (refreshStatus) {
+ case SafetyCenterStatus.REFRESH_STATUS_NONE:
+ return null;
+ case SafetyCenterStatus.REFRESH_STATUS_DATA_FETCH_IN_PROGRESS:
+ if (!overallSeverityUnknown) {
+ return null;
+ }
+ // Fall through.
+ case SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS:
+ return mSafetyCenterResourcesContext.getStringByName("scanning_title");
+ }
+
+ Log.w(TAG, "Unexpected SafetyCenterStatus.RefreshStatus: " + refreshStatus);
+ return null;
+ }
+
+ @Nullable
+ private String getSafetyCenterRefreshStatusSummary(
+ @SafetyCenterStatus.RefreshStatus int refreshStatus) {
+ switch (refreshStatus) {
+ case SafetyCenterStatus.REFRESH_STATUS_NONE:
+ return null;
+ case SafetyCenterStatus.REFRESH_STATUS_DATA_FETCH_IN_PROGRESS:
+ case SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS:
+ return mSafetyCenterResourcesContext.getStringByName("loading_summary");
+ }
+
+ Log.w(TAG, "Unexpected SafetyCenterStatus.RefreshStatus: " + refreshStatus);
+ return null;
+ }
+
+ private static SafetySourceKey toSafetySourceKey(String safetyCenterEntryIdString) {
+ SafetyCenterEntryId id = SafetyCenterIds.entryIdFromString(safetyCenterEntryIdString);
+ return SafetySourceKey.of(id.getSafetySourceId(), id.getUserId());
+ }
+
+ /**
+ * An internal mutable class to keep track of the overall {@link SafetyCenterStatus} severity
+ * level and whether the list of entries provided requires attention.
+ */
+ private static final class SafetyCenterOverallState {
+
+ @SafetyCenterStatus.OverallSeverityLevel
+ private int mIssuesOverallSeverityLevel = SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK;
+
+ @SafetyCenterStatus.OverallSeverityLevel
+ private int mEntriesOverallSeverityLevel = SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK;
+
+ /**
+ * Adds a {@link SafetyCenterStatus.OverallSeverityLevel} computed from an issue.
+ *
+ * <p>The {@code overallSeverityLevel} provided cannot be {@link
+ * SafetyCenterStatus#OVERALL_SEVERITY_LEVEL_UNKNOWN}. If the data for an issue is not
+ * provided yet, this will be reflected when calling {@link
+ * #addEntryOverallSeverityLevel(int)}. The exception to that are issue-only safety sources
+ * but since they do not have user-visible entries they do not affect whether the overall
+ * status is unknown.
+ */
+ private void addIssueOverallSeverityLevel(
+ @SafetyCenterStatus.OverallSeverityLevel int issueOverallSeverityLevel) {
+ if (issueOverallSeverityLevel == SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN) {
+ return;
+ }
+ mIssuesOverallSeverityLevel =
+ mergeOverallSeverityLevels(
+ mIssuesOverallSeverityLevel, issueOverallSeverityLevel);
+ }
+
+ /**
+ * Adds a {@link SafetyCenterStatus.OverallSeverityLevel} computed from an entry.
+ *
+ * <p>Entries may be unknown (e.g. due to an error or no data provided yet). In this case,
+ * the overall status will be marked as unknown if there are no recommendations or critical
+ * issues.
+ */
+ private void addEntryOverallSeverityLevel(
+ @SafetyCenterStatus.OverallSeverityLevel int entryOverallSeverityLevel) {
+ mEntriesOverallSeverityLevel =
+ mergeOverallSeverityLevels(
+ mEntriesOverallSeverityLevel, entryOverallSeverityLevel);
+ }
+
+ /**
+ * Returns the {@link SafetyCenterStatus.OverallSeverityLevel} computed.
+ *
+ * <p>Returns {@link SafetyCenterStatus#OVERALL_SEVERITY_LEVEL_UNKNOWN} if any entry is
+ * unknown / has errored-out and there are no recommendations or critical issues.
+ *
+ * <p>Otherwise, this is computed based on the maximum severity level of issues.
+ */
+ @SafetyCenterStatus.OverallSeverityLevel
+ private int getOverallSeverityLevel() {
+ if (mEntriesOverallSeverityLevel == SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN
+ && mIssuesOverallSeverityLevel
+ <= SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK) {
+ return SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN;
+ }
+ return mIssuesOverallSeverityLevel;
+ }
+
+ /**
+ * Returns whether there are settings to review (i.e. at least one entry has a more severe
+ * status than the overall status, or if any entry is not yet known / has errored-out).
+ */
+ private boolean hasSettingsToReview() {
+ return mEntriesOverallSeverityLevel == SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN
+ || mEntriesOverallSeverityLevel > mIssuesOverallSeverityLevel;
+ }
+
+ @SafetyCenterStatus.OverallSeverityLevel
+ private static int mergeOverallSeverityLevels(
+ @SafetyCenterStatus.OverallSeverityLevel int left,
+ @SafetyCenterStatus.OverallSeverityLevel int right) {
+ if (left == SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN
+ || right == SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN) {
+ return SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN;
+ }
+ return Math.max(left, right);
+ }
+ }
+}
diff --git a/service/java/com/android/safetycenter/SafetyCenterDataTracker.java b/service/java/com/android/safetycenter/SafetyCenterDataTracker.java
deleted file mode 100644
index 0906ec7fb..000000000
--- a/service/java/com/android/safetycenter/SafetyCenterDataTracker.java
+++ /dev/null
@@ -1,707 +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;
-
-import static android.os.Build.VERSION_CODES.TIRAMISU;
-
-import static java.util.Collections.emptyList;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Binder;
-import android.safetycenter.SafetyCenterData;
-import android.safetycenter.SafetyCenterEntry;
-import android.safetycenter.SafetyCenterEntryGroup;
-import android.safetycenter.SafetyCenterEntryOrGroup;
-import android.safetycenter.SafetyCenterIssue;
-import android.safetycenter.SafetyCenterStaticEntry;
-import android.safetycenter.SafetyCenterStaticEntryGroup;
-import android.safetycenter.SafetyCenterStatus;
-import android.safetycenter.SafetySourceData;
-import android.safetycenter.SafetySourceIssue;
-import android.safetycenter.SafetySourceStatus;
-import android.safetycenter.config.SafetyCenterConfig;
-import android.safetycenter.config.SafetySource;
-import android.safetycenter.config.SafetySourcesGroup;
-import android.util.Log;
-
-import androidx.annotation.RequiresApi;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * A class that keeps track of all the {@link SafetySourceData} set by safety sources, and
- * aggregates them into a {@link SafetyCenterData} object to be used by permission controller.
- *
- * <p>This class isn't thread safe. Thread safety must be handled by the caller.
- */
-@RequiresApi(TIRAMISU)
-final class SafetyCenterDataTracker {
-
- private static final String TAG = "SafetyCenterDataTracker";
-
- private final Map<Key, SafetySourceData> mSafetySourceDataForKey = new HashMap<>();
-
- @NonNull private final Context mContext;
- @NonNull private final SafetyCenterConfigReader mSafetyCenterConfigReader;
-
- /**
- * Creates a {@link SafetyCenterDataTracker} using the given {@link Context} and {@link
- * SafetyCenterConfigReader}.
- */
- SafetyCenterDataTracker(
- @NonNull Context context, @NonNull SafetyCenterConfigReader safetyCenterConfigReader) {
- mContext = context;
- mSafetyCenterConfigReader = safetyCenterConfigReader;
- }
-
- /**
- * Sets the latest {@link SafetySourceData} for the given {@code safetySourceId} and {@code
- * userId}, and returns the updated {@link SafetyCenterData} of the {@code userId}.
- *
- * <p>Returns {@code null} if there was no update to the underlying {@link SafetyCenterData}, or
- * if the {@link SafetyCenterConfig} is not available.
- */
- @Nullable
- SafetyCenterData setSafetySourceData(
- @NonNull String safetySourceId,
- @Nullable SafetySourceData safetySourceData,
- @NonNull String packageName,
- @UserIdInt int userId) {
- if (!configContains(safetySourceId, packageName)) {
- // TODO(b/218801292): Should this be hard error for the caller?
- return null;
- }
-
- Key key = Key.of(safetySourceId, packageName, userId);
- SafetySourceData existingSafetySourceData = mSafetySourceDataForKey.get(key);
- if (Objects.equals(safetySourceData, existingSafetySourceData)) {
- return null;
- }
-
- mSafetySourceDataForKey.put(key, safetySourceData);
- return getSafetyCenterData(userId);
- }
-
- /**
- * Returns the latest {@link SafetySourceData} for the given {@code safetySourceId} and {@code
- * userId}.
- *
- * <p>Returns {@code null} if there was no data set.
- */
- @Nullable
- SafetySourceData getSafetySourceData(
- @NonNull String safetySourceId, @NonNull String packageName, @UserIdInt int userId) {
- if (!configContains(safetySourceId, packageName)) {
- // TODO(b/218801292): Should this be hard error for the caller?
- return null;
- }
-
- return mSafetySourceDataForKey.get(Key.of(safetySourceId, packageName, userId));
- }
-
- /** Clears all the {@link SafetySourceData} set received so far, for all users. */
- void clear() {
- mSafetySourceDataForKey.clear();
- }
-
- /**
- * Returns the current {@link SafetyCenterData} for the given {@code userId}, aggregated from
- * all the {@link SafetySourceData} set so far.
- *
- * <p>Returns an arbitrary default value if no data has been received for the user so far, or if
- * the {@link SafetyCenterConfig} is not available.
- */
- @NonNull
- SafetyCenterData getSafetyCenterData(@UserIdInt int userId) {
- SafetyCenterConfig safetyCenterConfig = mSafetyCenterConfigReader.getSafetyCenterConfig();
- if (safetyCenterConfig == null) {
- Log.w(TAG, "SafetyCenterConfig unavailable, returning default SafetyCenterData");
- return getDefaultSafetyCenterData();
- }
-
- // TODO(b/218819144): Merge for all profiles.
- return getSafetyCenterData(safetyCenterConfig, userId);
- }
-
- /**
- * Returns a default {@link SafetyCenterData} object to be returned when the API is disabled.
- */
- @NonNull
- static SafetyCenterData getDefaultSafetyCenterData() {
- return new SafetyCenterData(
- new SafetyCenterStatus.Builder(
- getSafetyCenterStatusTitle(
- SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN),
- getSafetyCenterStatusSummary(
- SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN))
- .setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN)
- .build(),
- emptyList(),
- emptyList(),
- emptyList());
- }
-
- // TODO(b/219702252): Create a more efficient data structure for this, and update it when the
- // config changes.
- private boolean configContains(@NonNull String safetySourceId, @NonNull String packageName) {
- SafetyCenterConfig safetyCenterConfig = mSafetyCenterConfigReader.getSafetyCenterConfig();
- if (safetyCenterConfig == null) {
- Log.w(TAG, "SafetyCenterConfig unavailable, assuming no sources can send/get data");
- return false;
- }
-
- // TODO(b/217944317): Remove this allowlisting once the test API for the config is
- // available.
- if (packageName.equals("android.safetycenter.cts")) {
- return true;
- }
-
- List<SafetySourcesGroup> safetySourcesGroups = safetyCenterConfig.getSafetySourcesGroups();
- for (int i = 0; i < safetySourcesGroups.size(); i++) {
- SafetySourcesGroup safetySourcesGroup = safetySourcesGroups.get(i);
-
- List<SafetySource> safetySources = safetySourcesGroup.getSafetySources();
- for (int j = 0; j < safetySources.size(); j++) {
- SafetySource safetySource = safetySources.get(j);
-
- if (safetySource.getType() == SafetySource.SAFETY_SOURCE_TYPE_STATIC) {
- continue;
- }
-
- if (safetySourceId.equals(safetySource.getId())
- && packageName.equals(safetySource.getPackageName())) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- @NonNull
- private SafetyCenterData getSafetyCenterData(
- @NonNull SafetyCenterConfig safetyCenterConfig, @UserIdInt int userId) {
- int maxSafetyCenterEntryLevel = SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN;
- List<SafetyCenterIssue> safetyCenterIssues = new ArrayList<>();
- List<SafetyCenterEntryOrGroup> safetyCenterEntryOrGroups = new ArrayList<>();
- List<SafetyCenterStaticEntryGroup> safetyCenterStaticEntryGroups = new ArrayList<>();
-
- List<SafetySourcesGroup> safetySourcesGroups = safetyCenterConfig.getSafetySourcesGroups();
- for (int i = 0; i < safetySourcesGroups.size(); i++) {
- SafetySourcesGroup safetySourcesGroup = safetySourcesGroups.get(i);
-
- int groupSafetyCenterEntryLevel = SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN;
- switch (safetySourcesGroup.getType()) {
- case SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_COLLAPSIBLE: {
- groupSafetyCenterEntryLevel =
- Math.max(
- addSafetyCenterIssues(
- safetyCenterIssues, safetySourcesGroup, userId),
- addSafetyCenterEntryGroup(
- safetyCenterEntryOrGroups,
- safetySourcesGroup,
- userId));
- break;
- }
- case SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_RIGID: {
- addSafetyCenterStaticEntryGroup(
- safetyCenterStaticEntryGroups, safetySourcesGroup);
- break;
- }
- case SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_HIDDEN: {
- groupSafetyCenterEntryLevel =
- addSafetyCenterIssues(
- safetyCenterIssues, safetySourcesGroup, userId);
- break;
- }
- }
- // TODO(b/219700241): Should we rely on ordering for severity levels?
- maxSafetyCenterEntryLevel =
- Math.max(maxSafetyCenterEntryLevel, groupSafetyCenterEntryLevel);
- }
-
- int safetyCenterOverallSeverityLevel =
- entryToSafetyCenterStatusOverallLevel(maxSafetyCenterEntryLevel);
- return new SafetyCenterData(
- new SafetyCenterStatus.Builder(
- getSafetyCenterStatusTitle(safetyCenterOverallSeverityLevel),
- getSafetyCenterStatusSummary(safetyCenterOverallSeverityLevel))
- .setSeverityLevel(safetyCenterOverallSeverityLevel)
- .build(),
- safetyCenterIssues,
- safetyCenterEntryOrGroups,
- safetyCenterStaticEntryGroups);
- }
-
- @SafetyCenterEntry.EntrySeverityLevel
- private int addSafetyCenterIssues(
- @NonNull List<SafetyCenterIssue> safetyCenterIssues,
- @NonNull SafetySourcesGroup safetySourcesGroup,
- @UserIdInt int userId) {
- int maxSafetyCenterEntrySeverityLevel = SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN;
- List<SafetySource> safetySources = safetySourcesGroup.getSafetySources();
- for (int i = 0; i < safetySources.size(); i++) {
- SafetySource safetySource = safetySources.get(i);
-
- if (safetySource.getType() == SafetySource.SAFETY_SOURCE_TYPE_STATIC) {
- continue;
- }
-
- Key key = Key.of(safetySource.getId(), safetySource.getPackageName(), userId);
- SafetySourceData safetySourceData = mSafetySourceDataForKey.get(key);
- if (safetySourceData == null) {
- continue;
- }
-
- List<SafetySourceIssue> safetySourceIssues = safetySourceData.getIssues();
- for (int j = 0; j < safetySourceIssues.size(); j++) {
- SafetySourceIssue safetySourceIssue = safetySourceIssues.get(j);
-
- SafetyCenterIssue safetyCenterIssue = toSafetyCenterIssue(safetySourceIssue);
- maxSafetyCenterEntrySeverityLevel =
- Math.max(
- maxSafetyCenterEntrySeverityLevel,
- issueToSafetyCenterEntryLevel(
- safetyCenterIssue.getSeverityLevel()));
- safetyCenterIssues.add(safetyCenterIssue);
- }
- }
-
- return maxSafetyCenterEntrySeverityLevel;
- }
-
- @NonNull
- private static SafetyCenterIssue toSafetyCenterIssue(
- @NonNull SafetySourceIssue safetySourceIssue) {
- List<SafetySourceIssue.Action> safetySourceIssueActions = safetySourceIssue.getActions();
- List<SafetyCenterIssue.Action> safetyCenterIssueActions =
- new ArrayList<>(safetySourceIssueActions.size());
- for (int i = 0; i < safetySourceIssueActions.size(); i++) {
- SafetySourceIssue.Action safetySourceIssueAction = safetySourceIssueActions.get(i);
-
- safetyCenterIssueActions.add(
- new SafetyCenterIssue.Action.Builder(
- safetySourceIssue.getId(),
- safetySourceIssueAction.getLabel(),
- safetySourceIssueAction.getPendingIntent())
- .setSuccessMessage(safetySourceIssueAction.getSuccessMessage())
- .build());
- }
-
- // TODO(b/218817233): Add missing fields like: dismissible, shouldConfirmDismissal.
- return new SafetyCenterIssue.Builder(
- safetySourceIssue.getId(),
- safetySourceIssue.getTitle(),
- safetySourceIssue.getSummary())
- .setSeverityLevel(
- sourceToSafetyCenterIssueSeverityLevel(
- safetySourceIssue.getSeverityLevel()))
- .setSubtitle(safetySourceIssue.getSubtitle())
- .setActions(safetyCenterIssueActions)
- .build();
- }
-
- @SafetyCenterEntry.EntrySeverityLevel
- private int addSafetyCenterEntryGroup(
- @NonNull List<SafetyCenterEntryOrGroup> safetyCenterEntryOrGroups,
- @NonNull SafetySourcesGroup safetySourcesGroup,
- @UserIdInt int userId) {
- int maxSafetyCenterEntryLevel = SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN;
-
- List<SafetySource> safetySources = safetySourcesGroup.getSafetySources();
- List<SafetyCenterEntry> entries = new ArrayList<>(safetySources.size());
- for (int i = 0; i < safetySources.size(); i++) {
- SafetySource safetySource = safetySources.get(i);
-
- SafetyCenterEntry safetyCenterEntry = toSafetyCenterEntry(safetySource, userId);
- if (safetyCenterEntry == null) {
- continue;
- }
-
- // TODO(b/219700241): Should we rely on ordering for severity levels?
- maxSafetyCenterEntryLevel =
- Math.max(maxSafetyCenterEntryLevel, safetyCenterEntry.getSeverityLevel());
- entries.add(safetyCenterEntry);
- }
-
- // TODO(b/218817233): Add missing fields like: statelessIconType.
- safetyCenterEntryOrGroups.add(
- new SafetyCenterEntryOrGroup(
- new SafetyCenterEntryGroup.Builder(
- safetySourcesGroup.getId(),
- mSafetyCenterConfigReader.readStringResource(
- safetySourcesGroup.getTitleResId()))
- .setSeverityLevel(maxSafetyCenterEntryLevel)
- .setSummary(
- mSafetyCenterConfigReader.readStringResource(
- safetySourcesGroup.getSummaryResId()))
- .setEntries(entries)
- .build()));
-
- return maxSafetyCenterEntryLevel;
- }
-
- @Nullable
- private SafetyCenterEntry toSafetyCenterEntry(
- @NonNull SafetySource safetySource, @UserIdInt int userId) {
- switch (safetySource.getType()) {
- case SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY: {
- Log.w(TAG, "Issue only safety source found in collapsible group");
- return null;
- }
- case SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC: {
- Key key = Key.of(safetySource.getId(), safetySource.getPackageName(), userId);
- SafetySourceStatus safetySourceStatus =
- getSafetySourceStatus(mSafetySourceDataForKey.get(key));
- // TODO(b/218817233): Add missing fields like: iconAction, statelessIconType.
- if (safetySourceStatus != null) {
- PendingIntent pendingIntent = safetySourceStatus.getPendingIntent();
- if (pendingIntent == null) {
- pendingIntent =
- toPendingIntent(
- safetySource.getIntentAction(),
- safetySource.getPackageName());
- // TODO(b/222838784): Automatically mark the source as disabled if the
- // pending intent is null again.
- }
- return new SafetyCenterEntry.Builder(
- safetySource.getId(), safetySourceStatus.getTitle())
- .setSeverityLevel(
- sourceToSafetyCenterEntrySeverityLevel(
- safetySourceStatus.getSeverityLevel()))
- .setSummary(safetySourceStatus.getSummary())
- .setEnabled(safetySourceStatus.isEnabled())
- .setPendingIntent(pendingIntent)
- .build();
- }
- return toDefaultSafetyCenterEntry(
- safetySource,
- safetySource.getPackageName(),
- SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED);
- }
- case SafetySource.SAFETY_SOURCE_TYPE_STATIC: {
- return toDefaultSafetyCenterEntry(
- safetySource, null, SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN);
- }
- }
- Log.w(
- TAG,
- String.format(
- "Unknown safety source type found in collapsible group: %s",
- safetySource.getType()));
- return null;
- }
-
- @Nullable
- private SafetyCenterEntry toDefaultSafetyCenterEntry(
- @NonNull SafetySource safetySource,
- @Nullable String packageName,
- @SafetyCenterEntry.EntrySeverityLevel int entrySeverityLevel) {
- if (safetySource.getType() == SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC
- && safetySource.getInitialDisplayState()
- == SafetySource.INITIAL_DISPLAY_STATE_HIDDEN) {
- return null;
- }
-
- PendingIntent pendingIntent = toPendingIntent(safetySource.getIntentAction(), packageName);
-
- // TODO(b/218817233): Add missing fields like: enabled.
- // TODO(b/222838784): Automatically mark the source as disabled (both dynamic and static?)
- // if the pending intent is null.
- return new SafetyCenterEntry.Builder(
- safetySource.getId(),
- mSafetyCenterConfigReader.readStringResource(safetySource.getTitleResId()))
- .setSeverityLevel(entrySeverityLevel)
- .setSummary(
- mSafetyCenterConfigReader.readStringResource(
- safetySource.getSummaryResId()))
- .setPendingIntent(pendingIntent)
- .build();
- }
-
- private void addSafetyCenterStaticEntryGroup(
- @NonNull List<SafetyCenterStaticEntryGroup> safetyCenterStaticEntryGroups,
- @NonNull SafetySourcesGroup safetySourcesGroup) {
- List<SafetySource> safetySources = safetySourcesGroup.getSafetySources();
- List<SafetyCenterStaticEntry> staticEntries = new ArrayList<>(safetySources.size());
- for (int i = 0; i < safetySources.size(); i++) {
- SafetySource safetySource = safetySources.get(i);
-
- if (safetySource.getType() != SafetySource.SAFETY_SOURCE_TYPE_STATIC) {
- Log.w(TAG, "Non-static safety source found in rigid group");
- continue;
- }
-
- PendingIntent pendingIntent = toPendingIntent(safetySource.getIntentAction(), null);
- if (pendingIntent == null) {
- // TODO(b/222838784): Decide strategy for static entries when the intent is null.
- continue;
- }
-
- staticEntries.add(
- new SafetyCenterStaticEntry.Builder(
- mSafetyCenterConfigReader.readStringResource(
- safetySource.getTitleResId()))
- .setSummary(
- mSafetyCenterConfigReader.readStringResource(
- safetySource.getSummaryResId()))
- .setPendingIntent(pendingIntent)
- .build());
- }
-
- safetyCenterStaticEntryGroups.add(
- new SafetyCenterStaticEntryGroup(
- mSafetyCenterConfigReader.readStringResource(
- safetySourcesGroup.getTitleResId()),
- staticEntries));
- }
-
- @Nullable
- private PendingIntent toPendingIntent(
- @Nullable String intentAction, @Nullable String packageName) {
- if (intentAction == null) {
- return null;
- }
-
- Context context;
- if (packageName == null) {
- context = mContext;
- } else {
- final long identity = Binder.clearCallingIdentity();
- try {
- context = mContext.createPackageContext(packageName, 0);
- } catch (NameNotFoundException e) {
- Log.w(TAG, String.format("Package name %s not found", packageName), e);
- return null;
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- // TODO(b/222838784): Validate that the intent action is available.
-
- // TODO(b/219699223): Is it safe to create a PendingIntent as system server here?
- final long identity = Binder.clearCallingIdentity();
- try {
- // TODO(b/218816518): May need to create a unique requestCode per PendingIntent.
- return PendingIntent.getActivity(
- context, 0, new Intent(intentAction), PendingIntent.FLAG_IMMUTABLE);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- @Nullable
- private static SafetySourceStatus getSafetySourceStatus(
- @Nullable SafetySourceData safetySourceData) {
- if (safetySourceData == null) {
- return null;
- }
-
- return safetySourceData.getStatus();
- }
-
- @SafetyCenterStatus.OverallSeverityLevel
- private static int entryToSafetyCenterStatusOverallLevel(
- @SafetyCenterEntry.EntrySeverityLevel int safetyCenterEntrySeverityLevel) {
- switch (safetyCenterEntrySeverityLevel) {
- case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN:
- return SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN;
- case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED:
- case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK:
- return SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK;
- case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION:
- return SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION;
- case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING:
- return SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING;
- }
-
- throw new IllegalArgumentException(
- String.format(
- "Unexpected SafetyCenterEntry.EntrySeverityLevel: %s",
- safetyCenterEntrySeverityLevel));
- }
-
- @SafetyCenterEntry.EntrySeverityLevel
- private static int issueToSafetyCenterEntryLevel(
- @SafetyCenterIssue.IssueSeverityLevel int safetyCenterIssueSeverityLevel) {
- switch (safetyCenterIssueSeverityLevel) {
- case SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK:
- return SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK;
- case SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION:
- return SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION;
- case SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING:
- return SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING;
- }
-
- throw new IllegalArgumentException(
- String.format(
- "Unexpected SafetyCenterIssue.IssueSeverityLevel: %s",
- safetyCenterIssueSeverityLevel));
- }
-
- @SafetyCenterEntry.EntrySeverityLevel
- private static int sourceToSafetyCenterEntrySeverityLevel(
- @SafetySourceData.SeverityLevel int safetySourceSeverityLevel) {
- switch (safetySourceSeverityLevel) {
- case SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED:
- return SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED;
- case SafetySourceData.SEVERITY_LEVEL_INFORMATION:
- return SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK;
- case SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION:
- return SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION;
- case SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING:
- return SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING;
- }
-
- throw new IllegalArgumentException(
- String.format(
- "Unexpected SafetySourceSeverity.Level in SafetySourceStatus: %s",
- safetySourceSeverityLevel));
- }
-
- @SafetyCenterIssue.IssueSeverityLevel
- private static int sourceToSafetyCenterIssueSeverityLevel(
- @SafetySourceData.SeverityLevel int safetySourceIssueSeverityLevel) {
- switch (safetySourceIssueSeverityLevel) {
- case SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED:
- Log.w(
- TAG,
- "Unexpected use of SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED in "
- + "SafetySourceStatus");
- return SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK;
- case SafetySourceData.SEVERITY_LEVEL_INFORMATION:
- return SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK;
- case SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION:
- return SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION;
- case SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING:
- return SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING;
- }
-
- throw new IllegalArgumentException(
- String.format(
- "Unexpected SafetySourceSeverity.Level in SafetySourceIssue: %s",
- safetySourceIssueSeverityLevel));
- }
-
- // TODO(b/218801295): Use the right strings and localize them.
- private static String getSafetyCenterStatusTitle(
- @SafetyCenterStatus.OverallSeverityLevel int overallSeverityLevel) {
- switch (overallSeverityLevel) {
- case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN:
- return "Unknown";
- case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK:
- return "All good";
- case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION:
- return "Some warnings";
- case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING:
- return "Uh-oh";
- }
-
- throw new IllegalArgumentException(
- String.format(
- "Unexpected SafetyCenterStatus.OverallSeverityLevel: %s",
- overallSeverityLevel));
- }
-
- // TODO(b/218801295): Use the right strings and localize them.
- private static String getSafetyCenterStatusSummary(
- @SafetyCenterStatus.OverallSeverityLevel int overallSeverityLevel) {
- switch (overallSeverityLevel) {
- case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN:
- return "Unknown safety status";
- case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK:
- return "No problemo maestro";
- case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION:
- return "Careful there";
- case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING:
- return "Code red";
- }
-
- throw new IllegalArgumentException(
- String.format(
- "Unexpected SafetyCenterStatus.OverallSeverityLevel: %s",
- overallSeverityLevel));
- }
-
- /**
- * A key for {@link SafetySourceData}; based on the {@code safetySourceId}, {@code packageName}
- * and {@code userId}.
- */
- // TODO(b/219697341): Look into using AutoValue for this data class.
- private static final class Key {
- @NonNull private final String mSafetySourceId;
- @NonNull private final String mPackageName;
- @UserIdInt private final int mUserId;
-
- private Key(
- @NonNull String safetySourceId,
- @NonNull String packageName,
- @UserIdInt int userId) {
- mSafetySourceId = safetySourceId;
- mPackageName = packageName;
- mUserId = userId;
- }
-
- @NonNull
- private static Key of(
- @NonNull String safetySourceId,
- @NonNull String packageName,
- @UserIdInt int userId) {
- return new Key(safetySourceId, packageName, userId);
- }
-
- @Override
- public String toString() {
- return "Key{"
- + "mSafetySourceId='"
- + mSafetySourceId
- + '\''
- + ", mPackageName='"
- + mPackageName
- + '\''
- + ", mUserId="
- + mUserId
- + '\''
- + '}';
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof Key)) return false;
- Key key = (Key) o;
- return mSafetySourceId.equals(key.mSafetySourceId)
- && mPackageName.equals(key.mPackageName)
- && mUserId == key.mUserId;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mSafetySourceId, mPackageName, mUserId);
- }
- }
-}
diff --git a/service/java/com/android/safetycenter/SafetyCenterFlags.java b/service/java/com/android/safetycenter/SafetyCenterFlags.java
new file mode 100644
index 000000000..1fc88d4b0
--- /dev/null
+++ b/service/java/com/android/safetycenter/SafetyCenterFlags.java
@@ -0,0 +1,576 @@
+/*
+ * 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;
+
+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;
+import android.safetycenter.SafetySourceIssue;
+import android.util.ArraySet;
+import android.util.Log;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.modules.utils.build.SdkLevel;
+import com.android.safetycenter.resources.SafetyCenterResourcesContext;
+
+import java.io.PrintWriter;
+import java.time.Duration;
+
+/**
+ * A class to access the Safety Center {@link DeviceConfig} flags.
+ *
+ * @hide
+ */
+@RequiresApi(TIRAMISU)
+public final class SafetyCenterFlags {
+
+ private static final String TAG = "SafetyCenterFlags";
+
+ /** {@link DeviceConfig} property name for {@link #getSafetyCenterEnabled()}. */
+ static final String PROPERTY_SAFETY_CENTER_ENABLED = "safety_center_is_enabled";
+
+ private static final String PROPERTY_NOTIFICATIONS_ENABLED =
+ "safety_center_notifications_enabled";
+
+ private static final String PROPERTY_NOTIFICATIONS_ALLOWED_SOURCES =
+ "safety_center_notifications_allowed_sources";
+
+ private static final String PROPERTY_NOTIFICATIONS_MIN_DELAY =
+ "safety_center_notifications_min_delay";
+
+ private static final String PROPERTY_NOTIFICATIONS_IMMEDIATE_BEHAVIOR_ISSUES =
+ "safety_center_notifications_immediate_behavior_issues";
+
+ 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";
+
+ private static final String PROPERTY_RESOLVING_ACTION_TIMEOUT_MILLIS =
+ "safety_center_resolve_action_timeout_millis";
+
+ private static final String PROPERTY_FGS_ALLOWLIST_DURATION_MILLIS =
+ "safety_center_refresh_fgs_allowlist_duration_millis";
+
+ private static final String PROPERTY_RESURFACE_ISSUE_MAX_COUNTS =
+ "safety_center_resurface_issue_max_counts";
+
+ private static final String PROPERTY_RESURFACE_ISSUE_DELAYS_MILLIS =
+ "safety_center_resurface_issue_delays_millis";
+
+ private static final String PROPERTY_UNTRACKED_SOURCES = "safety_center_untracked_sources";
+
+ private static final String PROPERTY_BACKGROUND_REFRESH_DENIED_SOURCES =
+ "safety_center_background_refresh_denied_sources";
+
+ private static final String PROPERTY_REFRESH_SOURCES_TIMEOUTS_MILLIS =
+ "safety_center_refresh_sources_timeouts_millis";
+
+ private static final String PROPERTY_ISSUE_CATEGORY_ALLOWLISTS =
+ "safety_center_issue_category_allowlists";
+
+ private static final String PROPERTY_ALLOW_STATSD_LOGGING =
+ "safety_center_allow_statsd_logging";
+
+ private static final String PROPERTY_SHOW_SUBPAGES = "safety_center_show_subpages";
+
+ private static final String PROPERTY_OVERRIDE_REFRESH_ON_PAGE_OPEN_SOURCES =
+ "safety_center_override_refresh_on_page_open_sources";
+
+ private static final String PROPERTY_ADDITIONAL_ALLOW_PACKAGE_CERTS =
+ "safety_center_additional_allow_package_certs";
+
+ private static final Duration FGS_ALLOWLIST_DEFAULT_DURATION = Duration.ofSeconds(20);
+
+ private static final String PROPERTY_TEMP_HIDDEN_ISSUE_RESURFACE_DELAY_MILLIS =
+ "safety_center_temp_hidden_issue_resurface_delay_millis";
+
+ private static final Duration RESOLVING_ACTION_TIMEOUT_DEFAULT_DURATION =
+ Duration.ofSeconds(10);
+
+ private static final Duration NOTIFICATIONS_MIN_DELAY_DEFAULT_DURATION = Duration.ofDays(180);
+
+ private static final String REFRESH_SOURCES_TIMEOUT_DEFAULT =
+ "100:15000,200:60000,300:30000,400:30000,500:30000,600:3600000";
+ private static final Duration REFRESH_SOURCES_TIMEOUT_DEFAULT_DURATION = Duration.ofSeconds(15);
+
+ private static final String RESURFACE_ISSUE_MAX_COUNT_DEFAULT = "200:0,300:1,400:1";
+ private static final long RESURFACE_ISSUE_MAX_COUNT_DEFAULT_COUNT = 0;
+
+ private static final String RESURFACE_ISSUE_DELAYS_DEFAULT = "";
+ private static final Duration RESURFACE_ISSUE_DELAYS_DEFAULT_DURATION = Duration.ofDays(180);
+
+ private static volatile String sUntrackedSourcesDefault =
+ "AndroidAccessibility,AndroidBackgroundLocation,"
+ + "AndroidNotificationListener,AndroidPermissionAutoRevoke";
+
+ private static volatile String sBackgroundRefreshDenyDefault = "";
+
+ private static volatile String sIssueCategoryAllowlistDefault = "";
+
+ private static volatile String sRefreshOnPageOpenSourcesDefault =
+ "AndroidBiometrics,AndroidLockScreen";
+
+ static void init(SafetyCenterResourcesContext resourceContext) {
+ String untrackedSourcesDefault =
+ resourceContext.getOptionalStringByName("config_defaultUntrackedSources");
+ if (untrackedSourcesDefault != null) {
+ sUntrackedSourcesDefault = untrackedSourcesDefault;
+ }
+ String backgroundRefreshDenyDefault =
+ resourceContext.getOptionalStringByName("config_defaultBackgroundRefreshDeny");
+ if (backgroundRefreshDenyDefault != null) {
+ sBackgroundRefreshDenyDefault = backgroundRefreshDenyDefault;
+ }
+ String issueCategoryAllowlistDefault =
+ resourceContext.getOptionalStringByName("config_defaultIssueCategoryAllowlist");
+ if (issueCategoryAllowlistDefault != null) {
+ sIssueCategoryAllowlistDefault = issueCategoryAllowlistDefault;
+ }
+ String refreshOnPageOpenSourcesDefault =
+ resourceContext.getOptionalStringByName("config_defaultRefreshOnPageOpenSources");
+ if (refreshOnPageOpenSourcesDefault != null) {
+ sRefreshOnPageOpenSourcesDefault = refreshOnPageOpenSourcesDefault;
+ }
+ }
+
+ private static final Duration TEMP_HIDDEN_ISSUE_RESURFACE_DELAY_DEFAULT_DURATION =
+ Duration.ofDays(2);
+
+ /** Dumps state for debugging purposes. */
+ static void dump(PrintWriter fout) {
+ 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_MIN_DELAY, getNotificationsMinDelay());
+ printFlag(
+ fout,
+ PROPERTY_NOTIFICATIONS_IMMEDIATE_BEHAVIOR_ISSUES,
+ 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());
+ printFlag(fout, PROPERTY_UNTRACKED_SOURCES, getUntrackedSourceIds());
+ printFlag(fout, PROPERTY_RESURFACE_ISSUE_MAX_COUNTS, getResurfaceIssueMaxCounts());
+ printFlag(fout, PROPERTY_RESURFACE_ISSUE_DELAYS_MILLIS, getResurfaceIssueDelaysMillis());
+ printFlag(
+ fout,
+ PROPERTY_BACKGROUND_REFRESH_DENIED_SOURCES,
+ getBackgroundRefreshDeniedSourceIds());
+ printFlag(
+ fout, PROPERTY_REFRESH_SOURCES_TIMEOUTS_MILLIS, getRefreshSourcesTimeoutsMillis());
+ printFlag(fout, PROPERTY_ISSUE_CATEGORY_ALLOWLISTS, getIssueCategoryAllowlists());
+ printFlag(fout, PROPERTY_ALLOW_STATSD_LOGGING, getAllowStatsdLogging());
+ printFlag(fout, PROPERTY_SHOW_SUBPAGES, getShowSubpages());
+ printFlag(
+ fout,
+ PROPERTY_OVERRIDE_REFRESH_ON_PAGE_OPEN_SOURCES,
+ getOverrideRefreshOnPageOpenSourceIds());
+ printFlag(
+ fout,
+ PROPERTY_ADDITIONAL_ALLOW_PACKAGE_CERTS,
+ getAdditionalAllowedPackageCertsString());
+ fout.println();
+ }
+
+ private static void printFlag(PrintWriter pw, String key, @Nullable Duration duration) {
+ if (duration == null) {
+ printFlag(pw, key, "null");
+ } else {
+ printFlag(pw, key, duration.toMillis() + " (" + duration + ")");
+ }
+ }
+
+ private static void printFlag(PrintWriter pw, String key, Object value) {
+ pw.println("\t" + key + "=" + value);
+ }
+
+ /** Returns whether Safety Center is enabled. */
+ public static boolean getSafetyCenterEnabled() {
+ return getBoolean(PROPERTY_SAFETY_CENTER_ENABLED, SdkLevel.isAtLeastU());
+ }
+
+ /** Returns whether Safety Center notifications are enabled. */
+ public static boolean getNotificationsEnabled() {
+ return getBoolean(PROPERTY_NOTIFICATIONS_ENABLED, SdkLevel.isAtLeastU());
+ }
+
+ /**
+ * Returns the IDs of sources that Safety Center can send notifications about, in addition to
+ * those permitted by the current XML config.
+ *
+ * <p>If the ID of a source appears on this list then Safety Center may send notifications about
+ * issues from that source, regardless of (overriding) the XML config. If the ID of a source is
+ * absent from this list, then Safety Center may send such notifications only if the XML config
+ * allows it.
+ *
+ * <p>Note that the {@code areNotificationsAllowed} config attribute is only available on API U+
+ * and therefore this is the only way to enable notifications for sources on Android T.
+ */
+ public static ArraySet<String> getNotificationsAllowedSourceIds() {
+ return getCommaSeparatedStrings(PROPERTY_NOTIFICATIONS_ALLOWED_SOURCES);
+ }
+
+ /**
+ * Returns the minimum delay before Safety Center can send a notification for an issue with
+ * {@link SafetySourceIssue#NOTIFICATION_BEHAVIOR_DELAYED}.
+ *
+ * <p>The actual delay used may be longer.
+ */
+ public static Duration getNotificationsMinDelay() {
+ return getDuration(
+ PROPERTY_NOTIFICATIONS_MIN_DELAY, NOTIFICATIONS_MIN_DELAY_DEFAULT_DURATION);
+ }
+
+ /**
+ * Returns the issue type IDs for which, if otherwise undefined, Safety Center should use {@link
+ * SafetySourceIssue#NOTIFICATION_BEHAVIOR_IMMEDIATELY}.
+ *
+ * <p>If a safety source specifies the notification behavior of an issue explicitly this flag
+ * has no effect, even if the issue matches one of the entries in this flag.
+ *
+ * <p>Entries in this set should be strings of the form "safety_source_id/issue_type_id".
+ */
+ public static ArraySet<String> getImmediateNotificationBehaviorIssues() {
+ return getCommaSeparatedStrings(PROPERTY_NOTIFICATIONS_IMMEDIATE_BEHAVIOR_ISSUES);
+ }
+
+ /**
+ * Returns the minimum interval that must elapse before Safety Center can resurface a
+ * notification after it was dismissed, or {@code null} (the default) if dismissed notifications
+ * cannot resurface.
+ *
+ * <p>Returns {@code null} if the underlying device config flag is either unset or is set to a
+ * negative value.
+ *
+ * <p>There may be other conditions for resurfacing a notification and the actual delay may be
+ * longer than this.
+ */
+ @Nullable
+ public static Duration getNotificationResurfaceInterval() {
+ long millis = getLong(PROPERTY_NOTIFICATION_RESURFACE_INTERVAL, -1);
+ if (millis < 0) {
+ return null;
+ } else {
+ return Duration.ofMillis(millis);
+ }
+ }
+
+ /**
+ * 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}.
+ */
+ public static boolean getReplaceLockScreenIconAction() {
+ return getBoolean(PROPERTY_REPLACE_LOCK_SCREEN_ICON_ACTION, true);
+ }
+
+ /**
+ * Returns the time for which Safety Center will wait for a source to respond to a resolving
+ * action before timing out.
+ */
+ static Duration getResolvingActionTimeout() {
+ return getDuration(
+ PROPERTY_RESOLVING_ACTION_TIMEOUT_MILLIS,
+ RESOLVING_ACTION_TIMEOUT_DEFAULT_DURATION);
+ }
+
+ /**
+ * Returns the time for which an app, upon receiving a Safety Center refresh broadcast, will be
+ * placed on a temporary power allowlist allowing it to start a foreground service from the
+ * background.
+ */
+ static Duration getFgsAllowlistDuration() {
+ return getDuration(PROPERTY_FGS_ALLOWLIST_DURATION_MILLIS, FGS_ALLOWLIST_DEFAULT_DURATION);
+ }
+
+ /**
+ * Returns the IDs of sources that should not be tracked, for example because they are
+ * mid-rollout. Broadcasts are still sent to these sources.
+ */
+ static ArraySet<String> getUntrackedSourceIds() {
+ return getCommaSeparatedStrings(PROPERTY_UNTRACKED_SOURCES, sUntrackedSourcesDefault);
+ }
+
+ /**
+ * Returns the 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.
+ */
+ static ArraySet<String> getBackgroundRefreshDeniedSourceIds() {
+ return getCommaSeparatedStrings(
+ PROPERTY_BACKGROUND_REFRESH_DENIED_SOURCES, sBackgroundRefreshDenyDefault);
+ }
+
+ /**
+ * Returns the time for which a Safety Center refresh is allowed to wait for a source to respond
+ * to a refresh request before timing out and marking the refresh as completed, based on the
+ * reason for the refresh.
+ */
+ static Duration getRefreshSourcesTimeout(@RefreshReason int refreshReason) {
+ String refreshSourcesTimeouts = getRefreshSourcesTimeoutsMillis();
+ Long timeout = getLongValueFromStringMapping(refreshSourcesTimeouts, refreshReason);
+ if (timeout != null) {
+ return Duration.ofMillis(timeout);
+ }
+ return REFRESH_SOURCES_TIMEOUT_DEFAULT_DURATION;
+ }
+
+ /**
+ * Returns a comma-delimited list of colon-delimited pairs where the left value is a {@link
+ * RefreshReason} and the right value is the refresh timeout applied for each source in case of
+ * a refresh.
+ */
+ private static String getRefreshSourcesTimeoutsMillis() {
+ return getString(PROPERTY_REFRESH_SOURCES_TIMEOUTS_MILLIS, REFRESH_SOURCES_TIMEOUT_DEFAULT);
+ }
+
+ /**
+ * Returns the number of times an issue of the given {@link SafetySourceData.SeverityLevel}
+ * should be resurfaced.
+ */
+ public static long getResurfaceIssueMaxCount(
+ @SafetySourceData.SeverityLevel int severityLevel) {
+ String maxCountsConfigString = getResurfaceIssueMaxCounts();
+ Long maxCount = getLongValueFromStringMapping(maxCountsConfigString, severityLevel);
+ if (maxCount != null) {
+ return maxCount;
+ }
+ return RESURFACE_ISSUE_MAX_COUNT_DEFAULT_COUNT;
+ }
+
+ /**
+ * Returns a comma-delimited list of colon-delimited pairs where the left value is an issue
+ * {@link SafetySourceData.SeverityLevel} and the right value is the number of times an issue of
+ * this {@link SafetySourceData.SeverityLevel} should be resurfaced.
+ */
+ private static String getResurfaceIssueMaxCounts() {
+ return getString(PROPERTY_RESURFACE_ISSUE_MAX_COUNTS, RESURFACE_ISSUE_MAX_COUNT_DEFAULT);
+ }
+
+ /**
+ * Returns the time after which a dismissed issue of the given {@link
+ * SafetySourceData.SeverityLevel} will resurface if it has not reached the maximum count for
+ * which a dismissed issue of the given {@link SafetySourceData.SeverityLevel} should be
+ * resurfaced.
+ */
+ public static Duration getResurfaceIssueDelay(
+ @SafetySourceData.SeverityLevel int severityLevel) {
+ String delaysConfigString = getResurfaceIssueDelaysMillis();
+ Long delayMillis = getLongValueFromStringMapping(delaysConfigString, severityLevel);
+ if (delayMillis != null) {
+ return Duration.ofMillis(delayMillis);
+ }
+ return RESURFACE_ISSUE_DELAYS_DEFAULT_DURATION;
+ }
+
+ /**
+ * Returns a comma-delimited list of colon-delimited pairs where the left value is an issue
+ * {@link SafetySourceData.SeverityLevel} and the right value is the time after which a
+ * dismissed issue of this safety source severity level will resurface if it has not reached the
+ * maximum count for which a dismissed issue of this {@link SafetySourceData.SeverityLevel}
+ * should be resurfaced.
+ */
+ private static String getResurfaceIssueDelaysMillis() {
+ return getString(PROPERTY_RESURFACE_ISSUE_DELAYS_MILLIS, RESURFACE_ISSUE_DELAYS_DEFAULT);
+ }
+
+ /** Returns a duration after which a temporarily hidden issue will resurface. */
+ public static Duration getTemporarilyHiddenIssueResurfaceDelay() {
+ return getDuration(
+ PROPERTY_TEMP_HIDDEN_ISSUE_RESURFACE_DELAY_MILLIS,
+ TEMP_HIDDEN_ISSUE_RESURFACE_DELAY_DEFAULT_DURATION);
+ }
+
+ /**
+ * Returns whether a safety source is allowed to send issues for the given {@link
+ * SafetySourceIssue.IssueCategory}.
+ */
+ 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;
+ }
+
+ /** Returns a set of package certificates allowlisted for the given package name. */
+ public static ArraySet<String> getAdditionalAllowedPackageCerts(String packageName) {
+ String property = getAdditionalAllowedPackageCertsString();
+ String allowlistedCertString = getStringValueFromStringMapping(property, packageName);
+ if (allowlistedCertString == null) {
+ return new ArraySet<>();
+ }
+ return new ArraySet<String>(allowlistedCertString.split("\\|"));
+ }
+
+ /**
+ * Returns a comma-delimited list of colon-delimited pairs where the left value is an issue
+ * {@link SafetySourceIssue.IssueCategory} and the right value is a vertical-bar-delimited list
+ * of IDs of safety sources that are allowed to send issues with this category.
+ */
+ private static String getIssueCategoryAllowlists() {
+ return getString(PROPERTY_ISSUE_CATEGORY_ALLOWLISTS, sIssueCategoryAllowlistDefault);
+ }
+
+ private static String getAdditionalAllowedPackageCertsString() {
+ return getString(PROPERTY_ADDITIONAL_ALLOW_PACKAGE_CERTS, "");
+ }
+
+ /** Returns whether we allow statsd logging. */
+ public static boolean getAllowStatsdLogging() {
+ return getBoolean(PROPERTY_ALLOW_STATSD_LOGGING, true);
+ }
+
+ /**
+ * Returns whether to show subpages in the Safety Center UI for Android-U instead of the
+ * expand-and-collapse list implementation.
+ */
+ static boolean getShowSubpages() {
+ return SdkLevel.isAtLeastU() && getBoolean(PROPERTY_SHOW_SUBPAGES, true);
+ }
+
+ /**
+ * Returns an array of safety source Ids that will be refreshed on page open, even if
+ * refreshOnPageOpenAllowed is false (the default) in the XML config.
+ */
+ static ArraySet<String> getOverrideRefreshOnPageOpenSourceIds() {
+ return getCommaSeparatedStrings(
+ PROPERTY_OVERRIDE_REFRESH_ON_PAGE_OPEN_SOURCES, sRefreshOnPageOpenSourcesDefault);
+ }
+
+ private static Duration getDuration(String property, Duration defaultValue) {
+ return Duration.ofMillis(getLong(property, defaultValue.toMillis()));
+ }
+
+ private static boolean getBoolean(String property, boolean defaultValue) {
+ // This call requires the READ_DEVICE_CONFIG permission.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, property, defaultValue);
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ private static long getLong(String property, long defaultValue) {
+ // This call requires the READ_DEVICE_CONFIG permission.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ return DeviceConfig.getLong(DeviceConfig.NAMESPACE_PRIVACY, property, defaultValue);
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ private static ArraySet<String> getCommaSeparatedStrings(String property) {
+ return getCommaSeparatedStrings(property, "");
+ }
+
+ private static ArraySet<String> getCommaSeparatedStrings(String property, String defaultValue) {
+ return new ArraySet<>(getString(property, defaultValue).split(","));
+ }
+
+ private static String getString(String property, String defaultValue) {
+ // This call requires the READ_DEVICE_CONFIG permission.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ return DeviceConfig.getString(DeviceConfig.NAMESPACE_PRIVACY, property, defaultValue);
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ /**
+ * Gets a long value for the provided integer key in a comma separated list of colon separated
+ * pairs of integers and longs.
+ */
+ @Nullable
+ private static Long getLongValueFromStringMapping(String config, int key) {
+ String valueString = getStringValueFromStringMapping(config, key);
+ if (valueString == null) {
+ return null;
+ }
+ try {
+ return Long.parseLong(valueString);
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Badly formatted string config: " + config, e);
+ return null;
+ }
+ }
+
+ /**
+ * Gets a value for the provided integer key in a comma separated list of colon separated pairs
+ * of integers and strings.
+ */
+ @Nullable
+ private static String getStringValueFromStringMapping(String config, int key) {
+ return getStringValueFromStringMapping(config, Integer.toString(key));
+ }
+
+ /**
+ * Gets a value for the provided key in a comma separated list of colon separated key-value
+ * string pairs.
+ */
+ @Nullable
+ private static String getStringValueFromStringMapping(String config, String key) {
+ if (config.isEmpty()) {
+ return null;
+ }
+ String[] pairsList = config.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);
+ continue;
+ }
+ if (pair[0].equals(key)) {
+ return pair[1];
+ }
+ }
+ return null;
+ }
+
+ private SafetyCenterFlags() {}
+}
diff --git a/service/java/com/android/safetycenter/SafetyCenterListeners.java b/service/java/com/android/safetycenter/SafetyCenterListeners.java
index 56c2d4c27..9e07c3d17 100644
--- a/service/java/com/android/safetycenter/SafetyCenterListeners.java
+++ b/service/java/com/android/safetycenter/SafetyCenterListeners.java
@@ -18,19 +18,25 @@ package com.android.safetycenter;
import static android.os.Build.VERSION_CODES.TIRAMISU;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.safetycenter.IOnSafetyCenterDataChangedListener;
import android.safetycenter.SafetyCenterData;
import android.safetycenter.SafetyCenterErrorDetails;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
import androidx.annotation.RequiresApi;
+import java.io.PrintWriter;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
/**
* A class that keeps track of all the registered {@link IOnSafetyCenterDataChangedListener}
* per-user.
@@ -38,23 +44,26 @@ import androidx.annotation.RequiresApi;
* <p>This class isn't thread safe. Thread safety must be handled by the caller.
*/
@RequiresApi(TIRAMISU)
+@NotThreadSafe
final class SafetyCenterListeners {
private static final String TAG = "SafetyCenterListeners";
+ private final SafetyCenterDataFactory mSafetyCenterDataFactory;
+
private final SparseArray<RemoteCallbackList<IOnSafetyCenterDataChangedListener>>
mSafetyCenterDataChangedListeners = new SparseArray<>();
- /** Creates a {@link SafetyCenterListeners}. */
- SafetyCenterListeners() {}
+ SafetyCenterListeners(SafetyCenterDataFactory safetyCenterDataFactory) {
+ mSafetyCenterDataFactory = safetyCenterDataFactory;
+ }
/**
* Delivers a {@link SafetyCenterData} update to a single {@link
* IOnSafetyCenterDataChangedListener}.
*/
- static void deliverUpdate(
- @NonNull IOnSafetyCenterDataChangedListener listener,
- @NonNull SafetyCenterData safetyCenterData) {
+ static void deliverDataForListener(
+ IOnSafetyCenterDataChangedListener listener, SafetyCenterData safetyCenterData) {
try {
listener.onSafetyCenterDataChanged(safetyCenterData);
} catch (RemoteException e) {
@@ -63,31 +72,12 @@ final class SafetyCenterListeners {
}
/**
- * Delivers a {@link SafetyCenterData} update to a {@link RemoteCallbackList} of {@link
- * IOnSafetyCenterDataChangedListener}.
- *
- * <p>Registering or unregistering {@link IOnSafetyCenterDataChangedListener} on the underlying
- * {@link RemoteCallbackList} on another thread while an update is happening is safe as this is
- * handled by the {@link RemoteCallbackList} already (as well as listeners death).
- */
- static void deliverUpdate(
- @NonNull RemoteCallbackList<IOnSafetyCenterDataChangedListener> listeners,
- @NonNull SafetyCenterData safetyCenterData) {
- int i = listeners.beginBroadcast();
- while (i > 0) {
- i--;
- deliverUpdate(listeners.getBroadcastItem(i), safetyCenterData);
- }
- listeners.finishBroadcast();
- }
-
- /**
* Delivers a {@link SafetyCenterErrorDetails} update to a single {@link
* IOnSafetyCenterDataChangedListener}.
*/
- private static void deliverError(
- @NonNull IOnSafetyCenterDataChangedListener listener,
- @NonNull SafetyCenterErrorDetails safetyCenterErrorDetails) {
+ private static void deliverErrorForListener(
+ IOnSafetyCenterDataChangedListener listener,
+ SafetyCenterErrorDetails safetyCenterErrorDetails) {
try {
listener.onError(safetyCenterErrorDetails);
} catch (RemoteException e) {
@@ -96,55 +86,230 @@ final class SafetyCenterListeners {
}
/**
- * Delivers a {@link SafetyCenterErrorDetails} update to a {@link RemoteCallbackList} of {@link
- * IOnSafetyCenterDataChangedListener}.
- *
- * <p>Registering or unregistering {@link IOnSafetyCenterDataChangedListener} on the underlying
- * {@link RemoteCallbackList} on another thread while an update is happening is safe as this is
- * handled by the {@link RemoteCallbackList} already (as well as listeners death).
+ * Delivers a {@link SafetyCenterData} update on all listeners of the given {@link
+ * UserProfileGroup}.
*/
- static void deliverError(
- @NonNull RemoteCallbackList<IOnSafetyCenterDataChangedListener> listeners,
- @NonNull SafetyCenterErrorDetails safetyCenterErrorDetails) {
- int i = listeners.beginBroadcast();
- while (i > 0) {
- i--;
- deliverError(listeners.getBroadcastItem(i), safetyCenterErrorDetails);
- }
- listeners.finishBroadcast();
+ void deliverDataForUserProfileGroup(UserProfileGroup userProfileGroup) {
+ ArrayMap<String, SafetyCenterData> safetyCenterDataCache = new ArrayMap<>();
+ int[] relevantUserIds = userProfileGroup.getProfileParentAndManagedRunningProfilesUserIds();
+ for (int i = 0; i < relevantUserIds.length; i++) {
+ deliverUpdateForUser(
+ relevantUserIds[i], userProfileGroup, safetyCenterDataCache, true, null);
+ }
}
- /** Adds a {@link IOnSafetyCenterDataChangedListener} for the given {@code userId}. */
- void addListener(@NonNull IOnSafetyCenterDataChangedListener listener, @UserIdInt int userId) {
+ /**
+ * Delivers a given {@link SafetyCenterErrorDetails} in an update on all listeners of the given
+ * {@link UserProfileGroup}.
+ */
+ void deliverErrorForUserProfileGroup(
+ UserProfileGroup userProfileGroup, SafetyCenterErrorDetails safetyCenterErrorDetails) {
+ ArrayMap<String, SafetyCenterData> safetyCenterDataCache = new ArrayMap<>();
+ int[] relevantUserIds = userProfileGroup.getProfileParentAndManagedRunningProfilesUserIds();
+ for (int i = 0; i < relevantUserIds.length; i++) {
+ deliverUpdateForUser(
+ relevantUserIds[i],
+ userProfileGroup,
+ safetyCenterDataCache,
+ false,
+ safetyCenterErrorDetails);
+ }
+ }
+
+ /**
+ * Adds a {@link IOnSafetyCenterDataChangedListener} for the given {@code packageName} and
+ * {@code userId}.
+ *
+ * <p>Returns the registered {@link IOnSafetyCenterDataChangedListener} if this operation was
+ * successful. Otherwise, returns {@code null}.
+ */
+ @Nullable
+ IOnSafetyCenterDataChangedListener addListener(
+ IOnSafetyCenterDataChangedListener listener,
+ String packageName,
+ @UserIdInt int userId) {
RemoteCallbackList<IOnSafetyCenterDataChangedListener> listeners =
mSafetyCenterDataChangedListeners.get(userId);
if (listeners == null) {
listeners = new RemoteCallbackList<>();
- mSafetyCenterDataChangedListeners.put(userId, listeners);
}
- listeners.register(listener);
+ OnSafetyCenterDataChangedListenerWrapper listenerWrapper =
+ new OnSafetyCenterDataChangedListenerWrapper(listener, packageName);
+ boolean registered = listeners.register(listenerWrapper);
+ if (!registered) {
+ return null;
+ }
+ mSafetyCenterDataChangedListeners.put(userId, listeners);
+ return listenerWrapper;
}
- /** Removes a {@link IOnSafetyCenterDataChangedListener} for the given {@code userId}. */
- void removeListener(
- @NonNull IOnSafetyCenterDataChangedListener listener, @UserIdInt int userId) {
+ /**
+ * Removes a {@link IOnSafetyCenterDataChangedListener} for the given {@code userId}.
+ *
+ * <p>Returns whether the callback was unregistered. Returns {@code false} if the callback was
+ * never registered.
+ */
+ boolean removeListener(IOnSafetyCenterDataChangedListener listener, @UserIdInt int userId) {
RemoteCallbackList<IOnSafetyCenterDataChangedListener> listeners =
mSafetyCenterDataChangedListeners.get(userId);
if (listeners == null) {
- return;
+ return false;
}
- listeners.unregister(listener);
+ boolean unregistered = listeners.unregister(listener);
if (listeners.getRegisteredCallbackCount() == 0) {
- mSafetyCenterDataChangedListeners.put(userId, null);
+ mSafetyCenterDataChangedListeners.remove(userId);
+ }
+ return unregistered;
+ }
+
+ /** Clears all {@link IOnSafetyCenterDataChangedListener}s, for the given user. */
+ void clearForUser(@UserIdInt int userId) {
+ RemoteCallbackList<IOnSafetyCenterDataChangedListener> listeners =
+ mSafetyCenterDataChangedListeners.get(userId);
+ if (listeners == null) {
+ return;
}
+ listeners.kill();
+ mSafetyCenterDataChangedListeners.remove(userId);
+ }
+
+ /** Clears all {@link IOnSafetyCenterDataChangedListener}s, for all user ids. */
+ void clear() {
+ for (int i = 0; i < mSafetyCenterDataChangedListeners.size(); i++) {
+ RemoteCallbackList<IOnSafetyCenterDataChangedListener> listeners =
+ mSafetyCenterDataChangedListeners.valueAt(i);
+ if (listeners == null) {
+ continue;
+ }
+ listeners.kill();
+ }
+ mSafetyCenterDataChangedListeners.clear();
+ }
+
+ private void deliverUpdateForUser(
+ @UserIdInt int userId,
+ UserProfileGroup userProfileGroup,
+ ArrayMap<String, SafetyCenterData> safetyCenterDataCache,
+ boolean updateSafetyCenterData,
+ @Nullable SafetyCenterErrorDetails safetyCenterErrorDetails) {
+ RemoteCallbackList<IOnSafetyCenterDataChangedListener> listenersForUserId =
+ mSafetyCenterDataChangedListeners.get(userId);
+ if (listenersForUserId == null) {
+ return;
+ }
+ int i = listenersForUserId.beginBroadcast();
+ try {
+ while (i > 0) {
+ i--;
+ OnSafetyCenterDataChangedListenerWrapper listenerWrapper =
+ (OnSafetyCenterDataChangedListenerWrapper)
+ listenersForUserId.getBroadcastItem(i);
+ if (updateSafetyCenterData) {
+ SafetyCenterData safetyCenterData =
+ assembleSafetyCenterDataIfAbsent(
+ safetyCenterDataCache,
+ listenerWrapper.getPackageName(),
+ userProfileGroup);
+
+ deliverDataForListener(listenerWrapper, safetyCenterData);
+ }
+ if (safetyCenterErrorDetails != null) {
+ deliverErrorForListener(listenerWrapper, safetyCenterErrorDetails);
+ }
+ }
+ } finally {
+ listenersForUserId.finishBroadcast();
+ }
+ }
+
+ private SafetyCenterData assembleSafetyCenterDataIfAbsent(
+ ArrayMap<String, SafetyCenterData> safetyCenterDataCache,
+ String packageName,
+ UserProfileGroup userProfileGroup) {
+ SafetyCenterData cachedSafetyCenterData = safetyCenterDataCache.get(packageName);
+ if (cachedSafetyCenterData != null) {
+ return cachedSafetyCenterData;
+ }
+ SafetyCenterData safetyCenterData =
+ mSafetyCenterDataFactory.assembleSafetyCenterData(packageName, userProfileGroup);
+ safetyCenterDataCache.put(packageName, safetyCenterData);
+ return safetyCenterData;
+ }
+
+ /** Dumps state for debugging purposes. */
+ void dump(PrintWriter fout) {
+ int userIdCount = mSafetyCenterDataChangedListeners.size();
+ fout.println("DATA CHANGED LISTENERS (" + userIdCount + " user IDs)");
+ for (int i = 0; i < userIdCount; i++) {
+ int userId = mSafetyCenterDataChangedListeners.keyAt(i);
+ RemoteCallbackList<IOnSafetyCenterDataChangedListener> listeners =
+ mSafetyCenterDataChangedListeners.valueAt(i);
+ if (listeners == null) {
+ continue;
+ }
+ int listenerCount = listeners.getRegisteredCallbackCount();
+ fout.println("\t[" + i + "] user " + userId + " (" + listenerCount + " listeners)");
+ for (int j = 0; j < listenerCount; j++) {
+ fout.println("\t\t[" + j + "] " + listeners.getRegisteredCallbackItem(j));
+ }
+ }
+ fout.println();
}
/**
- * Returns the {@link RemoteCallbackList} of {@link IOnSafetyCenterDataChangedListener} for the
- * given {@code userId}.
+ * A wrapper around an {@link IOnSafetyCenterDataChangedListener} to ensure it is only called
+ * when the {@link SafetyCenterData} actually changes.
*/
- @Nullable
- RemoteCallbackList<IOnSafetyCenterDataChangedListener> getListeners(@UserIdInt int userId) {
- return mSafetyCenterDataChangedListeners.get(userId);
+ private static final class OnSafetyCenterDataChangedListenerWrapper
+ implements IOnSafetyCenterDataChangedListener {
+
+ private final IOnSafetyCenterDataChangedListener mDelegate;
+ private final String mPackageName;
+
+ private final AtomicReference<SafetyCenterData> mLastSafetyCenterData =
+ new AtomicReference<>();
+
+ OnSafetyCenterDataChangedListenerWrapper(
+ IOnSafetyCenterDataChangedListener delegate, String packageName) {
+ mDelegate = delegate;
+ mPackageName = packageName;
+ }
+
+ @Override
+ public void onSafetyCenterDataChanged(SafetyCenterData safetyCenterData)
+ throws RemoteException {
+ if (safetyCenterData.equals(mLastSafetyCenterData.getAndSet(safetyCenterData))) {
+ return;
+ }
+ mDelegate.onSafetyCenterDataChanged(safetyCenterData);
+ }
+
+ @Override
+ public void onError(SafetyCenterErrorDetails safetyCenterErrorDetails)
+ throws RemoteException {
+ mDelegate.onError(safetyCenterErrorDetails);
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return mDelegate.asBinder();
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ @Override
+ public String toString() {
+ return "OnSafetyCenterDataChangedListenerWrapper{"
+ + "mDelegate="
+ + mDelegate
+ + ", mPackageName='"
+ + mPackageName
+ + '\''
+ + ", mLastSafetyCenterData="
+ + mLastSafetyCenterData
+ + '}';
+ }
}
}
diff --git a/service/java/com/android/safetycenter/SafetyCenterRefreshManager.java b/service/java/com/android/safetycenter/SafetyCenterRefreshManager.java
deleted file mode 100644
index b4374bd8d..000000000
--- a/service/java/com/android/safetycenter/SafetyCenterRefreshManager.java
+++ /dev/null
@@ -1,184 +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;
-
-import static android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE;
-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;
-import static android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA;
-import static android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_GET_DATA;
-import static android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE;
-import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_PAGE_OPEN;
-import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_RESCAN_BUTTON_CLICK;
-import static android.safetycenter.config.SafetySource.SAFETY_SOURCE_TYPE_STATIC;
-
-import android.annotation.NonNull;
-import android.app.BroadcastOptions;
-import android.content.Context;
-import android.content.Intent;
-import android.os.UserHandle;
-import android.safetycenter.SafetyCenterManager.RefreshReason;
-import android.safetycenter.config.SafetyCenterConfig;
-import android.safetycenter.config.SafetySource;
-import android.util.Log;
-
-import androidx.annotation.RequiresApi;
-
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * Class to manage and track refresh broadcasts sent by {@link SafetyCenterService}.
- *
- * <p>This class isn't thread safe. Thread safety must be handled by the caller.
- */
-@RequiresApi(TIRAMISU)
-final class SafetyCenterRefreshManager {
-
- private static final String TAG = "SafetyCenterRefreshMana";
-
- /**
- * Time for which an app, upon receiving a particular broadcast, will be placed on a temporary
- * power allowlist allowing it to start a foreground service from the background.
- */
- // TODO(b/219553295): Use a Device Config value instead, so that this duration can be
- // easily adjusted.
- private static final Duration ALLOWLIST_DURATION = Duration.ofSeconds(20);
-
- @NonNull private final List<String> mAdditionalSafetySourcePackageNames = new ArrayList<>();
- @NonNull private final Context mContext;
- @NonNull private final SafetyCenterConfigReader mSafetyCenterConfigReader;
-
- /**
- * Creates a {@link SafetyCenterRefreshManager} using the given {@link Context} and {@link
- * SafetyCenterConfigReader}.
- */
- SafetyCenterRefreshManager(
- @NonNull Context context, @NonNull SafetyCenterConfigReader safetyCenterConfigReader) {
- mContext = context;
- mSafetyCenterConfigReader = safetyCenterConfigReader;
- }
-
- /** Adds a package name representing a source to refresh. */
- // TODO(b/218157907): Remove this method and use a SafetyCenterConfigReader field in
- // SafetyCenterRefreshManager instead once ag/16834483 is submitted.
- void addAdditionalSafetySourcePackageNames(@NonNull String packageName) {
- mAdditionalSafetySourcePackageNames.add(packageName);
- }
-
- /** Removes all additional package names representing sources to refresh. */
- // TODO(b/218157907): Remove this method and use a SafetyCenterConfigReader field in
- // SafetyCenterRefreshManager instead once ag/16834483 is submitted.
- void clearAdditionalSafetySourcePackageNames() {
- mAdditionalSafetySourcePackageNames.clear();
- }
-
- /**
- * Triggers a refresh of safety sources by sending them broadcasts with action {@link
- * android.safetycenter.SafetyCenterManager#ACTION_REFRESH_SAFETY_SOURCES}.
- */
- void refreshSafetySources(@RefreshReason int refreshReason) {
- int requestType;
- switch (refreshReason) {
- case REFRESH_REASON_RESCAN_BUTTON_CLICK:
- requestType = EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA;
- break;
- case REFRESH_REASON_PAGE_OPEN:
- requestType = EXTRA_REFRESH_REQUEST_TYPE_GET_DATA;
- break;
- default:
- throw new IllegalArgumentException("Invalid refresh reason: " + refreshReason);
- }
-
- SafetyCenterConfig safetyCenterConfig = mSafetyCenterConfigReader.getSafetyCenterConfig();
- if (safetyCenterConfig == null) {
- Log.w(TAG, "SafetyCenterConfig unavailable, ignoring refresh");
- return;
- }
-
- // TODO(b/219702252): Use a more efficient data structure for this.
- List<SafetySource> safetySourcesToRefresh =
- safetyCenterConfig.getSafetySourcesGroups().stream()
- .flatMap(group -> group.getSafetySources().stream())
- .filter(
- // Only send broadcasts to dynamic safety sources.
- source -> source.getType() != SAFETY_SOURCE_TYPE_STATIC)
- .collect(Collectors.toList());
-
- sendRefreshBroadcastToSafetySources(safetySourcesToRefresh, requestType);
- sendRefreshBroadcastToAdditionalSafetySourceReceivers(requestType);
- }
-
- private void sendRefreshBroadcastToSafetySources(
- List<SafetySource> safetySources, int requestType) {
- Intent broadcastIntent =
- new Intent(ACTION_REFRESH_SAFETY_SOURCES)
- .putExtra(EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE, requestType)
- .setFlags(FLAG_RECEIVER_FOREGROUND);
- BroadcastOptions broadcastOptions = BroadcastOptions.makeBasic();
- // The following operation requires START_FOREGROUND_SERVICES_FROM_BACKGROUND
- // permission.
- broadcastOptions.setTemporaryAppAllowlist(
- ALLOWLIST_DURATION.toMillis(),
- TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
- REASON_REFRESH_SAFETY_SOURCES,
- "Safety Center is requesting data from safety sources");
-
- for (SafetySource source : safetySources) {
- Intent broadcastIntentForSource =
- new Intent(broadcastIntent).setPackage(source.getPackageName());
- // TODO(b/215144069): Add cross profile support for safety sources which support
- // both personal and work profile. This implementation invokes
- // `sendBroadcastAsUser` in order to invoke the permission.
- // The following operation requires INTERACT_ACROSS_USERS permission.
- mContext.sendBroadcastAsUser(
- broadcastIntentForSource,
- UserHandle.CURRENT,
- SEND_SAFETY_CENTER_UPDATE,
- broadcastOptions.toBundle());
- }
- }
-
- private void sendRefreshBroadcastToAdditionalSafetySourceReceivers(int requestType) {
- Intent broadcastIntent =
- new Intent(ACTION_REFRESH_SAFETY_SOURCES)
- .putExtra(EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE, requestType)
- .setFlags(FLAG_RECEIVER_FOREGROUND);
- BroadcastOptions broadcastOptions = BroadcastOptions.makeBasic();
- // The following operation requires START_FOREGROUND_SERVICES_FROM_BACKGROUND
- // permission.
- broadcastOptions.setTemporaryAppAllowlist(
- ALLOWLIST_DURATION.toMillis(),
- TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
- REASON_REFRESH_SAFETY_SOURCES,
- "Safety Center is requesting data from safety sources");
-
- for (String packageName : mAdditionalSafetySourcePackageNames) {
- // The following operation requires INTERACT_ACROSS_USERS permission.
- mContext.sendBroadcastAsUser(
- new Intent(broadcastIntent).setPackage(packageName),
- UserHandle.CURRENT,
- SEND_SAFETY_CENTER_UPDATE,
- broadcastOptions.toBundle());
- }
- }
-}
diff --git a/service/java/com/android/safetycenter/SafetyCenterRefreshTracker.java b/service/java/com/android/safetycenter/SafetyCenterRefreshTracker.java
new file mode 100644
index 000000000..a28ce7d22
--- /dev/null
+++ b/service/java/com/android/safetycenter/SafetyCenterRefreshTracker.java
@@ -0,0 +1,536 @@
+/*
+ * 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;
+
+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;
+import android.safetycenter.SafetyCenterManager.RefreshReason;
+import android.safetycenter.SafetyCenterStatus;
+import android.safetycenter.SafetyCenterStatus.RefreshStatus;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.permission.util.UserUtils;
+import com.android.safetycenter.logging.SafetyCenterStatsdLogger;
+
+import java.io.PrintWriter;
+import java.time.Duration;
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
+/**
+ * A class to store the state of a refresh of safety sources, if any is ongoing.
+ *
+ * <p>This class isn't thread safe. Thread safety must be handled by the caller.
+ *
+ * @hide
+ */
+@RequiresApi(TIRAMISU)
+@NotThreadSafe
+public final class SafetyCenterRefreshTracker {
+ private static final String TAG = "SafetyCenterRefreshTrac";
+
+ private final Context mContext;
+
+ @Nullable
+ // TODO(b/229060064): Should we allow one refresh at a time per UserProfileGroup rather than
+ // one global refresh?
+ private RefreshInProgress mRefreshInProgress = null;
+
+ private int mRefreshCounter = 0;
+
+ SafetyCenterRefreshTracker(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Reports that a new refresh is in progress and returns the broadcast id associated with this
+ * refresh.
+ */
+ String reportRefreshInProgress(
+ @RefreshReason int refreshReason, UserProfileGroup userProfileGroup) {
+ if (mRefreshInProgress != null) {
+ Log.w(TAG, "Replacing an ongoing refresh");
+ }
+
+ String refreshBroadcastId = UUID.randomUUID() + "_" + mRefreshCounter++;
+ Log.v(
+ TAG,
+ "Starting a new refresh with refreshReason:"
+ + refreshReason
+ + " refreshBroadcastId:"
+ + refreshBroadcastId);
+
+ mRefreshInProgress =
+ new RefreshInProgress(
+ refreshBroadcastId,
+ refreshReason,
+ userProfileGroup,
+ SafetyCenterFlags.getUntrackedSourceIds());
+
+ return refreshBroadcastId;
+ }
+
+ /** Returns the current refresh status. */
+ @RefreshStatus
+ int getRefreshStatus() {
+ if (mRefreshInProgress == null || mRefreshInProgress.isComplete()) {
+ return SafetyCenterStatus.REFRESH_STATUS_NONE;
+ }
+
+ if (mRefreshInProgress.getReason() == REFRESH_REASON_RESCAN_BUTTON_CLICK) {
+ return SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS;
+ }
+ return SafetyCenterStatus.REFRESH_STATUS_DATA_FETCH_IN_PROGRESS;
+ }
+
+ /**
+ * Returns the {@link RefreshReason} for the current refresh, or {@code null} if none is in
+ * progress.
+ */
+ @RefreshReason
+ @Nullable
+ public Integer getRefreshReason() {
+ if (mRefreshInProgress != null) {
+ return mRefreshInProgress.getReason();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Reports that refresh requests have been sent to a collection of sources.
+ *
+ * <p>When those sources respond call {@link #reportSourceRefreshCompleted} to mark the request
+ * as complete.
+ */
+ void reportSourceRefreshesInFlight(
+ String refreshBroadcastId, List<String> sourceIds, @UserIdInt int userId) {
+ RefreshInProgress refreshInProgress =
+ getRefreshInProgressWithId("reportSourceRefreshesInFlight", refreshBroadcastId);
+ if (refreshInProgress == null) {
+ return;
+ }
+ for (int i = 0; i < sourceIds.size(); i++) {
+ SafetySourceKey key = SafetySourceKey.of(sourceIds.get(i), userId);
+ refreshInProgress.markSourceRefreshInFlight(key);
+ }
+ }
+
+ /**
+ * Reports that a source has completed its refresh, and returns {@code true} if the whole
+ * current refresh is now complete.
+ *
+ * <p>If a source calls {@code reportSafetySourceError}, then this method is also used to mark
+ * the refresh as completed. The {@code successful} parameter indicates whether the refresh
+ * completed successfully or not. The {@code dataChanged} parameter indicates whether this
+ * source's data changed or not.
+ *
+ * <p>Completed refreshes are logged to statsd.
+ */
+ public boolean reportSourceRefreshCompleted(
+ String refreshBroadcastId,
+ String sourceId,
+ @UserIdInt int userId,
+ boolean successful,
+ boolean dataChanged) {
+ RefreshInProgress refreshInProgress =
+ getRefreshInProgressWithId("reportSourceRefreshCompleted", refreshBroadcastId);
+ if (refreshInProgress == null) {
+ return false;
+ }
+
+ SafetySourceKey sourceKey = SafetySourceKey.of(sourceId, userId);
+ Duration duration =
+ refreshInProgress.markSourceRefreshComplete(sourceKey, successful, dataChanged);
+ int refreshReason = refreshInProgress.getReason();
+ int requestType = RefreshReasons.toRefreshRequestType(refreshReason);
+
+ if (duration != null) {
+ int sourceResult = toSystemEventResult(successful);
+ SafetyCenterStatsdLogger.writeSourceRefreshSystemEvent(
+ requestType,
+ sourceId,
+ UserUtils.isManagedProfile(userId, mContext),
+ duration,
+ sourceResult,
+ refreshReason,
+ dataChanged);
+ }
+
+ if (!refreshInProgress.isComplete()) {
+ return false;
+ }
+
+ Log.v(TAG, "Refresh with id: " + refreshInProgress.getId() + " completed");
+ int wholeResult =
+ toSystemEventResult(/* success= */ !refreshInProgress.hasAnyTrackedSourceErrors());
+ SafetyCenterStatsdLogger.writeWholeRefreshSystemEvent(
+ requestType,
+ refreshInProgress.getDurationSinceStart(),
+ wholeResult,
+ refreshReason,
+ refreshInProgress.hasAnyTrackedSourceDataChanged());
+ mRefreshInProgress = null;
+ return true;
+ }
+
+ /**
+ * Clears any ongoing refresh in progress, if any.
+ *
+ * <p>Note that this method simply clears the tracking of a refresh, and does not prevent
+ * scheduled broadcasts being sent by {@link
+ * android.safetycenter.SafetyCenterManager#refreshSafetySources}.
+ */
+ void clearRefresh() {
+ clearRefreshInternal();
+ }
+
+ /**
+ * Clears the refresh in progress, if there is any with the given id.
+ *
+ * <p>Note that this method simply clears the tracking of a refresh, and does not prevent
+ * scheduled broadcasts being sent by {@link
+ * android.safetycenter.SafetyCenterManager#refreshSafetySources}.
+ */
+ void clearRefresh(String refreshBroadcastId) {
+ if (!checkRefreshInProgress("clearRefresh", refreshBroadcastId)) {
+ return;
+ }
+ clearRefreshInternal();
+ }
+
+ /**
+ * Clears any ongoing refresh in progress for the given user.
+ *
+ * <p>Note that this method simply clears the tracking of a refresh, and does not prevent
+ * scheduled broadcasts being sent by {@link
+ * android.safetycenter.SafetyCenterManager#refreshSafetySources}.
+ */
+ void clearRefreshForUser(@UserIdInt int userId) {
+ if (mRefreshInProgress == null) {
+ Log.v(TAG, "Clear refresh for user called but no refresh in progress");
+ return;
+ }
+ if (mRefreshInProgress.clearForUser(userId)) {
+ clearRefreshInternal();
+ }
+ }
+
+ /**
+ * Clears the refresh in progress with the given id, and returns the {@link SafetySourceKey}s
+ * that were still in-flight prior to doing that, if any.
+ *
+ * <p>Returns {@code null} if there was no refresh in progress with the given {@code
+ * refreshBroadcastId}, or if it was already complete.
+ *
+ * <p>Note that this method simply clears the tracking of a refresh, and does not prevent
+ * scheduled broadcasts being sent by {@link
+ * android.safetycenter.SafetyCenterManager#refreshSafetySources}.
+ */
+ @Nullable
+ ArraySet<SafetySourceKey> timeoutRefresh(String refreshBroadcastId) {
+ if (!checkRefreshInProgress("timeoutRefresh", refreshBroadcastId)) {
+ return null;
+ }
+
+ RefreshInProgress clearedRefresh = clearRefreshInternal();
+
+ if (clearedRefresh == null || clearedRefresh.isComplete()) {
+ return null;
+ }
+
+ ArraySet<SafetySourceKey> timedOutSources = clearedRefresh.getSourceRefreshesInFlight();
+ int refreshReason = clearedRefresh.getReason();
+ int requestType = RefreshReasons.toRefreshRequestType(refreshReason);
+
+ for (int i = 0; i < timedOutSources.size(); i++) {
+ SafetySourceKey sourceKey = timedOutSources.valueAt(i);
+ Duration duration = clearedRefresh.getDurationSinceSourceStart(sourceKey);
+ if (duration != null) {
+ SafetyCenterStatsdLogger.writeSourceRefreshSystemEvent(
+ requestType,
+ sourceKey.getSourceId(),
+ UserUtils.isManagedProfile(sourceKey.getUserId(), mContext),
+ duration,
+ SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__TIMEOUT,
+ refreshReason,
+ false);
+ }
+ }
+
+ SafetyCenterStatsdLogger.writeWholeRefreshSystemEvent(
+ requestType,
+ clearedRefresh.getDurationSinceStart(),
+ SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__TIMEOUT,
+ refreshReason,
+ clearedRefresh.hasAnyTrackedSourceDataChanged());
+
+ return timedOutSources;
+ }
+
+ /**
+ * Clears the any 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.
+ */
+ @Nullable
+ private RefreshInProgress clearRefreshInternal() {
+ RefreshInProgress refreshToClear = mRefreshInProgress;
+ if (refreshToClear == null) {
+ Log.v(TAG, "Clear refresh called but no refresh in progress");
+ return null;
+ }
+
+ Log.v(TAG, "Clearing refresh with refreshBroadcastId:" + refreshToClear.getId());
+ mRefreshInProgress = null;
+ return refreshToClear;
+ }
+
+ /**
+ * Returns the current {@link RefreshInProgress} if it has the given ID, or logs and returns
+ * {@code null} if not.
+ */
+ @Nullable
+ private RefreshInProgress getRefreshInProgressWithId(
+ 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");
+ return null;
+ }
+ return refreshInProgress;
+ }
+
+ private boolean checkRefreshInProgress(String methodName, String refreshBroadcastId) {
+ return getRefreshInProgressWithId(methodName, refreshBroadcastId) != null;
+ }
+
+ /** Dumps state for debugging purposes. */
+ void dump(PrintWriter fout) {
+ fout.println(
+ "REFRESH IN PROGRESS ("
+ + (mRefreshInProgress != null)
+ + ", counter="
+ + mRefreshCounter
+ + ")");
+ if (mRefreshInProgress != null) {
+ fout.println("\t" + mRefreshInProgress);
+ }
+ fout.println();
+ }
+
+ /** Class representing the state of a refresh in progress. */
+ private static final class RefreshInProgress {
+
+ private final String mId;
+ @RefreshReason private final int mReason;
+ private final UserProfileGroup mUserProfileGroup;
+ private final ArraySet<String> mUntrackedSourcesIds;
+ @ElapsedRealtimeLong private final long mStartElapsedMillis;
+
+ // The values in this map are the start times of each source refresh. The alternative of
+ // using mStartTime as the start time of all source refreshes was considered, but this
+ // approach is less sensitive to delays/implementation changes in broadcast dispatch.
+ private final ArrayMap<SafetySourceKey, Long> mSourceRefreshesInFlight = new ArrayMap<>();
+
+ private boolean mAnyTrackedSourceErrors = false;
+ private boolean mAnyTrackedSourceDataChanged = false;
+
+ RefreshInProgress(
+ String id,
+ @RefreshReason int reason,
+ UserProfileGroup userProfileGroup,
+ ArraySet<String> untrackedSourceIds) {
+ mId = id;
+ mReason = reason;
+ mUserProfileGroup = userProfileGroup;
+ mUntrackedSourcesIds = untrackedSourceIds;
+ mStartElapsedMillis = SystemClock.elapsedRealtime();
+ }
+
+ /**
+ * Returns the id of the {@link RefreshInProgress}, which corresponds to the {@link
+ * android.safetycenter.SafetyCenterManager#EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID} used
+ * in the refresh.
+ */
+ private String getId() {
+ return mId;
+ }
+
+ /** Returns the {@link RefreshReason} that was given for this {@link RefreshInProgress}. */
+ @RefreshReason
+ private int getReason() {
+ return mReason;
+ }
+
+ /** Returns the {@link Duration} since this refresh started. */
+ private Duration getDurationSinceStart() {
+ return Duration.ofMillis(SystemClock.elapsedRealtime() - mStartElapsedMillis);
+ }
+
+ @Nullable
+ private Duration getDurationSinceSourceStart(SafetySourceKey safetySourceKey) {
+ Long startElapsedMillis = mSourceRefreshesInFlight.get(safetySourceKey);
+ if (startElapsedMillis == null) {
+ return null;
+ }
+ return Duration.ofMillis(SystemClock.elapsedRealtime() - startElapsedMillis);
+ }
+
+ /** Returns the {@link SafetySourceKey} of all in-flight source refreshes. */
+ private ArraySet<SafetySourceKey> getSourceRefreshesInFlight() {
+ return new ArraySet<>(mSourceRefreshesInFlight.keySet());
+ }
+
+ /** Returns {@code true} if any refresh of a tracked source completed with an error. */
+ private boolean hasAnyTrackedSourceErrors() {
+ return mAnyTrackedSourceErrors;
+ }
+
+ /** Returns {@code true} if any refresh of a tracked source changed that source's data. */
+ private boolean hasAnyTrackedSourceDataChanged() {
+ return mAnyTrackedSourceDataChanged;
+ }
+
+ private void markSourceRefreshInFlight(SafetySourceKey safetySourceKey) {
+ boolean tracked = isTracked(safetySourceKey);
+ long currentElapsedMillis = SystemClock.elapsedRealtime();
+ if (tracked) {
+ mSourceRefreshesInFlight.put(safetySourceKey, currentElapsedMillis);
+ }
+ Log.v(
+ TAG,
+ "Refresh started for sourceId:"
+ + safetySourceKey.getSourceId()
+ + " userId:"
+ + safetySourceKey.getUserId()
+ + " with refreshBroadcastId:"
+ + mId
+ + " at currentElapsedMillis:"
+ + currentElapsedMillis
+ + " & tracking:"
+ + tracked
+ + ", now "
+ + mSourceRefreshesInFlight.size()
+ + " tracked sources in flight.");
+ }
+
+ @Nullable
+ private Duration markSourceRefreshComplete(
+ SafetySourceKey safetySourceKey, boolean successful, boolean dataChanged) {
+ Long startElapsedMillis = mSourceRefreshesInFlight.remove(safetySourceKey);
+
+ boolean tracked = isTracked(safetySourceKey);
+ mAnyTrackedSourceErrors |= (tracked && !successful);
+ mAnyTrackedSourceDataChanged |= dataChanged;
+ Duration duration =
+ (startElapsedMillis == null)
+ ? null
+ : Duration.ofMillis(SystemClock.elapsedRealtime() - startElapsedMillis);
+ Log.v(
+ TAG,
+ "Refresh completed for sourceId:"
+ + safetySourceKey.getSourceId()
+ + " userId:"
+ + safetySourceKey.getUserId()
+ + " with refreshBroadcastId:"
+ + mId
+ + " duration:"
+ + duration
+ + " successful:"
+ + successful
+ + " dataChanged:"
+ + dataChanged
+ + " & tracking:"
+ + tracked
+ + ", "
+ + mSourceRefreshesInFlight.size()
+ + " tracked sources still in flight.");
+ return duration;
+ }
+
+ private boolean isTracked(SafetySourceKey safetySourceKey) {
+ return !mUntrackedSourcesIds.contains(safetySourceKey.getSourceId());
+ }
+
+ /**
+ * Clears the data for the given {@code userId} and returns whether that caused the entire
+ * refresh to complete.
+ */
+ private boolean clearForUser(@UserIdInt int userId) {
+ if (mUserProfileGroup.getProfileParentUserId() == userId) {
+ return true;
+ }
+ // Loop in reverse index order to be able to remove entries while iterating.
+ for (int i = mSourceRefreshesInFlight.size() - 1; i >= 0; i--) {
+ SafetySourceKey sourceKey = mSourceRefreshesInFlight.keyAt(i);
+ if (sourceKey.getUserId() == userId) {
+ mSourceRefreshesInFlight.removeAt(i);
+ }
+ }
+ return isComplete();
+ }
+
+ private boolean isComplete() {
+ return mSourceRefreshesInFlight.isEmpty();
+ }
+
+ @Override
+ public String toString() {
+ return "RefreshInProgress{"
+ + "mId='"
+ + mId
+ + '\''
+ + ", mReason="
+ + mReason
+ + ", mUserProfileGroup="
+ + mUserProfileGroup
+ + ", mUntrackedSourcesIds="
+ + mUntrackedSourcesIds
+ + ", mSourceRefreshesInFlight="
+ + mSourceRefreshesInFlight
+ + ", mStartElapsedMillis="
+ + mStartElapsedMillis
+ + ", mAnyTrackedSourceErrors="
+ + mAnyTrackedSourceErrors
+ + ", mAnyTrackedSourceDataChanged="
+ + mAnyTrackedSourceDataChanged
+ + '}';
+ }
+ }
+}
diff --git a/service/java/com/android/safetycenter/SafetyCenterService.java b/service/java/com/android/safetycenter/SafetyCenterService.java
index b0d9a8fac..f23f041bd 100644
--- a/service/java/com/android/safetycenter/SafetyCenterService.java
+++ b/service/java/com/android/safetycenter/SafetyCenterService.java
@@ -19,42 +19,82 @@ package com.android.safetycenter;
import static android.Manifest.permission.MANAGE_SAFETY_CENTER;
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_OTHER;
import static android.safetycenter.SafetyCenterManager.RefreshReason;
-import static android.safetycenter.config.SafetySource.SAFETY_SOURCE_TYPE_STATIC;
+import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED;
+import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED;
+
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__TIMEOUT;
+import static com.android.permission.PermissionStatsLog.SAFETY_STATE;
+import static com.android.safetycenter.SafetyCenterFlags.PROPERTY_SAFETY_CENTER_ENABLED;
+import static com.android.safetycenter.internaldata.SafetyCenterIds.toUserFriendlyString;
import static java.util.Objects.requireNonNull;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.app.AppOpsManager;
+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;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManager.PackageInfoFlags;
import android.content.res.Resources;
import android.os.Binder;
-import android.os.RemoteCallbackList;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.UserHandle;
import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.OnPropertiesChangedListener;
import android.safetycenter.IOnSafetyCenterDataChangedListener;
import android.safetycenter.ISafetyCenterManager;
import android.safetycenter.SafetyCenterData;
import android.safetycenter.SafetyCenterErrorDetails;
+import android.safetycenter.SafetyCenterManager;
import android.safetycenter.SafetyEvent;
import android.safetycenter.SafetySourceData;
import android.safetycenter.SafetySourceErrorDetails;
+import android.safetycenter.SafetySourceIssue;
import android.safetycenter.config.SafetyCenterConfig;
-import android.safetycenter.config.SafetySource;
-import android.safetycenter.config.SafetySourcesGroup;
+import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.Log;
import androidx.annotation.Keep;
import androidx.annotation.RequiresApi;
import com.android.internal.annotations.GuardedBy;
-import com.android.permission.util.PermissionUtils;
+import com.android.modules.utils.BackgroundThread;
+import com.android.permission.util.ForegroundThread;
+import com.android.permission.util.UserUtils;
+import com.android.safetycenter.data.SafetyCenterDataManager;
+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.logging.SafetyCenterPullAtomCallback;
+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.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.
@@ -67,42 +107,141 @@ public final class SafetyCenterService extends SystemService {
private static final String TAG = "SafetyCenterService";
- /** Phenotype flag that determines whether SafetyCenter is enabled. */
- private static final String PROPERTY_SAFETY_CENTER_ENABLED = "safety_center_is_enabled";
+ private final ApiLock mApiLock = new ApiLock();
+
+ @GuardedBy("mApiLock")
+ private final SafetyCenterTimeouts mSafetyCenterTimeouts = new SafetyCenterTimeouts();
+
+ private final SafetyCenterResourcesContext mSafetyCenterResourcesContext;
+
+ private final SafetyCenterNotificationChannels mNotificationChannels;
- private final Object mApiLock = new Object();
- // Refresh/rescan is guarded by another lock: sending broadcasts can be a lengthy operation and
- // the APIs that will be exercised by the receivers are already protected by `mApiLock`.
- private final Object mRefreshLock = new Object();
+ @GuardedBy("mApiLock")
+ private final SafetyCenterConfigReader mSafetyCenterConfigReader;
@GuardedBy("mApiLock")
- private final SafetyCenterListeners mSafetyCenterListeners = new SafetyCenterListeners();
+ private final SafetyCenterRefreshTracker mSafetyCenterRefreshTracker;
- @NonNull private final SafetyCenterConfigReader mSafetyCenterConfigReader;
+ @GuardedBy("mApiLock")
+ private final SafetyCenterDataManager mSafetyCenterDataManager;
@GuardedBy("mApiLock")
- @NonNull
- private final SafetyCenterDataTracker mSafetyCenterDataTracker;
+ private final SafetyCenterDataFactory mSafetyCenterDataFactory;
- @GuardedBy("mRefreshLock")
- @NonNull
- private final SafetyCenterRefreshManager mSafetyCenterRefreshManager;
+ @GuardedBy("mApiLock")
+ private final SafetyCenterListeners mSafetyCenterListeners;
+
+ @GuardedBy("mApiLock")
+ private final SafetyCenterNotificationSender mNotificationSender;
+
+ @GuardedBy("mApiLock")
+ private final SafetyCenterBroadcastDispatcher mSafetyCenterBroadcastDispatcher;
+
+ @GuardedBy("mApiLock")
+ private final SafetyCenterDataChangeNotifier mSafetyCenterDataChangeNotifier;
- @NonNull private final AppOpsManager mAppOpsManager;
+ private final StatsPullAtomCallback mPullAtomCallback;
+ private final boolean mDeviceSupportsSafetyCenter;
- public SafetyCenterService(@NonNull Context context) {
+ /** Whether the {@link SafetyCenterConfig} was successfully loaded. */
+ private volatile boolean mConfigAvailable;
+
+ public SafetyCenterService(Context context) {
super(context);
- mSafetyCenterConfigReader = new SafetyCenterConfigReader(context);
- mSafetyCenterDataTracker = new SafetyCenterDataTracker(context, mSafetyCenterConfigReader);
- mSafetyCenterRefreshManager =
- new SafetyCenterRefreshManager(context, mSafetyCenterConfigReader);
- mAppOpsManager = requireNonNull(context.getSystemService(AppOpsManager.class));
+ mSafetyCenterResourcesContext = new SafetyCenterResourcesContext(context);
+ mSafetyCenterConfigReader = new SafetyCenterConfigReader(mSafetyCenterResourcesContext);
+ mSafetyCenterRefreshTracker = new SafetyCenterRefreshTracker(context);
+ mSafetyCenterDataManager =
+ new SafetyCenterDataManager(
+ context, mSafetyCenterConfigReader, mSafetyCenterRefreshTracker, mApiLock);
+ mSafetyCenterDataFactory =
+ new SafetyCenterDataFactory(
+ context,
+ mSafetyCenterResourcesContext,
+ mSafetyCenterConfigReader,
+ mSafetyCenterRefreshTracker,
+ new PendingIntentFactory(context, mSafetyCenterResourcesContext),
+ mSafetyCenterDataManager);
+ mSafetyCenterListeners = new SafetyCenterListeners(mSafetyCenterDataFactory);
+ mNotificationChannels = new SafetyCenterNotificationChannels(mSafetyCenterResourcesContext);
+ mNotificationSender =
+ SafetyCenterNotificationSender.newInstance(
+ context,
+ mSafetyCenterResourcesContext,
+ mNotificationChannels,
+ mSafetyCenterDataManager);
+ mSafetyCenterBroadcastDispatcher =
+ new SafetyCenterBroadcastDispatcher(
+ context,
+ mSafetyCenterConfigReader,
+ mSafetyCenterRefreshTracker,
+ mSafetyCenterDataManager);
+ mPullAtomCallback =
+ new SafetyCenterPullAtomCallback(
+ context,
+ mApiLock,
+ mSafetyCenterConfigReader,
+ mSafetyCenterDataFactory,
+ mSafetyCenterDataManager);
+ mSafetyCenterDataChangeNotifier =
+ new SafetyCenterDataChangeNotifier(mNotificationSender, mSafetyCenterListeners);
+ mDeviceSupportsSafetyCenter =
+ context.getResources()
+ .getBoolean(
+ 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());
- mSafetyCenterConfigReader.loadSafetyCenterConfig();
+ 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());
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_BOOT_COMPLETED && canUseSafetyCenter()) {
+ registerSafetyCenterEnabledListener();
+ registerSafetyCenterPullAtomCallback();
+ mNotificationChannels.createAllChannelsForAllUsers(getContext());
+ }
+ }
+
+ 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);
+ DeviceConfig.addOnPropertiesChangedListener(
+ DeviceConfig.NAMESPACE_PRIVACY, foregroundThreadExecutor, listener);
+ }
+
+ private void registerSafetyCenterPullAtomCallback() {
+ StatsManager statsManager =
+ requireNonNull(getContext().getSystemService(StatsManager.class));
+ statsManager.setPullAtomCallback(
+ SAFETY_STATE, null, BackgroundThread.getExecutor(), mPullAtomCallback);
}
/** Service implementation of {@link ISafetyCenterManager.Stub}. */
@@ -111,122 +250,137 @@ public final class SafetyCenterService extends SystemService {
public boolean isSafetyCenterEnabled() {
enforceAnyCallingOrSelfPermissions(
"isSafetyCenterEnabled", READ_SAFETY_CENTER_STATUS, SEND_SAFETY_CENTER_UPDATE);
- // TODO(b/214568975): Decide if we should disable safety center if there is a problem
- // reading the config.
return isApiEnabled();
}
@Override
public void setSafetySourceData(
- @NonNull String safetySourceId,
+ String safetySourceId,
@Nullable SafetySourceData safetySourceData,
- @NonNull SafetyEvent safetyEvent,
- @NonNull String packageName,
+ SafetyEvent safetyEvent,
+ String packageName,
@UserIdInt int userId) {
- mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
- // TODO(b/217235899): Finalize cross-user behavior.
- PermissionUtils.enforceCrossUserPermission(
- userId, false, "setSafetySourceData", getContext());
- // TODO(b/205706756): Security: check certs?
+ requireNonNull(safetySourceId);
+ requireNonNull(safetyEvent);
+ requireNonNull(packageName);
getContext()
.enforceCallingOrSelfPermission(
SEND_SAFETY_CENTER_UPDATE, "setSafetySourceData");
- if (!checkApiEnabled("setSafetySourceData")) {
+ if (!enforceCrossUserPermission("setSafetySourceData", userId)
+ || !enforcePackage(Binder.getCallingUid(), packageName, userId)
+ || !checkApiEnabled("setSafetySourceData")) {
return;
}
- // TODO(b/218812582): Validate the SafetySourceData.
- SafetyCenterData safetyCenterData;
- RemoteCallbackList<IOnSafetyCenterDataChangedListener> listeners;
+ UserProfileGroup userProfileGroup = UserProfileGroup.fromUser(getContext(), userId);
synchronized (mApiLock) {
- safetyCenterData =
- mSafetyCenterDataTracker.setSafetySourceData(
- safetySourceId, safetySourceData, packageName, userId);
- listeners = mSafetyCenterListeners.getListeners(userId);
- }
- // This doesn't need to be done while holding the lock, as RemoteCallbackList already
- // handles concurrent calls.
- // If the listener uses SafetyCenterManager and is executed on #directExecutor(),
- // doing this while holding the lock could also potentially lead to deadlocks.
- if (listeners != null && safetyCenterData != null) {
- // TODO(b/218811189): This should be called on all listeners associated with the
- // userId, i.e. if #setSafetySourceData is called with a work profile userId,
- // we should also let the personal profile listeners know about the update.
- SafetyCenterListeners.deliverUpdate(listeners, safetyCenterData);
+ boolean hasUpdate =
+ mSafetyCenterDataManager.setSafetySourceData(
+ safetySourceData, safetySourceId, safetyEvent, packageName, userId);
+ if (hasUpdate) {
+ // When an action is successfully resolved, call notifyActionSuccess before
+ // updateDataConsumers: Calling the former first will turn any notification for
+ // the resolved issue into a success notification, whereas calling the latter
+ // will simply clear any issue notification and no success message will show.
+ if (safetyEvent.getType() == SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED) {
+ mNotificationSender.notifyActionSuccess(
+ safetySourceId, safetyEvent, userId);
+ }
+ mSafetyCenterDataChangeNotifier.updateDataConsumers(userProfileGroup, userId);
+ }
}
}
@Override
@Nullable
public SafetySourceData getSafetySourceData(
- @NonNull String safetySourceId,
- @NonNull String packageName,
- @UserIdInt int userId) {
- mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
- // TODO(b/217235899): Finalize cross-user behavior.
- PermissionUtils.enforceCrossUserPermission(
- userId, false, "getSafetySourceData", getContext());
- // TODO(b/205706756): Security: check certs?
+ String safetySourceId, String packageName, @UserIdInt int userId) {
+ requireNonNull(safetySourceId);
+ requireNonNull(packageName);
getContext()
.enforceCallingOrSelfPermission(
SEND_SAFETY_CENTER_UPDATE, "getSafetySourceData");
- if (!checkApiEnabled("getSafetySourceData")) {
+ if (!enforceCrossUserPermission("getSafetySourceData", userId)
+ || !enforcePackage(Binder.getCallingUid(), packageName, userId)
+ || !checkApiEnabled("getSafetySourceData")) {
return null;
}
synchronized (mApiLock) {
- return mSafetyCenterDataTracker.getSafetySourceData(
+ return mSafetyCenterDataManager.getSafetySourceData(
safetySourceId, packageName, userId);
}
}
@Override
public void reportSafetySourceError(
- @NonNull String safetySourceId,
- @NonNull SafetySourceErrorDetails errorDetails,
- @NonNull String packageName,
+ String safetySourceId,
+ SafetySourceErrorDetails errorDetails,
+ String packageName,
@UserIdInt int userId) {
- mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
- // TODO(b/217235899): Finalize cross-user behavior.
- PermissionUtils.enforceCrossUserPermission(
- userId, false, "reportSafetySourceError", getContext());
+ requireNonNull(safetySourceId);
+ requireNonNull(errorDetails);
+ requireNonNull(packageName);
getContext()
.enforceCallingOrSelfPermission(
SEND_SAFETY_CENTER_UPDATE, "reportSafetySourceError");
- if (!checkApiEnabled("reportSafetySourceError")) {
+ if (!enforceCrossUserPermission("reportSafetySourceError", userId)
+ || !enforcePackage(Binder.getCallingUid(), packageName, userId)
+ || !checkApiEnabled("reportSafetySourceError")) {
return;
}
- // TODO(b/218379298): Add implementation
- RemoteCallbackList<IOnSafetyCenterDataChangedListener> listeners;
+ UserProfileGroup userProfileGroup = UserProfileGroup.fromUser(getContext(), userId);
synchronized (mApiLock) {
- listeners = mSafetyCenterListeners.getListeners(userId);
+ boolean hasUpdate =
+ mSafetyCenterDataManager.reportSafetySourceError(
+ errorDetails, safetySourceId, packageName, userId);
+ SafetyCenterErrorDetails safetyCenterErrorDetails = null;
+ if (hasUpdate
+ && errorDetails.getSafetyEvent().getType()
+ == SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED) {
+ safetyCenterErrorDetails =
+ new SafetyCenterErrorDetails(
+ mSafetyCenterResourcesContext.getStringByName(
+ "resolving_action_error"));
+ }
+ if (hasUpdate) {
+ mSafetyCenterDataChangeNotifier.updateDataConsumers(userProfileGroup, userId);
+ }
+ if (safetyCenterErrorDetails != null) {
+ mSafetyCenterListeners.deliverErrorForUserProfileGroup(
+ userProfileGroup, safetyCenterErrorDetails);
+ }
}
-
- SafetyCenterListeners.deliverError(listeners, new SafetyCenterErrorDetails("Error"));
}
@Override
public void refreshSafetySources(@RefreshReason int refreshReason, @UserIdInt int userId) {
- // TODO(b/217235899): Finalize cross-user behavior.
- PermissionUtils.enforceCrossUserPermission(
- userId, false, "refreshSafetySources", getContext());
+ RefreshReasons.validate(refreshReason);
getContext().enforceCallingPermission(MANAGE_SAFETY_CENTER, "refreshSafetySources");
- if (!checkApiEnabled("refreshSafetySources")) {
+ if (!enforceCrossUserPermission("refreshSafetySources", userId)
+ || !checkApiEnabled("refreshSafetySources")) {
return;
}
+ startRefreshingSafetySources(refreshReason, userId);
+ }
- // We don't require the caller to have INTERACT_ACROSS_USERS and
- // START_FOREGROUND_SERVICES_FROM_BACKGROUND permissions.
- final long callingId = Binder.clearCallingIdentity();
- try {
- synchronized (mRefreshLock) {
- mSafetyCenterRefreshManager.refreshSafetySources(refreshReason);
- }
- } finally {
- Binder.restoreCallingIdentity(callingId);
+ @Override
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ public void refreshSpecificSafetySources(
+ @RefreshReason int refreshReason,
+ @UserIdInt int userId,
+ List<String> safetySourceIds) {
+ requireNonNull(safetySourceIds, "safetySourceIds cannot be null");
+ RefreshReasons.validate(refreshReason);
+ getContext()
+ .enforceCallingPermission(MANAGE_SAFETY_CENTER, "refreshSpecificSafetySources");
+ if (!enforceCrossUserPermission("refreshSpecificSafetySources", userId)
+ || !checkApiEnabled("refreshSpecificSafetySources")) {
+ return;
}
+ startRefreshingSafetySources(refreshReason, userId, safetySourceIds);
}
@Override
@@ -234,6 +388,13 @@ public final class SafetyCenterService extends SystemService {
public SafetyCenterConfig getSafetyCenterConfig() {
getContext()
.enforceCallingOrSelfPermission(MANAGE_SAFETY_CENTER, "getSafetyCenterConfig");
+ // We still return the SafetyCenterConfig object when the API is disabled, as Settings
+ // 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");
+ return null;
+ }
synchronized (mApiLock) {
return mSafetyCenterConfigReader.getSafetyCenterConfig();
@@ -241,56 +402,62 @@ public final class SafetyCenterService extends SystemService {
}
@Override
- @NonNull
- public SafetyCenterData getSafetyCenterData(@UserIdInt int userId) {
- // TODO(b/217235899): Finalize cross-user behavior.
- PermissionUtils.enforceCrossUserPermission(
- userId, false, "getSafetyCenterData", getContext());
+ public SafetyCenterData getSafetyCenterData(String packageName, @UserIdInt int userId) {
+ requireNonNull(packageName);
getContext()
.enforceCallingOrSelfPermission(MANAGE_SAFETY_CENTER, "getSafetyCenterData");
- if (!checkApiEnabled("getSafetyCenterData")) {
- return SafetyCenterDataTracker.getDefaultSafetyCenterData();
+ if (!enforceCrossUserPermission("getSafetyCenterData", userId)
+ || !enforcePackage(Binder.getCallingUid(), packageName, userId)
+ || !checkApiEnabled("getSafetyCenterData")) {
+ return SafetyCenterDataFactory.getDefaultSafetyCenterData();
}
+ UserProfileGroup userProfileGroup = UserProfileGroup.fromUser(getContext(), userId);
synchronized (mApiLock) {
- return mSafetyCenterDataTracker.getSafetyCenterData(userId);
+ return mSafetyCenterDataFactory.assembleSafetyCenterData(
+ packageName, userProfileGroup);
}
}
@Override
public void addOnSafetyCenterDataChangedListener(
- @NonNull IOnSafetyCenterDataChangedListener listener, @UserIdInt int userId) {
- // TODO(b/217235899): Finalize cross-user behavior.
- PermissionUtils.enforceCrossUserPermission(
- userId, false, "addOnSafetyCenterDataChangedListener", getContext());
+ IOnSafetyCenterDataChangedListener listener,
+ String packageName,
+ @UserIdInt int userId) {
+ requireNonNull(listener);
+ requireNonNull(packageName);
getContext()
.enforceCallingOrSelfPermission(
MANAGE_SAFETY_CENTER, "addOnSafetyCenterDataChangedListener");
- if (!checkApiEnabled("addOnSafetyCenterDataChangedListener")) {
+ if (!enforceCrossUserPermission("addOnSafetyCenterDataChangedListener", userId)
+ || !enforcePackage(Binder.getCallingUid(), packageName, userId)
+ || !checkApiEnabled("addOnSafetyCenterDataChangedListener")) {
return;
}
- SafetyCenterData safetyCenterData;
+ UserProfileGroup userProfileGroup = UserProfileGroup.fromUser(getContext(), userId);
synchronized (mApiLock) {
- mSafetyCenterListeners.addListener(listener, userId);
- safetyCenterData = mSafetyCenterDataTracker.getSafetyCenterData(userId);
+ IOnSafetyCenterDataChangedListener registeredListener =
+ mSafetyCenterListeners.addListener(listener, packageName, userId);
+ if (registeredListener == null) {
+ return;
+ }
+ SafetyCenterListeners.deliverDataForListener(
+ registeredListener,
+ mSafetyCenterDataFactory.assembleSafetyCenterData(
+ packageName, userProfileGroup));
}
- // This doesn't need to be done while holding the lock.
- // If the listener uses SafetyCenterManager and is executed on #directExecutor(),
- // doing this while holding the lock could also potentially lead to deadlocks.
- SafetyCenterListeners.deliverUpdate(listener, safetyCenterData);
}
@Override
public void removeOnSafetyCenterDataChangedListener(
- @NonNull IOnSafetyCenterDataChangedListener listener, @UserIdInt int userId) {
- // TODO(b/217235899): Finalize cross-user behavior.
- PermissionUtils.enforceCrossUserPermission(
- userId, false, "removeOnSafetyCenterDataChangedListener", getContext());
+ IOnSafetyCenterDataChangedListener listener, @UserIdInt int userId) {
+ requireNonNull(listener);
getContext()
.enforceCallingOrSelfPermission(
MANAGE_SAFETY_CENTER, "removeOnSafetyCenterDataChangedListener");
- if (!checkApiEnabled("removeOnSafetyCenterDataChangedListener")) {
+ if (!enforceCrossUserPermission("removeOnSafetyCenterDataChangedListener", userId)
+ || !checkApiEnabled("removeOnSafetyCenterDataChangedListener")) {
return;
}
@@ -301,34 +468,90 @@ public final class SafetyCenterService extends SystemService {
@Override
public void dismissSafetyCenterIssue(String issueId, @UserIdInt int userId) {
- // TODO(b/217235899): Finalize cross-user behavior.
- PermissionUtils.enforceCrossUserPermission(
- userId, false, "dismissSafetyCenterIssue", getContext());
+ requireNonNull(issueId);
getContext()
.enforceCallingOrSelfPermission(
MANAGE_SAFETY_CENTER, "dismissSafetyCenterIssue");
- if (!checkApiEnabled("dismissSafetyCenterIssue")) {
+ if (!enforceCrossUserPermission("dismissSafetyCenterIssue", userId)
+ || !checkApiEnabled("dismissSafetyCenterIssue")) {
return;
}
- // TODO(b/202387059): Implement issue dismissal.
+ SafetyCenterIssueId safetyCenterIssueId = SafetyCenterIds.issueIdFromString(issueId);
+ SafetyCenterIssueKey safetyCenterIssueKey =
+ safetyCenterIssueId.getSafetyCenterIssueKey();
+ UserProfileGroup userProfileGroup = UserProfileGroup.fromUser(getContext(), userId);
+ enforceSameUserProfileGroup(
+ "dismissSafetyCenterIssue", userProfileGroup, safetyCenterIssueKey.getUserId());
+ synchronized (mApiLock) {
+ SafetySourceIssue safetySourceIssue =
+ mSafetyCenterDataManager.getSafetySourceIssue(safetyCenterIssueKey);
+ if (safetySourceIssue == null) {
+ Log.w(TAG, "Attempt to dismiss an issue that is not provided by the source");
+ // Don't send the error to the UI here, since it could happen when clicking the
+ // button multiple times in a row (e.g. if the source is clearing the issue as a
+ // result of the onDismissPendingIntent).
+ return;
+ }
+ if (mSafetyCenterDataManager.isIssueDismissed(
+ safetyCenterIssueKey, safetySourceIssue.getSeverityLevel())) {
+ Log.w(TAG, "Attempt to dismiss an issue that is already dismissed");
+ // Don't send the error to the UI here, since it could happen when clicking the
+ // button multiple times in a row.
+ return;
+ }
+ mSafetyCenterDataManager.dismissSafetyCenterIssue(safetyCenterIssueKey);
+ PendingIntent onDismissPendingIntent =
+ safetySourceIssue.getOnDismissPendingIntent();
+ if (onDismissPendingIntent != null
+ && !dispatchPendingIntent(onDismissPendingIntent, null)) {
+ Log.w(
+ TAG,
+ "Error dispatching dismissal for issue: "
+ + safetyCenterIssueKey.getSafetySourceIssueId()
+ + ", of source: "
+ + safetyCenterIssueKey.getSafetySourceId());
+ // We still consider the dismissal a success if there is an error dispatching
+ // the dismissal PendingIntent, since SafetyCenter won't surface this warning
+ // anymore.
+ }
+ mSafetyCenterDataChangeNotifier.updateDataConsumers(userProfileGroup, userId);
+ }
}
@Override
public void executeSafetyCenterIssueAction(
- @NonNull String safetyCenterIssueId,
- @NonNull String safetyCenterActionId,
- @UserIdInt int userId) {
- // TODO(b/217235899): Finalize cross-user behavior.
- PermissionUtils.enforceCrossUserPermission(
- userId, false, "executeSafetyCenterIssueAction", getContext());
+ String issueId, String issueActionId, @UserIdInt int userId) {
+ requireNonNull(issueId);
+ requireNonNull(issueActionId);
getContext()
.enforceCallingOrSelfPermission(
MANAGE_SAFETY_CENTER, "executeSafetyCenterIssueAction");
- if (!checkApiEnabled("executeSafetyCenterIssueAction")) {
+ if (!enforceCrossUserPermission("executeSafetyCenterIssueAction", userId)
+ || !checkApiEnabled("executeSafetyCenterIssueAction")) {
return;
}
- // TODO(b/218379298): Add implementation
+
+ SafetyCenterIssueId safetyCenterIssueId = SafetyCenterIds.issueIdFromString(issueId);
+ SafetyCenterIssueKey safetyCenterIssueKey =
+ safetyCenterIssueId.getSafetyCenterIssueKey();
+ SafetyCenterIssueActionId safetyCenterIssueActionId =
+ SafetyCenterIds.issueActionIdFromString(issueActionId);
+ if (!safetyCenterIssueActionId.getSafetyCenterIssueKey().equals(safetyCenterIssueKey)) {
+ throw new IllegalArgumentException(
+ toUserFriendlyString(safetyCenterIssueId)
+ + " and "
+ + toUserFriendlyString(safetyCenterIssueActionId)
+ + " do not match");
+ }
+ UserProfileGroup userProfileGroup = UserProfileGroup.fromUser(getContext(), userId);
+ enforceSameUserProfileGroup(
+ "executeSafetyCenterIssueAction",
+ userProfileGroup,
+ safetyCenterIssueKey.getUserId());
+ Integer taskId =
+ safetyCenterIssueId.hasTaskId() ? safetyCenterIssueId.getTaskId() : null;
+ executeIssueActionInternal(safetyCenterIssueActionId, userProfileGroup, taskId);
}
@Override
@@ -340,13 +563,18 @@ public final class SafetyCenterService extends SystemService {
return;
}
+ List<UserProfileGroup> userProfileGroups =
+ UserProfileGroup.getAllUserProfileGroups(getContext());
synchronized (mApiLock) {
- mSafetyCenterDataTracker.clear();
+ // TODO(b/236693607): Should tests leave real data untouched?
+ clearDataLocked();
+ mSafetyCenterDataChangeNotifier.updateDataConsumers(userProfileGroups);
}
}
@Override
- public void setSafetyCenterConfigForTests(@NonNull SafetyCenterConfig safetyCenterConfig) {
+ public void setSafetyCenterConfigForTests(SafetyCenterConfig safetyCenterConfig) {
+ requireNonNull(safetyCenterConfig);
getContext()
.enforceCallingOrSelfPermission(
MANAGE_SAFETY_CENTER, "setSafetyCenterConfigForTests");
@@ -354,20 +582,13 @@ public final class SafetyCenterService extends SystemService {
return;
}
- synchronized (mRefreshLock) {
- // TODO(b/217944317): Implement properly by overriding config in
- // SafetyCenterConfigReader instead. This placeholder impl serves to allow this
- // API to be merged in tm-dev, and final impl will be in tm-mainline-prod.
- for (int i = 0; i < safetyCenterConfig.getSafetySourcesGroups().size(); i++) {
- SafetySourcesGroup group = safetyCenterConfig.getSafetySourcesGroups().get(i);
- for (int j = 0; j < group.getSafetySources().size(); j++) {
- SafetySource safetySource = group.getSafetySources().get(j);
- if (safetySource.getType() != SAFETY_SOURCE_TYPE_STATIC) {
- mSafetyCenterRefreshManager.addAdditionalSafetySourcePackageNames(
- safetySource.getPackageName());
- }
- }
- }
+ List<UserProfileGroup> userProfileGroups =
+ UserProfileGroup.getAllUserProfileGroups(getContext());
+ synchronized (mApiLock) {
+ mSafetyCenterConfigReader.setConfigOverrideForTests(safetyCenterConfig);
+ // TODO(b/236693607): Should tests leave real data untouched?
+ clearDataLocked();
+ mSafetyCenterDataChangeNotifier.updateDataConsumers(userProfileGroups);
}
}
@@ -380,44 +601,27 @@ public final class SafetyCenterService extends SystemService {
return;
}
- synchronized (mRefreshLock) {
- mSafetyCenterRefreshManager.clearAdditionalSafetySourcePackageNames();
+ List<UserProfileGroup> userProfileGroups =
+ UserProfileGroup.getAllUserProfileGroups(getContext());
+ synchronized (mApiLock) {
+ mSafetyCenterConfigReader.clearConfigOverrideForTests();
+ // TODO(b/236693607): Should tests leave real data untouched?
+ clearDataLocked();
+ mSafetyCenterDataChangeNotifier.updateDataConsumers(userProfileGroups);
}
}
private boolean isApiEnabled() {
- return getSafetyCenterConfigValue() && getDeviceConfigSafetyCenterEnabledProperty();
- }
-
- private boolean getDeviceConfigSafetyCenterEnabledProperty() {
- // This call requires the READ_DEVICE_CONFIG permission.
- final long callingId = Binder.clearCallingIdentity();
- try {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_SAFETY_CENTER_ENABLED,
- /* defaultValue = */ false);
- } finally {
- Binder.restoreCallingIdentity(callingId);
- }
+ return canUseSafetyCenter() && SafetyCenterFlags.getSafetyCenterEnabled();
}
- private boolean getSafetyCenterConfigValue() {
- return getContext()
- .getResources()
- .getBoolean(
- Resources.getSystem()
- .getIdentifier("config_enableSafetyCenter", "bool", "android"));
- }
-
- private void enforceAnyCallingOrSelfPermissions(
- @NonNull String message, String... permissions) {
+ private void enforceAnyCallingOrSelfPermissions(String message, String... permissions) {
if (permissions.length == 0) {
throw new IllegalArgumentException("Must check at least one permission");
}
for (int i = 0; i < permissions.length; i++) {
if (getContext().checkCallingOrSelfPermission(permissions[i])
- == PackageManager.PERMISSION_GRANTED) {
+ == PERMISSION_GRANTED) {
return;
}
}
@@ -428,12 +632,544 @@ public final class SafetyCenterService extends SystemService {
+ ", but none were granted");
}
- private boolean checkApiEnabled(@NonNull String message) {
+ /** 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());
+ if (!UserUtils.isUserExistent(userId, getContext())) {
+ Log.w(
+ TAG,
+ "Called "
+ + message
+ + " with user id "
+ + userId
+ + ", which does not correspond to an existing user");
+ return false;
+ }
+ if (!UserProfileGroup.isSupported(userId, getContext())) {
+ Log.w(
+ TAG,
+ "Called "
+ + message
+ + " with user id "
+ + userId
+ + ", which is an unsupported user");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns {@code true} if the {@code packageName} exists and it belongs to the {@code
+ * callingUid}.
+ *
+ * <p>Throws a {@link SecurityException} if the {@code packageName} does not belong to the
+ * {@code callingUid}.
+ */
+ private boolean enforcePackage(int callingUid, String packageName, @UserIdInt int userId) {
+ if (TextUtils.isEmpty(packageName)) {
+ throw new IllegalArgumentException("packageName may not be empty");
+ }
+ int actualUid;
+ PackageManager packageManager = getContext().getPackageManager();
+ try {
+ actualUid =
+ packageManager.getPackageUidAsUser(
+ packageName, PackageInfoFlags.of(0), userId);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "packageName=" + packageName + ", not found for userId=" + userId, e);
+ return false;
+ }
+ if (callingUid == Process.ROOT_UID || callingUid == Process.SYSTEM_UID) {
+ return true;
+ }
+ if (UserHandle.getAppId(callingUid) != UserHandle.getAppId(actualUid)) {
+ throw new SecurityException(
+ "packageName="
+ + packageName
+ + ", does not belong to callingUid="
+ + callingUid);
+ }
+ return true;
+ }
+
+ private boolean checkApiEnabled(String message) {
if (!isApiEnabled()) {
- Log.w(TAG, String.format("Called %s, but Safety Center is disabled", message));
+ Log.w(TAG, "Called " + message + ", but Safety Center is disabled");
return false;
}
return true;
}
+
+ private void enforceSameUserProfileGroup(
+ String message, UserProfileGroup userProfileGroup, @UserIdInt int userId) {
+ if (!userProfileGroup.contains(userId)) {
+ throw new SecurityException(
+ message
+ + " requires target user id "
+ + userId
+ + " to be within the same profile group of the caller: "
+ + userProfileGroup);
+ }
+ }
+
+ @Override
+ public int handleShellCommand(
+ ParcelFileDescriptor in,
+ ParcelFileDescriptor out,
+ ParcelFileDescriptor err,
+ String[] args) {
+ return new SafetyCenterShellCommandHandler(
+ getContext(), this, mDeviceSupportsSafetyCenter)
+ .exec(
+ this,
+ in.getFileDescriptor(),
+ out.getFileDescriptor(),
+ err.getFileDescriptor(),
+ args);
+ }
+
+ /** Dumps state for debugging purposes. */
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter fout, @Nullable String[] args) {
+ if (!checkDumpPermission(fout)) {
+ return;
+ }
+ List<String> subjects = Arrays.asList(args);
+ boolean all = subjects.isEmpty();
+ synchronized (mApiLock) {
+ if (all || subjects.contains("service")) {
+ SafetyCenterService.this.dumpLocked(fout);
+ }
+ if (all || subjects.contains("flags")) {
+ SafetyCenterFlags.dump(fout);
+ }
+ if (all || subjects.contains("config")) {
+ mSafetyCenterConfigReader.dump(fout);
+ }
+ if (all || subjects.contains("data")) {
+ mSafetyCenterDataManager.dump(fd, fout);
+ }
+ if (all || subjects.contains("refresh")) {
+ mSafetyCenterRefreshTracker.dump(fout);
+ }
+ if (all || subjects.contains("timeouts")) {
+ mSafetyCenterTimeouts.dump(fout);
+ }
+ if (all || subjects.contains("listeners")) {
+ mSafetyCenterListeners.dump(fout);
+ }
+ if (all || subjects.contains("notifications")) {
+ mNotificationSender.dump(fout);
+ }
+ }
+ }
+
+ private boolean checkDumpPermission(PrintWriter writer) {
+ if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PERMISSION_GRANTED) {
+ writer.println(
+ "Permission Denial: can't dump "
+ + "safety_center"
+ + " from from pid="
+ + Binder.getCallingPid()
+ + ", uid="
+ + Binder.getCallingUid()
+ + " due to missing "
+ + android.Manifest.permission.DUMP
+ + " permission");
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ /**
+ * An {@link OnPropertiesChangedListener} for {@link
+ * SafetyCenterFlags#PROPERTY_SAFETY_CENTER_ENABLED} that sends broadcasts when the SafetyCenter
+ * property is enabled or disabled.
+ *
+ * <p>This listener assumes that the {@link SafetyCenterFlags#PROPERTY_SAFETY_CENTER_ENABLED}
+ * 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 {
+
+ private boolean mSafetyCenterEnabled;
+
+ @Override
+ public void onPropertiesChanged(DeviceConfig.Properties properties) {
+ if (!properties.getKeyset().contains(PROPERTY_SAFETY_CENTER_ENABLED)) {
+ return;
+ }
+ boolean safetyCenterEnabled =
+ properties.getBoolean(PROPERTY_SAFETY_CENTER_ENABLED, false);
+ if (mSafetyCenterEnabled == safetyCenterEnabled) {
+ return;
+ }
+ onSafetyCenterEnabledChanged(safetyCenterEnabled);
+ }
+
+ private void setInitialState() {
+ mSafetyCenterEnabled = SafetyCenterFlags.getSafetyCenterEnabled();
+ Log.w(TAG, "SafetyCenter is " + (mSafetyCenterEnabled ? "enabled." : "disabled."));
+ }
+
+ private void onSafetyCenterEnabledChanged(boolean safetyCenterEnabled) {
+ Log.w(TAG, "SafetyCenter is now " + (safetyCenterEnabled ? "enabled." : "disabled."));
+
+ if (safetyCenterEnabled) {
+ onApiEnabled();
+ } else {
+ onApiDisabled();
+ }
+ mSafetyCenterEnabled = safetyCenterEnabled;
+ }
+
+ private void onApiEnabled() {
+ synchronized (mApiLock) {
+ mSafetyCenterBroadcastDispatcher.sendEnabledChanged();
+ }
+ }
+
+ private void onApiDisabled() {
+ synchronized (mApiLock) {
+ clearDataLocked();
+ mSafetyCenterListeners.clear();
+ mSafetyCenterBroadcastDispatcher.sendEnabledChanged();
+ }
+ }
+ }
+
+ /** A {@link Runnable} that is called to signal a refresh timeout. */
+ private final class RefreshTimeout implements Runnable {
+
+ private final String mRefreshBroadcastId;
+ @RefreshReason private final int mRefreshReason;
+ private final UserProfileGroup mUserProfileGroup;
+
+ RefreshTimeout(
+ String refreshBroadcastId,
+ @RefreshReason int refreshReason,
+ UserProfileGroup userProfileGroup) {
+ mRefreshBroadcastId = refreshBroadcastId;
+ mRefreshReason = refreshReason;
+ mUserProfileGroup = userProfileGroup;
+ }
+
+ @Override
+ public void run() {
+ synchronized (mApiLock) {
+ mSafetyCenterTimeouts.remove(this);
+ ArraySet<SafetySourceKey> stillInFlight =
+ mSafetyCenterRefreshTracker.timeoutRefresh(mRefreshBroadcastId);
+ if (stillInFlight == null) {
+ return;
+ }
+ boolean showErrorEntriesOnTimeout =
+ SafetyCenterFlags.getShowErrorEntriesOnTimeout();
+ boolean setError =
+ showErrorEntriesOnTimeout
+ && !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
+ public String toString() {
+ return "RefreshTimeout{"
+ + "mRefreshBroadcastId='"
+ + mRefreshBroadcastId
+ + '\''
+ + ", mUserProfileGroup="
+ + mUserProfileGroup
+ + '}';
+ }
+ }
+
+ /** A {@link Runnable} that is called to signal a resolving action timeout. */
+ private final class ResolvingActionTimeout implements Runnable {
+
+ private final SafetyCenterIssueActionId mSafetyCenterIssueActionId;
+ private final UserProfileGroup mUserProfileGroup;
+
+ ResolvingActionTimeout(
+ SafetyCenterIssueActionId safetyCenterIssueActionId,
+ UserProfileGroup userProfileGroup) {
+ mSafetyCenterIssueActionId = safetyCenterIssueActionId;
+ mUserProfileGroup = userProfileGroup;
+ }
+
+ @Override
+ public void run() {
+ synchronized (mApiLock) {
+ mSafetyCenterTimeouts.remove(this);
+ SafetySourceIssue safetySourceIssue =
+ mSafetyCenterDataManager.getSafetySourceIssue(
+ mSafetyCenterIssueActionId.getSafetyCenterIssueKey());
+ boolean safetyCenterDataHasChanged =
+ mSafetyCenterDataManager.unmarkSafetyCenterIssueActionInFlight(
+ mSafetyCenterIssueActionId,
+ safetySourceIssue,
+ SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__TIMEOUT);
+ if (!safetyCenterDataHasChanged) {
+ return;
+ }
+ mSafetyCenterDataChangeNotifier.updateDataConsumers(mUserProfileGroup);
+ mSafetyCenterListeners.deliverErrorForUserProfileGroup(
+ mUserProfileGroup,
+ new SafetyCenterErrorDetails(
+ mSafetyCenterResourcesContext.getStringByName(
+ "resolving_action_error")));
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "ResolvingActionTimeout{"
+ + "mSafetyCenterIssueActionId="
+ + toUserFriendlyString(mSafetyCenterIssueActionId)
+ + ", mUserProfileGroup="
+ + mUserProfileGroup
+ + '}';
+ }
+ }
+
+ private boolean canUseSafetyCenter() {
+ return mDeviceSupportsSafetyCenter && mConfigAvailable;
+ }
+
+ /** {@link BroadcastReceiver} which handles Locale changes. */
+ private final class LocaleBroadcastReceiver extends BroadcastReceiver {
+
+ private static final String TAG = "LocaleBroadcastReceiver";
+
+ void register(Context context) {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_LOCALE_CHANGED);
+ context.registerReceiverForAllUsers(this, filter, null, null);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.d(TAG, "Locale changed broadcast received");
+ mNotificationChannels.createAllChannelsForAllUsers(getContext());
+ }
+ }
+
+ /**
+ * {@link BroadcastReceiver} which handles user and work profile related broadcasts that Safety
+ * Center is interested including quiet mode turning on/off and accounts being added/removed.
+ */
+ private final class UserBroadcastReceiver extends BroadcastReceiver {
+
+ private static final String TAG = "UserBroadcastReceiver";
+
+ void register(Context context) {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_ADDED);
+ 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);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action == null) {
+ 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!");
+ return;
+ }
+
+ int userId = userHandle.getIdentifier();
+ if (!UserProfileGroup.isSupported(userId, context)) {
+ Log.i(
+ TAG,
+ "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);
+ break;
+ case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE:
+ removeUser(userId, false);
+ // fall through!
+ case Intent.ACTION_USER_ADDED:
+ case Intent.ACTION_MANAGED_PROFILE_ADDED:
+ case Intent.ACTION_MANAGED_PROFILE_AVAILABLE:
+ startRefreshingSafetySources(REFRESH_REASON_OTHER, userId);
+ mNotificationChannels.createAllChannelsForUser(getContext(), userHandle);
+ break;
+ }
+ }
+ }
+
+ private void removeUser(@UserIdInt int userId, boolean clearDataPermanently) {
+ UserProfileGroup userProfileGroup = UserProfileGroup.fromUser(getContext(), userId);
+ synchronized (mApiLock) {
+ mSafetyCenterListeners.clearForUser(userId);
+ mSafetyCenterRefreshTracker.clearRefreshForUser(userId);
+
+ if (clearDataPermanently) {
+ mSafetyCenterDataManager.clearForUser(userId);
+ mSafetyCenterDataChangeNotifier.updateDataConsumers(userProfileGroup, userId);
+ } else {
+ mSafetyCenterListeners.deliverDataForUserProfileGroup(userProfileGroup);
+ }
+ }
+ }
+
+ private void startRefreshingSafetySources(
+ @RefreshReason int refreshReason, @UserIdInt int userId) {
+ startRefreshingSafetySources(refreshReason, userId, null);
+ }
+
+ private void startRefreshingSafetySources(
+ @RefreshReason int refreshReason,
+ @UserIdInt int userId,
+ @Nullable List<String> selectedSafetySourceIds) {
+ UserProfileGroup userProfileGroup = UserProfileGroup.fromUser(getContext(), userId);
+ synchronized (mApiLock) {
+ String refreshBroadcastId =
+ mSafetyCenterBroadcastDispatcher.sendRefreshSafetySources(
+ refreshReason, userProfileGroup, selectedSafetySourceIds);
+ if (refreshBroadcastId == null) {
+ return;
+ }
+
+ RefreshTimeout refreshTimeout =
+ new RefreshTimeout(refreshBroadcastId, refreshReason, userProfileGroup);
+ mSafetyCenterTimeouts.add(
+ refreshTimeout, SafetyCenterFlags.getRefreshSourcesTimeout(refreshReason));
+
+ mSafetyCenterDataChangeNotifier.updateDataConsumers(userProfileGroup);
+ }
+ }
+
+ /**
+ * Executes the {@link SafetySourceIssue.Action} specified by the given {@link
+ * SafetyCenterIssueActionId}.
+ *
+ * <p>No validation is performed on the contents of the given ID.
+ */
+ public void executeIssueActionInternal(SafetyCenterIssueActionId safetyCenterIssueActionId) {
+ SafetyCenterIssueKey safetyCenterIssueKey =
+ safetyCenterIssueActionId.getSafetyCenterIssueKey();
+ UserProfileGroup userProfileGroup =
+ UserProfileGroup.fromUser(getContext(), safetyCenterIssueKey.getUserId());
+ executeIssueActionInternal(safetyCenterIssueActionId, userProfileGroup, null);
+ }
+
+ private void executeIssueActionInternal(
+ SafetyCenterIssueActionId safetyCenterIssueActionId,
+ UserProfileGroup userProfileGroup,
+ @Nullable Integer taskId) {
+ synchronized (mApiLock) {
+ SafetySourceIssue.Action safetySourceIssueAction =
+ mSafetyCenterDataManager.getSafetySourceIssueAction(safetyCenterIssueActionId);
+
+ if (safetySourceIssueAction == null) {
+ Log.w(
+ TAG,
+ "Attempt to execute an issue action that is not provided by the source,"
+ + " that was dismissed, or is already in flight");
+ // Don't send the error to the UI here, since it could happen when clicking the
+ // button multiple times in a row.
+ return;
+ }
+ PendingIntent issueActionPendingIntent = safetySourceIssueAction.getPendingIntent();
+ if (!dispatchPendingIntent(issueActionPendingIntent, taskId)) {
+ Log.w(
+ TAG,
+ "Error dispatching action: "
+ + toUserFriendlyString(safetyCenterIssueActionId));
+ CharSequence errorMessage;
+ if (safetySourceIssueAction.willResolve()) {
+ errorMessage =
+ mSafetyCenterResourcesContext.getStringByName("resolving_action_error");
+ } else {
+ errorMessage =
+ mSafetyCenterResourcesContext.getStringByName("redirecting_error");
+ }
+ mSafetyCenterListeners.deliverErrorForUserProfileGroup(
+ userProfileGroup, new SafetyCenterErrorDetails(errorMessage));
+ return;
+ }
+ if (safetySourceIssueAction.willResolve()) {
+ mSafetyCenterDataManager.markSafetyCenterIssueActionInFlight(
+ safetyCenterIssueActionId);
+ ResolvingActionTimeout resolvingActionTimeout =
+ new ResolvingActionTimeout(safetyCenterIssueActionId, userProfileGroup);
+ mSafetyCenterTimeouts.add(
+ resolvingActionTimeout, SafetyCenterFlags.getResolvingActionTimeout());
+ mSafetyCenterDataChangeNotifier.updateDataConsumers(userProfileGroup);
+ }
+ }
+ }
+
+ private boolean dispatchPendingIntent(
+ PendingIntent pendingIntent, @Nullable Integer launchTaskId) {
+ if (launchTaskId != null
+ && getContext().checkCallingOrSelfPermission(START_TASKS_FROM_RECENTS)
+ != PERMISSION_GRANTED) {
+ launchTaskId = null;
+ }
+ return PendingIntentSender.trySend(pendingIntent, launchTaskId);
+ }
+
+ @GuardedBy("mApiLock")
+ private void clearDataLocked() {
+ mSafetyCenterDataManager.clear();
+ mSafetyCenterTimeouts.clear();
+ mSafetyCenterRefreshTracker.clearRefresh();
+ mNotificationSender.cancelAllNotifications();
+ }
+
+ /** Dumps state for debugging purposes. */
+ @GuardedBy("mApiLock")
+ private void dumpLocked(PrintWriter fout) {
+ fout.println("SERVICE");
+ fout.println(
+ "\tSafetyCenterService{"
+ + "mDeviceSupportsSafetyCenter="
+ + mDeviceSupportsSafetyCenter
+ + ", mConfigAvailable="
+ + mConfigAvailable
+ + '}');
+ fout.println();
}
}
diff --git a/service/java/com/android/safetycenter/SafetyCenterShellCommandHandler.java b/service/java/com/android/safetycenter/SafetyCenterShellCommandHandler.java
new file mode 100644
index 000000000..87e3372f7
--- /dev/null
+++ b/service/java/com/android/safetycenter/SafetyCenterShellCommandHandler.java
@@ -0,0 +1,211 @@
+/*
+ * 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;
+
+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;
+import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_PAGE_OPEN;
+import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_PERIODIC;
+import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_RESCAN_BUTTON_CLICK;
+import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_SAFETY_CENTER_ENABLED;
+
+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 com.android.modules.utils.BasicShellCommandHandler;
+import com.android.modules.utils.build.SdkLevel;
+
+import java.io.PrintWriter;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * A {@link BasicShellCommandHandler} implementation to handle Safety Center commands.
+ *
+ * <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();
+
+ private final Context mContext;
+ private final ISafetyCenterManager mSafetyCenterManager;
+ private final boolean mDeviceSupportsSafetyCenter;
+
+ SafetyCenterShellCommandHandler(
+ Context context,
+ ISafetyCenterManager safetyCenterManager,
+ boolean deviceSupportsSafetyCenter) {
+ mContext = context;
+ mSafetyCenterManager = safetyCenterManager;
+ mDeviceSupportsSafetyCenter = deviceSupportsSafetyCenter;
+ }
+
+ @Override
+ public int onCommand(@Nullable String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(null);
+ }
+ try {
+ // Hey! Are you adding a new command to this switch? Then don't forget to add
+ // instructions for it in the onHelp function below!
+ switch (cmd) {
+ case "enabled":
+ return onEnabled();
+ case "supported":
+ return onSupported();
+ case "refresh":
+ return onRefresh();
+ case "clear-data":
+ return onClearData();
+ case "package-name":
+ return onPackageName();
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ } catch (RemoteException | IllegalArgumentException e) {
+ e.printStackTrace(getErrPrintWriter());
+ return 1;
+ }
+ }
+
+ private int onEnabled() throws RemoteException {
+ getOutPrintWriter().println(mSafetyCenterManager.isSafetyCenterEnabled());
+ return 0;
+ }
+
+ private int onSupported() {
+ getOutPrintWriter().println(mDeviceSupportsSafetyCenter);
+ return 0;
+ }
+
+ private int onRefresh() throws RemoteException {
+ int reason = REFRESH_REASON_OTHER;
+ int userId = 0;
+ String opt = getNextOption();
+ while (opt != null) {
+ switch (opt) {
+ case "--reason":
+ reason = parseReason();
+ break;
+ case "--user":
+ userId = parseUserId();
+ break;
+ default:
+ throw new IllegalArgumentException("Unexpected option: " + opt);
+ }
+ opt = getNextOption();
+ }
+ getOutPrintWriter().println("Starting refresh…");
+ mSafetyCenterManager.refreshSafetySources(reason, userId);
+ return 0;
+ }
+
+ @RefreshReason
+ private int parseReason() {
+ String arg = getNextArgRequired();
+ Integer reason = REASONS.get(arg);
+ if (reason != null) {
+ return reason;
+ } else {
+ throw new IllegalArgumentException("Invalid --reason arg: " + arg);
+ }
+ }
+
+ @UserIdInt
+ private int parseUserId() {
+ String arg = getNextArgRequired();
+ try {
+ return Integer.parseInt(arg);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid --user arg: " + arg, e);
+ }
+ }
+
+ private int onClearData() throws RemoteException {
+ getOutPrintWriter().println("Clearing all data…");
+ mSafetyCenterManager.clearAllSafetySourceDataForTests();
+ return 0;
+ }
+
+ private int onPackageName() {
+ getOutPrintWriter()
+ .println(mContext.getPackageManager().getPermissionControllerPackageName());
+ return 0;
+ }
+
+ @Override
+ public void onHelp() {
+ getOutPrintWriter().println("Safety Center (safety_center) commands:");
+ printCmd("help or -h", "Print this help text");
+ printCmd(
+ "enabled",
+ "Check if Safety Center is enabled",
+ "Prints \"true\" if enabled, \"false\" otherwise");
+ printCmd(
+ "supported",
+ "Check if this device supports Safety Center (i.e. Safety Center could be enabled)",
+ "Prints \"true\" if supported, \"false\" otherwise");
+ printCmd(
+ "refresh [--reason REASON] [--user USERID]",
+ "Start a refresh of all sources",
+ "REASON is one of "
+ + String.join(", ", REASONS.keySet())
+ + "; determines whether sources fetch fresh data (default OTHER)",
+ "USERID is a user ID; refresh sources in this user profile group (default 0)");
+ printCmd(
+ "clear-data",
+ "Clear all data held by Safety Center",
+ "Includes data held in memory and persistent storage but not the listeners.");
+ printCmd("package-name", "Prints the name of the package that contains Safety Center");
+ }
+
+ /** Helper function to standardise pretty-printing of the help text. */
+ private void printCmd(String cmd, String... description) {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println(" " + cmd);
+ for (int i = 0; i < description.length; i++) {
+ pw.println(" " + description[i]);
+ }
+ }
+
+ private static Map<String, Integer> createReasonMap() {
+ // LinkedHashMap so that options get printed in order
+ LinkedHashMap<String, Integer> reasons = new LinkedHashMap<>(6);
+ reasons.put("PAGE_OPEN", REFRESH_REASON_PAGE_OPEN);
+ reasons.put("BUTTON_CLICK", REFRESH_REASON_RESCAN_BUTTON_CLICK);
+ reasons.put("REBOOT", REFRESH_REASON_DEVICE_REBOOT);
+ reasons.put("LOCALE_CHANGE", REFRESH_REASON_DEVICE_LOCALE_CHANGE);
+ reasons.put("SAFETY_CENTER_ENABLED", REFRESH_REASON_SAFETY_CENTER_ENABLED);
+ reasons.put("OTHER", REFRESH_REASON_OTHER);
+ if (SdkLevel.isAtLeastU()) {
+ reasons.put("PERIODIC", REFRESH_REASON_PERIODIC);
+ }
+ return unmodifiableMap(reasons);
+ }
+}
diff --git a/service/java/com/android/safetycenter/SafetyCenterTimeouts.java b/service/java/com/android/safetycenter/SafetyCenterTimeouts.java
new file mode 100644
index 000000000..f8bfd691e
--- /dev/null
+++ b/service/java/com/android/safetycenter/SafetyCenterTimeouts.java
@@ -0,0 +1,89 @@
+/*
+ * 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;
+
+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;
+import java.time.Duration;
+import java.util.ArrayDeque;
+import java.util.Iterator;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
+/**
+ * A class to track timeouts related to Safety Center.
+ *
+ * <p>This class isn't thread safe. Thread safety must be handled by the caller.
+ */
+@RequiresApi(TIRAMISU)
+@NotThreadSafe
+final class SafetyCenterTimeouts {
+
+ /**
+ * The maximum number of timeouts we are tracking at a given time. This is to avoid having the
+ * {@code mTimeouts} queue grow unbounded. In practice, we should never have more than 1 or 2
+ * timeouts in flight.
+ */
+ private static final int MAX_TRACKED = 10;
+
+ private final ArrayDeque<Runnable> mTimeouts = new ArrayDeque<>(MAX_TRACKED);
+
+ private final Handler mForegroundHandler = ForegroundThread.getHandler();
+
+ SafetyCenterTimeouts() {}
+
+ /** Adds the given {@link Runnable} to run as a timeout after the given {@link Duration}. */
+ void add(Runnable timeoutAction, Duration timeoutDuration) {
+ if (mTimeouts.size() + 1 >= MAX_TRACKED) {
+ remove(mTimeouts.pollFirst());
+ }
+ mTimeouts.addLast(timeoutAction);
+ mForegroundHandler.postDelayed(timeoutAction, timeoutDuration.toMillis());
+ }
+
+ /** Removes the given {@link Runnable} to run as a timeout. */
+ void remove(Runnable timeoutAction) {
+ mTimeouts.remove(timeoutAction);
+ mForegroundHandler.removeCallbacks(timeoutAction);
+ }
+
+ /** Clears all timeouts. */
+ void clear() {
+ while (!mTimeouts.isEmpty()) {
+ mForegroundHandler.removeCallbacks(mTimeouts.pollFirst());
+ }
+ }
+
+ /** Dumps state for debugging purposes. */
+ void dump(PrintWriter fout) {
+ int count = mTimeouts.size();
+ fout.println("TIMEOUTS (" + count + ")");
+ Iterator<Runnable> it = mTimeouts.iterator();
+ int i = 0;
+ while (it.hasNext()) {
+ fout.println("\t[" + i++ + "] " + it.next());
+ }
+ fout.println();
+ }
+}
diff --git a/service/java/com/android/safetycenter/SafetySourceIssueInfo.java b/service/java/com/android/safetycenter/SafetySourceIssueInfo.java
new file mode 100644
index 000000000..51e6567d7
--- /dev/null
+++ b/service/java/com/android/safetycenter/SafetySourceIssueInfo.java
@@ -0,0 +1,113 @@
+/*
+ * 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 static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import static com.android.safetycenter.internaldata.SafetyCenterIds.toUserFriendlyString;
+
+import android.annotation.UserIdInt;
+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;
+
+/**
+ * Contains various information about a {@link SafetySourceIssue}.
+ *
+ * @hide
+ */
+@RequiresApi(TIRAMISU)
+public final class SafetySourceIssueInfo {
+
+ private final SafetySourceIssue mSafetySourceIssue;
+ private final SafetySource mSafetySource;
+ private final SafetySourcesGroup mSafetySourcesGroup;
+ private final SafetyCenterIssueKey mSafetyCenterIssueKey;
+
+ /** Creates a new {@link SafetySourceIssueInfo} instance. */
+ public SafetySourceIssueInfo(
+ SafetySourceIssue safetySourceIssue,
+ SafetySource safetySource,
+ SafetySourcesGroup safetySourcesGroup,
+ @UserIdInt int userId) {
+ mSafetySourceIssue = safetySourceIssue;
+ mSafetySource = safetySource;
+ mSafetySourcesGroup = safetySourcesGroup;
+ mSafetyCenterIssueKey =
+ SafetyCenterIssueKey.newBuilder()
+ .setSafetySourceId(safetySource.getId())
+ .setSafetySourceIssueId(safetySourceIssue.getId())
+ .setUserId(userId)
+ .build();
+ }
+
+ /** Returns the {@link SafetyCenterIssueKey} related to this {@link SafetySourceIssue}. */
+ public SafetyCenterIssueKey getSafetyCenterIssueKey() {
+ return mSafetyCenterIssueKey;
+ }
+ /** Returns the {@link SafetySourceIssue}. */
+ public SafetySourceIssue getSafetySourceIssue() {
+ return mSafetySourceIssue;
+ }
+
+ /** Returns the {@link SafetySource} related to this {@link SafetySourceIssue}. */
+ public SafetySource getSafetySource() {
+ return mSafetySource;
+ }
+
+ /** Returns the {@link SafetySourcesGroup} related to this {@link SafetySourceIssue}. */
+ public SafetySourcesGroup getSafetySourcesGroup() {
+ return mSafetySourcesGroup;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SafetySourceIssueInfo)) return false;
+ SafetySourceIssueInfo that = (SafetySourceIssueInfo) o;
+ return mSafetySourceIssue.equals(that.mSafetySourceIssue)
+ && mSafetySource.equals(that.mSafetySource)
+ && mSafetySourcesGroup.equals(that.mSafetySourcesGroup)
+ && mSafetyCenterIssueKey.equals(that.mSafetyCenterIssueKey);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mSafetySourceIssue, mSafetySource, mSafetySourcesGroup, mSafetyCenterIssueKey);
+ }
+
+ @Override
+ public String toString() {
+ return "SafetySourceIssueInfo{"
+ + "mSafetySourceIssue="
+ + mSafetySourceIssue
+ + ", mSafetySource="
+ + mSafetySource
+ + ", mSafetySourcesGroup="
+ + mSafetySourcesGroup
+ + ", mSafetyCenterIssueKey="
+ + toUserFriendlyString(mSafetyCenterIssueKey)
+ + '}';
+ }
+}
diff --git a/service/java/com/android/safetycenter/SafetySourceKey.java b/service/java/com/android/safetycenter/SafetySourceKey.java
new file mode 100644
index 000000000..511fbef73
--- /dev/null
+++ b/service/java/com/android/safetycenter/SafetySourceKey.java
@@ -0,0 +1,79 @@
+/*
+ * 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;
+
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import android.annotation.UserIdInt;
+import android.safetycenter.SafetySourceData;
+
+import androidx.annotation.RequiresApi;
+
+import java.util.Objects;
+
+/**
+ * A key to identify a safety source providing {@link SafetySourceData}; based on the {@code
+ * sourceId} and {@code userId}.
+ *
+ * @hide
+ */
+// TODO(b/219697341): Look into using AutoValue for this data class.
+@RequiresApi(TIRAMISU)
+public final class SafetySourceKey {
+
+ private final String mSourceId;
+ @UserIdInt private final int mUserId;
+
+ private SafetySourceKey(String sourceId, @UserIdInt int userId) {
+ mSourceId = sourceId;
+ mUserId = userId;
+ }
+
+ /** Creates a {@link SafetySourceKey} for the given {@code sourceId} and {@code userId}. */
+ public static SafetySourceKey of(String sourceId, @UserIdInt int userId) {
+ return new SafetySourceKey(sourceId, userId);
+ }
+
+ /** Returns the source id of this {@link SafetySourceKey}. */
+ public String getSourceId() {
+ return mSourceId;
+ }
+
+ /** Returns the user id of this {@link SafetySourceKey}. */
+ @UserIdInt
+ public int getUserId() {
+ return mUserId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SafetySourceKey)) return false;
+ SafetySourceKey safetySourceKey = (SafetySourceKey) o;
+ return mSourceId.equals(safetySourceKey.mSourceId) && mUserId == safetySourceKey.mUserId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSourceId, mUserId);
+ }
+
+ @Override
+ public String toString() {
+ return "SafetySourceKey{" + "mSourceId='" + mSourceId + "', mUserId=" + mUserId + '}';
+ }
+}
diff --git a/service/java/com/android/safetycenter/SafetySources.java b/service/java/com/android/safetycenter/SafetySources.java
new file mode 100644
index 000000000..c0b0bdc48
--- /dev/null
+++ b/service/java/com/android/safetycenter/SafetySources.java
@@ -0,0 +1,114 @@
+/*
+ * 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;
+
+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";
+
+ /**
+ * Returns whether a {@link SafetySource} is external, i.e. if {@link SafetySourceData} can be
+ * provided for it.
+ */
+ public static boolean isExternal(SafetySource safetySource) {
+ int safetySourceType = safetySource.getType();
+ switch (safetySourceType) {
+ case SafetySource.SAFETY_SOURCE_TYPE_STATIC:
+ return false;
+ case SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC:
+ case SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY:
+ return true;
+ }
+ Log.w(TAG, "Unexpected safety source type: " + safetySourceType);
+ return false;
+ }
+
+ /** Returns whether a {@link SafetySource} supports managed profiles. */
+ public static boolean supportsManagedProfiles(SafetySource safetySource) {
+ int safetySourceProfile = safetySource.getProfile();
+ switch (safetySourceProfile) {
+ case SafetySource.PROFILE_PRIMARY:
+ case SafetySource.PROFILE_NONE:
+ return false;
+ case SafetySource.PROFILE_ALL:
+ return true;
+ }
+ Log.w(TAG, "Unexpected safety source profile: " + safetySourceProfile);
+ return false;
+ }
+
+ /** Returns whether a {@link SafetySource} default entry should be hidden in the UI. */
+ static boolean isDefaultEntryHidden(SafetySource safetySource) {
+ int safetySourceType = safetySource.getType();
+ switch (safetySourceType) {
+ case SafetySource.SAFETY_SOURCE_TYPE_STATIC:
+ case SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY:
+ return false;
+ case SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC:
+ return safetySource.getInitialDisplayState()
+ == SafetySource.INITIAL_DISPLAY_STATE_HIDDEN;
+ }
+ Log.w(TAG, "Unexpected safety source type: " + safetySourceType);
+ return false;
+ }
+
+ /** Returns whether a {@link SafetySource} default entry should be disabled in the UI. */
+ static boolean isDefaultEntryDisabled(SafetySource safetySource) {
+ int safetySourceType = safetySource.getType();
+ switch (safetySourceType) {
+ case SafetySource.SAFETY_SOURCE_TYPE_STATIC:
+ case SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY:
+ return false;
+ case SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC:
+ return safetySource.getInitialDisplayState()
+ == SafetySource.INITIAL_DISPLAY_STATE_DISABLED;
+ }
+ Log.w(TAG, "Unexpected safety source type: " + safetySourceType);
+ return false;
+ }
+
+ /**
+ * Returns whether a {@link SafetySource} can be logged, without requiring a check of source
+ * type first.
+ */
+ public static boolean isLoggable(SafetySource safetySource) {
+ // Only external sources can have logging allowed values. Non-external sources cannot have
+ // their loggability configured. Unfortunately isLoggingAllowed throws if called on a
+ // non-external source.
+ if (isExternal(safetySource)) {
+ return safetySource.isLoggingAllowed();
+ } else {
+ return true;
+ }
+ }
+
+ private SafetySources() {}
+}
diff --git a/service/java/com/android/safetycenter/SafetySourcesGroups.java b/service/java/com/android/safetycenter/SafetySourcesGroups.java
new file mode 100644
index 000000000..5233302aa
--- /dev/null
+++ b/service/java/com/android/safetycenter/SafetySourcesGroups.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package 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 {
+
+ /**
+ * Returns a builder with all fields of the original group copied other than {@link
+ * SafetySourcesGroup#getSafetySources()}.
+ */
+ static SafetySourcesGroup.Builder copyToBuilderWithoutSources(SafetySourcesGroup group) {
+ SafetySourcesGroup.Builder safetySourcesGroupBuilder =
+ new SafetySourcesGroup.Builder()
+ .setId(group.getId())
+ .setTitleResId(group.getTitleResId())
+ .setSummaryResId(group.getSummaryResId())
+ .setStatelessIconType(group.getStatelessIconType());
+ if (SdkLevel.isAtLeastU()) {
+ safetySourcesGroupBuilder.setType(group.getType());
+ }
+ return safetySourcesGroupBuilder;
+ }
+
+ private SafetySourcesGroups() {}
+}
diff --git a/service/java/com/android/safetycenter/TEST_MAPPING b/service/java/com/android/safetycenter/TEST_MAPPING
index 3985e563c..3cad386bc 100644
--- a/service/java/com/android/safetycenter/TEST_MAPPING
+++ b/service/java/com/android/safetycenter/TEST_MAPPING
@@ -1,7 +1,7 @@
{
- "presubmit": [
+ "imports": [
{
- "name": "CtsSafetyCenterTestCases"
+ "path": "packages/modules/Permission/SafetyCenter"
}
]
}
diff --git a/service/java/com/android/safetycenter/UserProfileGroup.java b/service/java/com/android/safetycenter/UserProfileGroup.java
new file mode 100644
index 000000000..8d3adc573
--- /dev/null
+++ b/service/java/com/android/safetycenter/UserProfileGroup.java
@@ -0,0 +1,297 @@
+/*
+ * 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;
+
+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;
+import android.os.Binder;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.permission.util.UserUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A class that represent all the enabled profiles (profile parent and managed profile(s))
+ * associated with a user id.
+ *
+ * @hide
+ */
+@RequiresApi(TIRAMISU)
+public final class UserProfileGroup {
+
+ private static final String TAG = "UserProfileGroup";
+
+ @UserIdInt private final int mProfileParentUserId;
+ private final int[] mManagedProfilesUserIds;
+ private final int[] mManagedRunningProfilesUserIds;
+
+ private UserProfileGroup(
+ @UserIdInt int profileParentUserId,
+ int[] managedProfilesUserIds,
+ int[] managedRunningProfilesUserIds) {
+ mProfileParentUserId = profileParentUserId;
+ mManagedProfilesUserIds = managedProfilesUserIds;
+ mManagedRunningProfilesUserIds = managedRunningProfilesUserIds;
+ }
+
+ /** Returns all the alive {@link UserProfileGroup}s. */
+ public static List<UserProfileGroup> getAllUserProfileGroups(Context context) {
+ List<UserProfileGroup> userProfileGroups = new ArrayList<>();
+ List<UserHandle> userHandles = UserUtils.getUserHandles(context);
+ for (int i = 0; i < userHandles.size(); i++) {
+ UserHandle userHandle = userHandles.get(i);
+ int userId = userHandle.getIdentifier();
+
+ if (userProfileGroupsContain(userProfileGroups, userId)) {
+ continue;
+ }
+
+ UserProfileGroup userProfileGroup = UserProfileGroup.fromUser(context, userId);
+ if (!userProfileGroup.contains(userId)) {
+ continue;
+ }
+
+ userProfileGroups.add(userProfileGroup);
+ }
+ return userProfileGroups;
+ }
+
+ private static boolean userProfileGroupsContain(
+ List<UserProfileGroup> userProfileGroups, @UserIdInt int userId) {
+ for (int i = 0; i < userProfileGroups.size(); i++) {
+ UserProfileGroup userProfileGroup = userProfileGroups.get(i);
+
+ if (userProfileGroup.contains(userId)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the {@link UserProfileGroup} associated with the given {@code userId}.
+ *
+ * <p>The given {@code userId} could be related to the profile parent or any of its associated
+ * profile(s).
+ *
+ * <p>It is possible for the {@code userId} to not be contained within the returned {@link
+ * UserProfileGroup}. This can happen if the {@code userId} is a profile that is not managed or
+ * is disabled.
+ */
+ public static UserProfileGroup fromUser(Context context, @UserIdInt int userId) {
+ UserManager userManager = getUserManagerForUser(userId, context);
+ List<UserHandle> userProfiles = getEnabledUserProfiles(userManager);
+ UserHandle profileParent = getProfileParent(userManager, userId);
+ int profileParentUserId = userId;
+ if (profileParent != null) {
+ profileParentUserId = profileParent.getIdentifier();
+ }
+
+ int[] managedProfilesUserIds = new int[userProfiles.size()];
+ int[] managedRunningProfilesUserIds = new int[userProfiles.size()];
+ int managedProfilesUserIdsLen = 0;
+ int managedRunningProfilesUserIdsLen = 0;
+ for (int i = 0; i < userProfiles.size(); i++) {
+ UserHandle userProfileHandle = userProfiles.get(i);
+ int userProfileId = userProfileHandle.getIdentifier();
+
+ if (UserUtils.isManagedProfile(userProfileId, context)) {
+ managedProfilesUserIds[managedProfilesUserIdsLen++] = userProfileId;
+ if (UserUtils.isProfileRunning(userProfileId, context)) {
+ managedRunningProfilesUserIds[managedRunningProfilesUserIdsLen++] =
+ userProfileId;
+ }
+ }
+ }
+
+ UserProfileGroup userProfileGroup =
+ new UserProfileGroup(
+ profileParentUserId,
+ Arrays.copyOf(managedProfilesUserIds, managedProfilesUserIdsLen),
+ Arrays.copyOf(
+ managedRunningProfilesUserIds, managedRunningProfilesUserIdsLen));
+ if (!userProfileGroup.contains(userId)) {
+ Log.w(
+ TAG,
+ "User id " + userId + " does not belong to " + userProfileGroup,
+ new Exception());
+ }
+ return userProfileGroup;
+ }
+
+ /** Returns whether the given {@code userId} is supported by {@link UserProfileGroup}. */
+ public static boolean isSupported(@UserIdInt int userId, Context context) {
+ if (!isProfile(userId, context)) {
+ return true;
+ }
+ return UserUtils.isManagedProfile(userId, context);
+ }
+
+ private static UserManager getUserManagerForUser(@UserIdInt int userId, Context context) {
+ Context userContext = getUserContext(context, UserHandle.of(userId));
+ return requireNonNull(userContext.getSystemService(UserManager.class));
+ }
+
+ private static Context getUserContext(Context context, UserHandle userHandle) {
+ if (Process.myUserHandle().equals(userHandle)) {
+ return context;
+ } else {
+ try {
+ return context.createPackageContextAsUser(context.getPackageName(), 0, userHandle);
+ } catch (PackageManager.NameNotFoundException doesNotHappen) {
+ throw new IllegalStateException(doesNotHappen);
+ }
+ }
+ }
+
+ private static boolean isProfile(@UserIdInt int userId, Context context) {
+ // This call requires the INTERACT_ACROSS_USERS permission.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ UserManager userManager = getUserManagerForUser(userId, context);
+ return userManager.isProfile();
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ private static List<UserHandle> getEnabledUserProfiles(UserManager userManager) {
+ // This call requires the QUERY_USERS permission.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ return userManager.getUserProfiles();
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ @Nullable
+ private static UserHandle getProfileParent(UserManager userManager, @UserIdInt int userId) {
+ // This call requires the INTERACT_ACROSS_USERS permission.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ return userManager.getProfileParent(UserHandle.of(userId));
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ /** Returns the profile parent user id of the {@link UserProfileGroup}. */
+ public int getProfileParentUserId() {
+ return mProfileParentUserId;
+ }
+
+ /** Returns the managed profile user ids of the {@link UserProfileGroup}. */
+ public int[] getManagedProfilesUserIds() {
+ return mManagedProfilesUserIds;
+ }
+
+ /** Returns the running managed profile user ids of the {@link UserProfileGroup}. */
+ public int[] getManagedRunningProfilesUserIds() {
+ return mManagedRunningProfilesUserIds;
+ }
+
+ /**
+ * Convenience method that combines the results of {@link
+ * UserProfileGroup#getProfileParentUserId()} and {@link
+ * UserProfileGroup#getManagedRunningProfilesUserIds()}.
+ */
+ public int[] getProfileParentAndManagedRunningProfilesUserIds() {
+ int[] profileParentAndManagedRunningProfilesUserIds =
+ new int[mManagedRunningProfilesUserIds.length + 1];
+ profileParentAndManagedRunningProfilesUserIds[0] = mProfileParentUserId;
+ System.arraycopy(
+ mManagedRunningProfilesUserIds,
+ 0,
+ profileParentAndManagedRunningProfilesUserIds,
+ 1,
+ mManagedRunningProfilesUserIds.length);
+ return profileParentAndManagedRunningProfilesUserIds;
+ }
+
+ /** Returns whether the {@link UserProfileGroup} contains the given {@code userId}. */
+ public boolean contains(@UserIdInt int userId) {
+ if (userId == mProfileParentUserId) {
+ return true;
+ }
+
+ for (int i = 0; i < mManagedProfilesUserIds.length; i++) {
+ if (userId == mManagedProfilesUserIds[i]) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /** Returns whether the given {@code userId} is associated with a running managed profile. */
+ boolean isManagedUserRunning(@UserIdInt int userId) {
+ for (int i = 0; i < mManagedRunningProfilesUserIds.length; i++) {
+ if (userId == mManagedRunningProfilesUserIds[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof UserProfileGroup)) return false;
+ UserProfileGroup that = (UserProfileGroup) o;
+ return mProfileParentUserId == that.mProfileParentUserId
+ && Arrays.equals(mManagedProfilesUserIds, that.mManagedProfilesUserIds)
+ && Arrays.equals(
+ mManagedRunningProfilesUserIds, that.mManagedRunningProfilesUserIds);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mProfileParentUserId,
+ Arrays.hashCode(mManagedProfilesUserIds),
+ Arrays.hashCode(mManagedRunningProfilesUserIds));
+ }
+
+ @Override
+ public String toString() {
+ return "UserProfileGroup{"
+ + "mProfileParentUserId="
+ + mProfileParentUserId
+ + ", mManagedProfilesUserIds="
+ + Arrays.toString(mManagedProfilesUserIds)
+ + ", mManagedRunningProfilesUserIds="
+ + Arrays.toString(mManagedRunningProfilesUserIds)
+ + '}';
+ }
+}
diff --git a/service/java/com/android/safetycenter/data/AndroidLockScreenFix.java b/service/java/com/android/safetycenter/data/AndroidLockScreenFix.java
new file mode 100644
index 000000000..5db3cfbad
--- /dev/null
+++ b/service/java/com/android/safetycenter/data/AndroidLockScreenFix.java
@@ -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.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;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.safetycenter.SafetyCenterEntry;
+import android.safetycenter.SafetySourceData;
+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;
+
+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";
+
+ private static final String ANDROID_LOCK_SCREEN_SOURCE_ID = "AndroidLockScreen";
+ private static final int SUSPECT_REQ_CODE = 0;
+ // Arbitrary values to construct PendingIntents that are guaranteed not to be equal due to
+ // these request codes not being equal. The values match the ones in Settings QPR, in case we
+ // ever end up using these request codes in QPR.
+ private static final int ANDROID_LOCK_SCREEN_ENTRY_REQ_CODE = 1;
+ private static final int ANDROID_LOCK_SCREEN_ICON_ACTION_REQ_CODE = 2;
+
+ private AndroidLockScreenFix() {}
+
+ /**
+ * Potentially 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
+ * SafetyCenterEntry.IconAction#getPendingIntent()}. The reason for this is that {@link
+ * PendingIntent} instances are cached and keyed by an object which does not take into account
+ * the underlying {@link Intent} extras; and these two {@link Intent}s only differ by the extras
+ * that they set.
+ *
+ * <p>We fix this issue by recreating the desired {@link PendingIntent}s manually here, using
+ * 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);
+ }
+
+ 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));
+ }
+ List<SafetySourceIssue> safetySourceIssues = safetySourceData.getIssues();
+ for (int i = 0; i < safetySourceIssues.size(); i++) {
+ SafetySourceIssue safetySourceIssue = safetySourceIssues.get(i);
+ overriddenSafetySourceData.addIssue(
+ overrideTiramisuSafetySourceIssue(context, safetySourceIssue));
+ }
+ return overriddenSafetySourceData.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();
+ if (iconAction != null) {
+ overriddenSafetySourceStatus.setIconAction(
+ overrideTiramisuSafetySourceStatusIconAction(
+ context, safetySourceStatus.getIconAction()));
+ }
+ return overriddenSafetySourceStatus.build();
+ }
+
+ private static SafetySourceStatus.IconAction overrideTiramisuSafetySourceStatusIconAction(
+ Context context, SafetySourceStatus.IconAction iconAction) {
+ return new SafetySourceStatus.IconAction(
+ iconAction.getIconType(),
+ overridePendingIntent(context, iconAction.getPendingIntent(), 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();
+ for (int i = 0; i < actions.size(); i++) {
+ SafetySourceIssue.Action action = actions.get(i);
+ overriddenSafetySourceIssue.addAction(
+ overrideTiramisuSafetySourceIssueAction(context, action));
+ }
+ return overriddenSafetySourceIssue.build();
+ }
+
+ private static SafetySourceIssue.Action overrideTiramisuSafetySourceIssueAction(
+ 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();
+ }
+
+ @Nullable
+ private static PendingIntent overridePendingIntent(
+ Context context, @Nullable PendingIntent pendingIntent, boolean isIconAction) {
+ if (pendingIntent == null) {
+ return null;
+ }
+ String settingsPackageName = pendingIntent.getCreatorPackage();
+ int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
+ Context settingsPackageContext =
+ PendingIntentFactory.createPackageContextAsUser(
+ context, settingsPackageName, userId);
+ if (settingsPackageContext == null) {
+ return pendingIntent;
+ }
+ if (hasFixedSettingsIssue(settingsPackageContext)) {
+ return pendingIntent;
+ }
+ PendingIntent suspectPendingIntent =
+ PendingIntentFactory.getNullableActivityPendingIntent(
+ settingsPackageContext,
+ SUSPECT_REQ_CODE,
+ newBaseLockScreenIntent(settingsPackageName),
+ PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_NO_CREATE);
+ if (suspectPendingIntent == null) {
+ // Nothing was cached.
+ return pendingIntent;
+ }
+ if (!suspectPendingIntent.equals(pendingIntent)) {
+ // The pending intent is not hitting this caching issue, so we should skip the override.
+ return pendingIntent;
+ }
+ // We’re most likely hitting the caching issue described in this method’s documentation, so
+ // we should ensure we create brand new pending intents where applicable by using different
+ // request codes. We only perform this override for the applicable pending intents.
+ // 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(
+ TAG,
+ "Replacing " + ANDROID_LOCK_SCREEN_SOURCE_ID + " icon action pending intent");
+ return PendingIntentFactory.getActivityPendingIntent(
+ settingsPackageContext,
+ ANDROID_LOCK_SCREEN_ICON_ACTION_REQ_CODE,
+ newLockScreenIconActionIntent(settingsPackageName),
+ PendingIntent.FLAG_IMMUTABLE);
+ }
+ Log.w(TAG, "Replacing " + ANDROID_LOCK_SCREEN_SOURCE_ID + " entry or issue pending intent");
+ return PendingIntentFactory.getActivityPendingIntent(
+ settingsPackageContext,
+ ANDROID_LOCK_SCREEN_ENTRY_REQ_CODE,
+ newLockScreenIntent(settingsPackageName),
+ PendingIntent.FLAG_IMMUTABLE);
+ }
+
+ private static boolean hasFixedSettingsIssue(Context settingsPackageContext) {
+ Resources settingsResources = settingsPackageContext.getResources();
+ int hasSettingsFixedIssueResourceId =
+ settingsResources.getIdentifier(
+ "config_isSafetyCenterLockScreenPendingIntentFixed",
+ "bool",
+ settingsPackageContext.getPackageName());
+ if (hasSettingsFixedIssueResourceId != Resources.ID_NULL) {
+ return settingsResources.getBoolean(hasSettingsFixedIssueResourceId);
+ }
+ return false;
+ }
+
+ private static Intent newBaseLockScreenIntent(String settingsPackageName) {
+ return new Intent(Intent.ACTION_MAIN)
+ .setComponent(
+ new ComponentName(
+ settingsPackageName, settingsPackageName + ".SubSettings"))
+ .putExtra(":settings:source_metrics", 1917);
+ }
+
+ private static Intent newLockScreenIntent(String settingsPackageName) {
+ String targetFragment =
+ settingsPackageName + ".password.ChooseLockGeneric$ChooseLockGenericFragment";
+ return newBaseLockScreenIntent(settingsPackageName)
+ .putExtra(":settings:show_fragment", targetFragment)
+ .putExtra("page_transition_type", 1);
+ }
+
+ private static Intent newLockScreenIconActionIntent(String settingsPackageName) {
+ String targetFragment = settingsPackageName + ".security.screenlock.ScreenLockSettings";
+ return newBaseLockScreenIntent(settingsPackageName)
+ .putExtra(":settings:show_fragment", targetFragment)
+ .putExtra("page_transition_type", 0);
+ }
+}
diff --git a/service/java/com/android/safetycenter/data/SafetyCenterDataManager.java b/service/java/com/android/safetycenter/data/SafetyCenterDataManager.java
new file mode 100644
index 000000000..734732401
--- /dev/null
+++ b/service/java/com/android/safetycenter/data/SafetyCenterDataManager.java
@@ -0,0 +1,536 @@
+/*
+ * 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.TIRAMISU;
+
+import static com.android.safetycenter.logging.SafetyCenterStatsdLogger.toSystemEventResult;
+
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.Context;
+import android.safetycenter.SafetyCenterData;
+import android.safetycenter.SafetyEvent;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceErrorDetails;
+import android.safetycenter.SafetySourceIssue;
+import android.safetycenter.config.SafetyCenterConfig;
+import android.safetycenter.config.SafetySourcesGroup;
+import android.util.Log;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.safetycenter.ApiLock;
+import com.android.safetycenter.SafetyCenterConfigReader;
+import com.android.safetycenter.SafetyCenterRefreshTracker;
+import com.android.safetycenter.SafetySourceIssueInfo;
+import com.android.safetycenter.SafetySourceKey;
+import com.android.safetycenter.UserProfileGroup;
+import com.android.safetycenter.internaldata.SafetyCenterIssueActionId;
+import com.android.safetycenter.internaldata.SafetyCenterIssueKey;
+import com.android.safetycenter.logging.SafetyCenterStatsdLogger;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.time.Instant;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
+/**
+ * Manages updates and access to all data in the data subpackage.
+ *
+ * <p>Data entails what safety sources reported to safety center, including issues, entries,
+ * dismissals, errors, in-flight actions, etc.
+ *
+ * @hide
+ */
+@RequiresApi(TIRAMISU)
+@NotThreadSafe
+public final class SafetyCenterDataManager {
+
+ private static final String TAG = "SafetyCenterDataManager";
+
+ private final SafetyCenterRefreshTracker mSafetyCenterRefreshTracker;
+ private final SafetySourceDataRepository mSafetySourceDataRepository;
+ private final SafetyCenterIssueDismissalRepository mSafetyCenterIssueDismissalRepository;
+ private final SafetyCenterIssueRepository mSafetyCenterIssueRepository;
+ private final SafetyCenterInFlightIssueActionRepository
+ mSafetyCenterInFlightIssueActionRepository;
+ private final SafetySourceDataValidator mSafetySourceDataValidator;
+ private final SafetySourceStateCollectedLogger mSafetySourceStateCollectedLogger;
+
+ /** Creates an instance of {@link SafetyCenterDataManager}. */
+ public SafetyCenterDataManager(
+ Context context,
+ SafetyCenterConfigReader safetyCenterConfigReader,
+ SafetyCenterRefreshTracker safetyCenterRefreshTracker,
+ ApiLock apiLock) {
+ mSafetyCenterRefreshTracker = safetyCenterRefreshTracker;
+ mSafetyCenterInFlightIssueActionRepository =
+ new SafetyCenterInFlightIssueActionRepository(context);
+ mSafetyCenterIssueDismissalRepository =
+ new SafetyCenterIssueDismissalRepository(apiLock, safetyCenterConfigReader);
+ mSafetySourceDataRepository =
+ new SafetySourceDataRepository(
+ context,
+ mSafetyCenterInFlightIssueActionRepository,
+ mSafetyCenterIssueDismissalRepository);
+ mSafetyCenterIssueRepository =
+ new SafetyCenterIssueRepository(
+ context,
+ mSafetySourceDataRepository,
+ safetyCenterConfigReader,
+ mSafetyCenterIssueDismissalRepository,
+ new SafetyCenterIssueDeduplicator(mSafetyCenterIssueDismissalRepository));
+ mSafetySourceDataValidator =
+ new SafetySourceDataValidator(context, safetyCenterConfigReader);
+ mSafetySourceStateCollectedLogger =
+ new SafetySourceStateCollectedLogger(
+ context,
+ mSafetySourceDataRepository,
+ mSafetyCenterIssueDismissalRepository,
+ mSafetyCenterIssueRepository);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ ////////////////////// STATE UPDATES ////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * 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}.
+ *
+ * <p>Throws if the request is invalid based on the {@link SafetyCenterConfig}: the given {@code
+ * safetySourceId}, {@code packageName} and/or {@code userId} are unexpected; or the {@link
+ * SafetySourceData} does not respect all constraints defined in the config.
+ *
+ * <p>Setting a {@code null} {@link SafetySourceData} evicts the current {@link
+ * SafetySourceData} entry and clears the {@link SafetyCenterIssueDismissalRepository} for the
+ * source.
+ *
+ * <p>This method may modify the {@link SafetyCenterIssueDismissalRepository}.
+ */
+ public boolean setSafetySourceData(
+ @Nullable SafetySourceData safetySourceData,
+ String safetySourceId,
+ SafetyEvent safetyEvent,
+ String packageName,
+ @UserIdInt int userId) {
+ if (!mSafetySourceDataValidator.validateRequest(
+ safetySourceData, safetySourceId, packageName, userId)) {
+ return false;
+ }
+ SafetySourceKey key = SafetySourceKey.of(safetySourceId, userId);
+
+ // Must fetch refresh reason before calling processSafetyEvent because the latter may
+ // complete and clear the current refresh.
+ // TODO(b/277174417): Restructure this code to avoid this error-prone sequencing concern
+ Integer refreshReason = null;
+ if (safetyEvent.getType() == SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED) {
+ refreshReason = mSafetyCenterRefreshTracker.getRefreshReason();
+ }
+
+ boolean sourceDataDiffers =
+ mSafetySourceDataRepository.setSafetySourceData(
+ safetySourceData, safetySourceId, userId);
+ boolean eventCausedChange =
+ processSafetyEvent(safetySourceId, safetyEvent, userId, false, sourceDataDiffers);
+ boolean safetyCenterDataChanged = sourceDataDiffers || eventCausedChange;
+
+ if (safetyCenterDataChanged) {
+ mSafetyCenterIssueRepository.updateIssues(userId);
+ }
+
+ mSafetySourceStateCollectedLogger.writeSourceUpdatedAtom(
+ key, safetySourceData, refreshReason, sourceDataDiffers, userId, safetyEvent);
+
+ return safetyCenterDataChanged;
+ }
+
+ /**
+ * Marks the issue with the given key as dismissed.
+ *
+ * <p>That issue's notification (if any) is also marked as dismissed.
+ */
+ public void dismissSafetyCenterIssue(SafetyCenterIssueKey safetyCenterIssueKey) {
+ mSafetyCenterIssueDismissalRepository.dismissIssue(safetyCenterIssueKey);
+ mSafetyCenterIssueRepository.updateIssues(safetyCenterIssueKey.getUserId());
+ }
+
+ /**
+ * Marks the notification (if any) of the issue with the given key as dismissed.
+ *
+ * <p>The issue itself is <strong>not</strong> marked as dismissed and its warning card can
+ * still appear in the Safety Center UI.
+ */
+ public void dismissNotification(SafetyCenterIssueKey safetyCenterIssueKey) {
+ mSafetyCenterIssueDismissalRepository.dismissNotification(safetyCenterIssueKey);
+ mSafetyCenterIssueRepository.updateIssues(safetyCenterIssueKey.getUserId());
+ }
+
+ /**
+ * Reports the given {@link SafetySourceErrorDetails} for the given {@code safetySourceId} and
+ * {@code userId}, and returns whether there was a change to the underlying {@link
+ * SafetyCenterData}.
+ *
+ * <p>Throws if the request is invalid based on the {@link SafetyCenterConfig}: the given {@code
+ * safetySourceId}, {@code packageName} and/or {@code userId} are unexpected.
+ */
+ public boolean reportSafetySourceError(
+ SafetySourceErrorDetails safetySourceErrorDetails,
+ String safetySourceId,
+ String packageName,
+ @UserIdInt int userId) {
+ if (!mSafetySourceDataValidator.validateRequest(
+ null, safetySourceId, packageName, userId)) {
+ return false;
+ }
+ SafetyEvent safetyEvent = safetySourceErrorDetails.getSafetyEvent();
+ SafetySourceKey key = SafetySourceKey.of(safetySourceId, userId);
+
+ // Must fetch refresh reason before calling processSafetyEvent because the latter may
+ // complete and clear the current refresh.
+ // TODO(b/277174417): Restructure this code to avoid this error-prone sequencing concern
+ Integer refreshReason = null;
+ if (safetyEvent.getType() == SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED) {
+ refreshReason = mSafetyCenterRefreshTracker.getRefreshReason();
+ }
+
+ boolean sourceDataDiffers =
+ mSafetySourceDataRepository.reportSafetySourceError(
+ safetySourceErrorDetails, safetySourceId, userId);
+ boolean eventCausedChange =
+ processSafetyEvent(safetySourceId, safetyEvent, userId, true, sourceDataDiffers);
+ boolean safetyCenterDataChanged = sourceDataDiffers || eventCausedChange;
+
+ if (safetyCenterDataChanged) {
+ mSafetyCenterIssueRepository.updateIssues(userId);
+ }
+
+ mSafetySourceStateCollectedLogger.writeSourceUpdatedAtom(
+ key, null, refreshReason, sourceDataDiffers, userId, safetyEvent);
+
+ return safetyCenterDataChanged;
+ }
+
+ /**
+ * Marks the given {@link SafetySourceKey} as having timed out during a refresh.
+ *
+ * @param setError whether we should clear the data associated with the source and set an error
+ */
+ public void markSafetySourceRefreshTimedOut(SafetySourceKey safetySourceKey, boolean setError) {
+ boolean dataUpdated =
+ mSafetySourceDataRepository.markSafetySourceRefreshTimedOut(
+ safetySourceKey, setError);
+ if (dataUpdated) {
+ mSafetyCenterIssueRepository.updateIssues(safetySourceKey.getUserId());
+ }
+ }
+
+ /** Marks the given {@link SafetyCenterIssueActionId} as in-flight. */
+ public void markSafetyCenterIssueActionInFlight(
+ SafetyCenterIssueActionId safetyCenterIssueActionId) {
+ mSafetyCenterInFlightIssueActionRepository.markSafetyCenterIssueActionInFlight(
+ safetyCenterIssueActionId);
+ mSafetyCenterIssueRepository.updateIssues(
+ safetyCenterIssueActionId.getSafetyCenterIssueKey().getUserId());
+ }
+
+ /**
+ * Unmarks the given {@link SafetyCenterIssueActionId} as in-flight and returns {@code true} if
+ * this caused any changes which would alter {@link SafetyCenterData}.
+ *
+ * <p>Also logs an event to statsd with the given {@code result} value.
+ */
+ public boolean unmarkSafetyCenterIssueActionInFlight(
+ SafetyCenterIssueActionId safetyCenterIssueActionId,
+ @Nullable SafetySourceIssue safetySourceIssue,
+ @SafetyCenterStatsdLogger.SystemEventResult int result) {
+ boolean dataUpdated =
+ mSafetyCenterInFlightIssueActionRepository.unmarkSafetyCenterIssueActionInFlight(
+ safetyCenterIssueActionId, safetySourceIssue, result);
+ if (dataUpdated) {
+ mSafetyCenterIssueRepository.updateIssues(
+ safetyCenterIssueActionId.getSafetyCenterIssueKey().getUserId());
+ }
+ return dataUpdated;
+ }
+
+ /** Clears all data related to the given {@code userId}. */
+ public void clearForUser(@UserIdInt int userId) {
+ mSafetySourceDataRepository.clearForUser(userId);
+ mSafetyCenterInFlightIssueActionRepository.clearForUser(userId);
+ mSafetyCenterIssueDismissalRepository.clearForUser(userId);
+ mSafetyCenterIssueRepository.clearForUser(userId);
+ }
+
+ /** Clears all stored data. */
+ public void clear() {
+ mSafetySourceDataRepository.clear();
+ mSafetyCenterIssueDismissalRepository.clear();
+ mSafetyCenterInFlightIssueActionRepository.clear();
+ mSafetyCenterIssueRepository.clear();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ ////////////////////// SafetyCenterIssueDismissalRepository /////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Returns {@code true} if the issue with the given key and severity level is currently
+ * dismissed.
+ *
+ * <p>An issue which is dismissed at one time may become "un-dismissed" later, after the
+ * resurface delay (which depends on severity level) has elapsed.
+ *
+ * <p>If the given issue key is not found in the repository this method returns {@code false}.
+ */
+ public boolean isIssueDismissed(
+ SafetyCenterIssueKey safetyCenterIssueKey,
+ @SafetySourceData.SeverityLevel int safetySourceIssueSeverityLevel) {
+ return mSafetyCenterIssueDismissalRepository.isIssueDismissed(
+ safetyCenterIssueKey, safetySourceIssueSeverityLevel);
+ }
+
+ /** Returns {@code true} if an issue's notification is dismissed now. */
+ // TODO(b/259084807): Consider extracting notification dismissal logic to separate class
+ public boolean isNotificationDismissedNow(
+ SafetyCenterIssueKey issueKey, @SafetySourceData.SeverityLevel int severityLevel) {
+ return mSafetyCenterIssueDismissalRepository.isNotificationDismissedNow(
+ issueKey, severityLevel);
+ }
+
+ /**
+ * Load available persisted data state into memory.
+ *
+ * <p>Note: only some pieces of the data can be persisted, the rest won't be loaded.
+ */
+ public void loadPersistableDataStateFromFile() {
+ mSafetyCenterIssueDismissalRepository.loadStateFromFile();
+ }
+
+ /**
+ * Returns the {@link Instant} when the issue with the given key was first reported to Safety
+ * Center.
+ */
+ @Nullable
+ public Instant getIssueFirstSeenAt(SafetyCenterIssueKey safetyCenterIssueKey) {
+ return mSafetyCenterIssueDismissalRepository.getIssueFirstSeenAt(safetyCenterIssueKey);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ ////////////////////// SafetyCenterIssueRepository /////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Fetches a list of issues related to the given {@link UserProfileGroup}.
+ *
+ * <p>Issues in the list are sorted in descending order and deduplicated (if applicable, only on
+ * Android U+).
+ *
+ * <p>Only includes issues related to active/running {@code userId}s in the given {@link
+ * UserProfileGroup}.
+ */
+ public List<SafetySourceIssueInfo> getIssuesDedupedSortedDescFor(
+ UserProfileGroup userProfileGroup) {
+ return mSafetyCenterIssueRepository.getIssuesDedupedSortedDescFor(userProfileGroup);
+ }
+
+ /**
+ * Counts the total number of issues from loggable sources, in the given {@link
+ * UserProfileGroup}.
+ *
+ * <p>Only includes issues related to active/running {@code userId}s in the given {@link
+ * UserProfileGroup}.
+ */
+ public int countLoggableIssuesFor(UserProfileGroup userProfileGroup) {
+ return mSafetyCenterIssueRepository.countLoggableIssuesFor(userProfileGroup);
+ }
+
+ /** Gets an unmodifiable list of all issues for the given {@code userId}. */
+ public List<SafetySourceIssueInfo> getIssuesForUser(@UserIdInt int userId) {
+ return mSafetyCenterIssueRepository.getIssuesForUser(userId);
+ }
+
+ /**
+ * Returns a set of {@link SafetySourcesGroup} IDs that the given {@link SafetyCenterIssueKey}
+ * is mapped to, or an empty list of no such mapping is configured.
+ *
+ * <p>Issue being mapped to a group means that this issue is relevant to that group.
+ */
+ public Set<String> getGroupMappingFor(SafetyCenterIssueKey issueKey) {
+ return mSafetyCenterIssueRepository.getGroupMappingFor(issueKey);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ ////////////////////// SafetyCenterInFlightIssueActionRepository ////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /** Returns {@code true} if the given issue action is in flight. */
+ public boolean actionIsInFlight(SafetyCenterIssueActionId safetyCenterIssueActionId) {
+ return mSafetyCenterInFlightIssueActionRepository.actionIsInFlight(
+ safetyCenterIssueActionId);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ ////////////////////// SafetySourceDataRepository ///////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Returns the latest {@link SafetySourceData} that was set by {@link #setSafetySourceData} for
+ * the given {@code safetySourceId}, {@code packageName} and {@code userId}.
+ *
+ * <p>Throws if the request is invalid based on the {@link SafetyCenterConfig}: the given {@code
+ * safetySourceId}, {@code packageName} and/or {@code userId} are unexpected.
+ *
+ * <p>Returns {@code null} if it was never set since boot, or if the entry was evicted using
+ * {@link #setSafetySourceData} with a {@code null} value.
+ */
+ @Nullable
+ public SafetySourceData getSafetySourceData(
+ String safetySourceId, String packageName, @UserIdInt int userId) {
+ if (!mSafetySourceDataValidator.validateRequest(
+ null, safetySourceId, packageName, userId)) {
+ return null;
+ }
+ return mSafetySourceDataRepository.getSafetySourceData(
+ SafetySourceKey.of(safetySourceId, userId));
+ }
+
+ /**
+ * Returns the latest {@link SafetySourceData} that was set by {@link #setSafetySourceData} for
+ * the given {@link SafetySourceKey}.
+ *
+ * <p>This method does not perform any validation, {@link #getSafetySourceData(String, String,
+ * int)} should be called wherever validation is required.
+ *
+ * <p>Returns {@code null} if it was never set since boot, or if the entry was evicted using
+ * {@link #setSafetySourceData} with a {@code null} value.
+ */
+ @Nullable
+ public SafetySourceData getSafetySourceDataInternal(SafetySourceKey safetySourceKey) {
+ return mSafetySourceDataRepository.getSafetySourceData(safetySourceKey);
+ }
+
+ /** Returns {@code true} if the given source has an error. */
+ public boolean sourceHasError(SafetySourceKey safetySourceKey) {
+ return mSafetySourceDataRepository.sourceHasError(safetySourceKey);
+ }
+
+ /**
+ * Returns the {@link SafetySourceIssue} associated with the given {@link SafetyCenterIssueKey}.
+ *
+ * <p>Returns {@code null} if there is no such {@link SafetySourceIssue}.
+ */
+ @Nullable
+ public SafetySourceIssue getSafetySourceIssue(SafetyCenterIssueKey safetyCenterIssueKey) {
+ return mSafetySourceDataRepository.getSafetySourceIssue(safetyCenterIssueKey);
+ }
+
+ /**
+ * Returns the {@link SafetySourceIssue.Action} associated with the given {@link
+ * SafetyCenterIssueActionId}.
+ *
+ * <p>Returns {@code null} if there is no associated {@link SafetySourceIssue}, or if it's been
+ * dismissed.
+ *
+ * <p>Returns {@code null} if the {@link SafetySourceIssue.Action} is currently in flight.
+ */
+ @Nullable
+ public SafetySourceIssue.Action getSafetySourceIssueAction(
+ SafetyCenterIssueActionId safetyCenterIssueActionId) {
+ return mSafetySourceDataRepository.getSafetySourceIssueAction(safetyCenterIssueActionId);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ //////////////////////////// Other /////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /** Dumps state for debugging purposes. */
+ public void dump(FileDescriptor fd, PrintWriter fout) {
+ mSafetySourceDataRepository.dump(fout);
+ mSafetyCenterIssueDismissalRepository.dump(fd, fout);
+ mSafetyCenterInFlightIssueActionRepository.dump(fout);
+ mSafetyCenterIssueRepository.dump(fout);
+ }
+
+ private boolean processSafetyEvent(
+ String safetySourceId,
+ SafetyEvent safetyEvent,
+ @UserIdInt int userId,
+ boolean isError,
+ boolean sourceDataChanged) {
+ 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);
+ return false;
+ }
+ return mSafetyCenterRefreshTracker.reportSourceRefreshCompleted(
+ refreshBroadcastId, safetySourceId, userId, !isError, sourceDataChanged);
+ 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);
+ return false;
+ }
+ String safetySourceIssueActionId = safetyEvent.getSafetySourceIssueActionId();
+ if (safetySourceIssueActionId == null) {
+ Log.w(TAG, "No safety source issue action id in SafetyEvent of type " + type);
+ return false;
+ }
+ SafetyCenterIssueKey safetyCenterIssueKey =
+ SafetyCenterIssueKey.newBuilder()
+ .setSafetySourceId(safetySourceId)
+ .setSafetySourceIssueId(safetySourceIssueId)
+ .setUserId(userId)
+ .build();
+ SafetyCenterIssueActionId safetyCenterIssueActionId =
+ SafetyCenterIssueActionId.newBuilder()
+ .setSafetyCenterIssueKey(safetyCenterIssueKey)
+ .setSafetySourceIssueActionId(safetySourceIssueActionId)
+ .build();
+ boolean success = type == SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED;
+ int result = toSystemEventResult(success);
+ return mSafetyCenterInFlightIssueActionRepository
+ .unmarkSafetyCenterIssueActionInFlight(
+ safetyCenterIssueActionId,
+ getSafetySourceIssue(safetyCenterIssueKey),
+ result);
+ case SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED:
+ case SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED:
+ case SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED:
+ return false;
+ }
+ Log.w(TAG, "Unexpected SafetyEvent.Type: " + type);
+ return false;
+ }
+
+ /**
+ * Writes a SafetySourceStateCollected atom for the given source in response to a stats pull.
+ */
+ public void logSafetySourceStateCollectedAutomatic(
+ SafetySourceKey sourceKey, boolean isManagedProfile) {
+ mSafetySourceStateCollectedLogger.writeAutomaticAtom(sourceKey, isManagedProfile);
+ }
+}
diff --git a/service/java/com/android/safetycenter/data/SafetyCenterInFlightIssueActionRepository.java b/service/java/com/android/safetycenter/data/SafetyCenterInFlightIssueActionRepository.java
new file mode 100644
index 000000000..4fa6e5363
--- /dev/null
+++ b/service/java/com/android/safetycenter/data/SafetyCenterInFlightIssueActionRepository.java
@@ -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.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.Log;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.permission.util.UserUtils;
+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 {
+
+ private static final String TAG = "SafetyCenterInFlight";
+
+ private final ArrayMap<SafetyCenterIssueActionId, Long> mSafetyCenterIssueActionsInFlight =
+ new ArrayMap<>();
+
+ private final Context mContext;
+
+ /** Constructs a new instance of {@link SafetyCenterInFlightIssueActionRepository}. */
+ SafetyCenterInFlightIssueActionRepository(Context context) {
+ mContext = context;
+ }
+
+ /** Marks the given {@link SafetyCenterIssueActionId} as in-flight. */
+ void markSafetyCenterIssueActionInFlight(SafetyCenterIssueActionId safetyCenterIssueActionId) {
+ mSafetyCenterIssueActionsInFlight.put(
+ safetyCenterIssueActionId, SystemClock.elapsedRealtime());
+ }
+
+ /**
+ * Unmarks the given {@link SafetyCenterIssueActionId} as in-flight and returns {@code true} if
+ * the given action was valid and unmarked successfully.
+ *
+ * <p>Also logs an event to statsd with the given {@code result} value.
+ */
+ boolean unmarkSafetyCenterIssueActionInFlight(
+ SafetyCenterIssueActionId safetyCenterIssueActionId,
+ @Nullable SafetySourceIssue safetySourceIssue,
+ @SafetyCenterStatsdLogger.SystemEventResult int result) {
+ Long startElapsedMillis =
+ mSafetyCenterIssueActionsInFlight.remove(safetyCenterIssueActionId);
+ if (startElapsedMillis == null) {
+ Log.w(
+ TAG,
+ "Attempt to unmark unknown in-flight action: "
+ + toUserFriendlyString(safetyCenterIssueActionId));
+ return false;
+ }
+
+ SafetyCenterIssueKey issueKey = safetyCenterIssueActionId.getSafetyCenterIssueKey();
+ String issueTypeId = safetySourceIssue == null ? null : safetySourceIssue.getIssueTypeId();
+ Duration duration = Duration.ofMillis(SystemClock.elapsedRealtime() - startElapsedMillis);
+
+ SafetyCenterStatsdLogger.writeInlineActionSystemEvent(
+ issueKey.getSafetySourceId(),
+ UserUtils.isManagedProfile(issueKey.getUserId(), mContext),
+ issueTypeId,
+ duration,
+ result);
+
+ if (safetySourceIssue == null
+ || getSafetySourceIssueAction(safetyCenterIssueActionId, safetySourceIssue)
+ == null) {
+ Log.w(
+ TAG,
+ "Attempt to unmark in-flight action for a non-existent issue or action: "
+ + toUserFriendlyString(safetyCenterIssueActionId));
+ return false;
+ }
+
+ return true;
+ }
+
+ /** Returns {@code true} if the given issue action is in flight. */
+ boolean actionIsInFlight(SafetyCenterIssueActionId safetyCenterIssueActionId) {
+ return mSafetyCenterIssueActionsInFlight.containsKey(safetyCenterIssueActionId);
+ }
+
+ /**
+ * Returns {@link SafetySourceIssue.Action} identified by the given {@link
+ * SafetyCenterIssueActionId} and {@link SafetySourceIssue}.
+ */
+ @Nullable
+ SafetySourceIssue.Action getSafetySourceIssueAction(
+ SafetyCenterIssueActionId safetyCenterIssueActionId,
+ SafetySourceIssue safetySourceIssue) {
+ if (actionIsInFlight(safetyCenterIssueActionId)) {
+ 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;
+ }
+
+ /** Dumps in-flight action data for debugging purposes. */
+ void dump(PrintWriter fout) {
+ int actionInFlightCount = mSafetyCenterIssueActionsInFlight.size();
+ fout.println("ACTIONS IN FLIGHT (" + actionInFlightCount + ")");
+ for (int i = 0; i < actionInFlightCount; i++) {
+ String printableId = toUserFriendlyString(mSafetyCenterIssueActionsInFlight.keyAt(i));
+ long startElapsedMillis = mSafetyCenterIssueActionsInFlight.valueAt(i);
+ long durationMillis = SystemClock.elapsedRealtime() - startElapsedMillis;
+ fout.println("\t[" + i + "] " + printableId + "(duration=" + durationMillis + "ms)");
+ }
+ fout.println();
+ }
+
+ /** Clears all in-flight action data. */
+ void clear() {
+ mSafetyCenterIssueActionsInFlight.clear();
+ }
+
+ /** Clears in-flight action data for given {@code userId}. */
+ void clearForUser(@UserIdInt int userId) {
+ // Loop in reverse index order to be able to remove entries while iterating.
+ for (int i = mSafetyCenterIssueActionsInFlight.size() - 1; i >= 0; i--) {
+ SafetyCenterIssueActionId issueActionId = mSafetyCenterIssueActionsInFlight.keyAt(i);
+ if (issueActionId.getSafetyCenterIssueKey().getUserId() == userId) {
+ mSafetyCenterIssueActionsInFlight.removeAt(i);
+ }
+ }
+ }
+}
diff --git a/service/java/com/android/safetycenter/data/SafetyCenterIssueDeduplicator.java b/service/java/com/android/safetycenter/data/SafetyCenterIssueDeduplicator.java
new file mode 100644
index 000000000..d5218a0aa
--- /dev/null
+++ b/service/java/com/android/safetycenter/data/SafetyCenterIssueDeduplicator.java
@@ -0,0 +1,448 @@
+/*
+ * 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.TIRAMISU;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+
+import static com.android.safetycenter.internaldata.SafetyCenterIds.toUserFriendlyString;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.emptyMap;
+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.RequiresApi;
+
+import com.android.safetycenter.SafetySourceIssueInfo;
+import com.android.safetycenter.internaldata.SafetyCenterIssueKey;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+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 {
+
+ private static final String TAG = "SafetyCenterDedup";
+
+ private final SafetyCenterIssueDismissalRepository mSafetyCenterIssueDismissalRepository;
+
+ @RequiresApi(TIRAMISU)
+ SafetyCenterIssueDeduplicator(
+ SafetyCenterIssueDismissalRepository safetyCenterIssueDismissalRepository) {
+ this.mSafetyCenterIssueDismissalRepository = safetyCenterIssueDismissalRepository;
+ }
+
+ /**
+ * Accepts a list of issues sorted by priority and filters out duplicates.
+ *
+ * <p>Issues are considered duplicate if they have the same deduplication id and were sent by
+ * sources which are part of the same deduplication group. All but the highest priority
+ * duplicate issue will be filtered out.
+ *
+ * <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
+ * process
+ */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ DeduplicationInfo deduplicateIssues(List<SafetySourceIssueInfo> sortedIssues) {
+ // (dedup key) -> list(issues)
+ ArrayMap<DeduplicationKey, List<SafetySourceIssueInfo>> dedupBuckets =
+ createDedupBuckets(sortedIssues);
+
+ // There is no further work to do when there are no dedup buckets
+ if (dedupBuckets.isEmpty()) {
+ return new DeduplicationInfo(new ArrayList<>(sortedIssues), emptyList(), emptyMap());
+ }
+
+ alignAllDismissals(dedupBuckets);
+
+ ArraySet<SafetyCenterIssueKey> duplicatesToFilterOut =
+ getDuplicatesToFilterOut(dedupBuckets);
+
+ resurfaceHiddenIssuesIfNeeded(dedupBuckets);
+
+ if (duplicatesToFilterOut.isEmpty()) {
+ return new DeduplicationInfo(new ArrayList<>(sortedIssues), emptyList(), emptyMap());
+ }
+
+ ArrayMap<SafetyCenterIssueKey, Set<String>> issueToGroupMap =
+ getTopIssueToGroupMapping(dedupBuckets);
+
+ List<SafetySourceIssueInfo> filteredOut = new ArrayList<>(duplicatesToFilterOut.size());
+ List<SafetySourceIssueInfo> deduplicatedIssues = new ArrayList<>();
+ for (int i = 0; i < sortedIssues.size(); i++) {
+ SafetySourceIssueInfo issueInfo = sortedIssues.get(i);
+ SafetyCenterIssueKey issueKey = issueInfo.getSafetyCenterIssueKey();
+ if (duplicatesToFilterOut.contains(issueKey)) {
+ filteredOut.add(issueInfo);
+ // mark as temporarily hidden, which will delay showing these issues if the top
+ // issue gets resolved.
+ mSafetyCenterIssueDismissalRepository.hideIssue(issueKey);
+ } else {
+ deduplicatedIssues.add(issueInfo);
+ }
+ }
+
+ return new DeduplicationInfo(deduplicatedIssues, filteredOut, issueToGroupMap);
+ }
+
+ private void resurfaceHiddenIssuesIfNeeded(
+ ArrayMap<DeduplicationKey, List<SafetySourceIssueInfo>> dedupBuckets) {
+ 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");
+ continue;
+ }
+
+ // top issue in the bucket, if hidden, should resurface after certain period
+ SafetyCenterIssueKey topIssueKey = duplicates.get(0).getSafetyCenterIssueKey();
+ if (mSafetyCenterIssueDismissalRepository.isIssueHidden(topIssueKey)) {
+ mSafetyCenterIssueDismissalRepository.resurfaceHiddenIssueAfterPeriod(topIssueKey);
+ }
+ }
+ }
+
+ /**
+ * Creates a mapping from the top issue in each dedupBucket to all groups in that dedupBucket.
+ */
+ private ArrayMap<SafetyCenterIssueKey, Set<String>> getTopIssueToGroupMapping(
+ ArrayMap<DeduplicationKey, List<SafetySourceIssueInfo>> dedupBuckets) {
+ ArrayMap<SafetyCenterIssueKey, Set<String>> issueToGroupMap = new ArrayMap<>();
+ for (int i = 0; i < dedupBuckets.size(); i++) {
+ List<SafetySourceIssueInfo> duplicates = dedupBuckets.valueAt(i);
+
+ boolean noMappingBecauseNoDuplicates = duplicates.size() < 2;
+ if (noMappingBecauseNoDuplicates) {
+ continue;
+ }
+
+ SafetyCenterIssueKey topIssueKey = duplicates.get(0).getSafetyCenterIssueKey();
+ for (int j = 0; j < duplicates.size(); j++) {
+ Set<String> groups = issueToGroupMap.getOrDefault(topIssueKey, new ArraySet<>());
+ groups.add(duplicates.get(j).getSafetySourcesGroup().getId());
+ if (j == duplicates.size() - 1) { // last element, no more modifications
+ groups = unmodifiableSet(groups);
+ }
+ issueToGroupMap.put(topIssueKey, groups);
+ }
+ }
+
+ return issueToGroupMap;
+ }
+
+ /**
+ * Handles dismissals logic: in each bucket, dismissal details of the top (highest priority)
+ * 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.
+ */
+ private void alignAllDismissals(
+ ArrayMap<DeduplicationKey, List<SafetySourceIssueInfo>> dedupBuckets) {
+ for (int i = 0; i < dedupBuckets.size(); i++) {
+ List<SafetySourceIssueInfo> duplicates = dedupBuckets.valueAt(i);
+ if (duplicates.size() < 2) {
+ continue;
+ }
+ SafetySourceIssueInfo topDismissed = getHighestPriorityDismissedIssue(duplicates);
+ SafetySourceIssueInfo topNotificationDismissed =
+ getHighestPriorityNotificationDismissedIssue(duplicates);
+ alignDismissalsInBucket(topDismissed, duplicates);
+ alignNotificationDismissalsInBucket(topNotificationDismissed, duplicates);
+ }
+ }
+
+ /**
+ * Dismisses all recipient issues of lower or equal severity than the given top dismissed issue
+ * in the bucket.
+ */
+ private void alignDismissalsInBucket(
+ @Nullable SafetySourceIssueInfo topDismissed, List<SafetySourceIssueInfo> duplicates) {
+ if (topDismissed == null) {
+ return;
+ }
+ SafetyCenterIssueKey topDismissedKey = topDismissed.getSafetyCenterIssueKey();
+ List<SafetyCenterIssueKey> recipients = getRecipientKeys(topDismissed, duplicates);
+ for (int i = 0; i < recipients.size(); i++) {
+ mSafetyCenterIssueDismissalRepository.copyDismissalData(
+ topDismissedKey, recipients.get(i));
+ }
+ }
+
+ /**
+ * Dismisses notifications for all recipient issues of lower or equal severity than the given
+ * top notification-dismissed issue in the bucket.
+ */
+ private void alignNotificationDismissalsInBucket(
+ @Nullable SafetySourceIssueInfo topNotificationDismissed,
+ List<SafetySourceIssueInfo> duplicates) {
+ if (topNotificationDismissed == null) {
+ return;
+ }
+ SafetyCenterIssueKey topNotificationDismissedKey =
+ topNotificationDismissed.getSafetyCenterIssueKey();
+ List<SafetyCenterIssueKey> recipients =
+ getRecipientKeys(topNotificationDismissed, duplicates);
+ for (int i = 0; i < recipients.size(); i++) {
+ mSafetyCenterIssueDismissalRepository.copyNotificationDismissalData(
+ topNotificationDismissedKey, recipients.get(i));
+ }
+ }
+
+ /**
+ * Returns the "recipient" issues for the given top issue from a bucket of duplicates.
+ * Recipients are those issues with a lower or equal severity level. The top issue is not its
+ * own recipient.
+ */
+ private List<SafetyCenterIssueKey> getRecipientKeys(
+ SafetySourceIssueInfo topIssue, List<SafetySourceIssueInfo> duplicates) {
+ ArrayList<SafetyCenterIssueKey> recipients = new ArrayList<>();
+ SafetyCenterIssueKey topKey = topIssue.getSafetyCenterIssueKey();
+ int topSeverity = topIssue.getSafetySourceIssue().getSeverityLevel();
+
+ for (int i = 0; i < duplicates.size(); i++) {
+ SafetySourceIssueInfo issueInfo = duplicates.get(i);
+ SafetyCenterIssueKey issueKey = issueInfo.getSafetyCenterIssueKey();
+ if (!issueKey.equals(topKey)
+ && issueInfo.getSafetySourceIssue().getSeverityLevel() <= topSeverity) {
+ recipients.add(issueKey);
+ }
+ }
+ return recipients;
+ }
+
+ @Nullable
+ private SafetySourceIssueInfo getHighestPriorityDismissedIssue(
+ List<SafetySourceIssueInfo> duplicates) {
+ for (int i = 0; i < duplicates.size(); i++) {
+ SafetySourceIssueInfo issueInfo = duplicates.get(i);
+ if (mSafetyCenterIssueDismissalRepository.isIssueDismissed(
+ issueInfo.getSafetyCenterIssueKey(),
+ issueInfo.getSafetySourceIssue().getSeverityLevel())) {
+ return issueInfo;
+ }
+ }
+
+ return null;
+ }
+
+ @Nullable
+ private SafetySourceIssueInfo getHighestPriorityNotificationDismissedIssue(
+ List<SafetySourceIssueInfo> duplicates) {
+ for (int i = 0; i < duplicates.size(); i++) {
+ SafetySourceIssueInfo issueInfo = duplicates.get(i);
+ if (mSafetyCenterIssueDismissalRepository.isNotificationDismissedNow(
+ issueInfo.getSafetyCenterIssueKey(),
+ issueInfo.getSafetySourceIssue().getSeverityLevel())) {
+ return issueInfo;
+ }
+ }
+
+ return null;
+ }
+
+ /** Returns a set of duplicate issues that need to be filtered out. */
+ private ArraySet<SafetyCenterIssueKey> getDuplicatesToFilterOut(
+ ArrayMap<DeduplicationKey, List<SafetySourceIssueInfo>> dedupBuckets) {
+ ArraySet<SafetyCenterIssueKey> duplicatesToFilterOut = new ArraySet<>();
+
+ for (int i = 0; i < dedupBuckets.size(); i++) {
+ List<SafetySourceIssueInfo> duplicates = dedupBuckets.valueAt(i);
+
+ // all but the top one in the bucket
+ for (int j = 1; j < duplicates.size(); j++) {
+ SafetyCenterIssueKey issueKey = duplicates.get(j).getSafetyCenterIssueKey();
+ duplicatesToFilterOut.add(issueKey);
+ }
+ }
+
+ return duplicatesToFilterOut;
+ }
+
+ /** Returns a mapping (dedup key) -> list(issues). */
+ private static ArrayMap<DeduplicationKey, List<SafetySourceIssueInfo>> createDedupBuckets(
+ List<SafetySourceIssueInfo> sortedIssues) {
+ ArrayMap<DeduplicationKey, List<SafetySourceIssueInfo>> dedupBuckets = new ArrayMap<>();
+
+ for (int i = 0; i < sortedIssues.size(); i++) {
+ SafetySourceIssueInfo issueInfo = sortedIssues.get(i);
+ DeduplicationKey dedupKey = getDedupKey(issueInfo);
+ if (dedupKey == null) {
+ continue;
+ }
+
+ // each bucket will remain sorted
+ List<SafetySourceIssueInfo> bucket =
+ dedupBuckets.getOrDefault(dedupKey, new ArrayList<>());
+ bucket.add(issueInfo);
+
+ dedupBuckets.put(dedupKey, bucket);
+ }
+
+ return dedupBuckets;
+ }
+
+ /** Returns deduplication key of the given {@code issueInfo}. */
+ @Nullable
+ private static DeduplicationKey getDedupKey(SafetySourceIssueInfo issueInfo) {
+ String deduplicationGroup = issueInfo.getSafetySource().getDeduplicationGroup();
+ String deduplicationId = issueInfo.getSafetySourceIssue().getDeduplicationId();
+
+ if (deduplicationGroup == null || deduplicationId == null) {
+ return null;
+ }
+ return new DeduplicationKey(
+ deduplicationGroup,
+ deduplicationId,
+ issueInfo.getSafetyCenterIssueKey().getUserId());
+ }
+
+ /** 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;
+ private final Map<SafetyCenterIssueKey, Set<String>> mIssueToGroup;
+
+ /** Creates a new {@link DeduplicationInfo}. */
+ DeduplicationInfo(
+ List<SafetySourceIssueInfo> deduplicatedIssues,
+ List<SafetySourceIssueInfo> filteredOutDuplicates,
+ Map<SafetyCenterIssueKey, Set<String>> issueToGroup) {
+ mDeduplicatedIssues = unmodifiableList(deduplicatedIssues);
+ mFilteredOutDuplicates = unmodifiableList(filteredOutDuplicates);
+ mIssueToGroup = unmodifiableMap(issueToGroup);
+ }
+
+ /**
+ * Returns the list of issues which were removed from the given list of issues in the most
+ * recent {@link SafetyCenterIssueDeduplicator#deduplicateIssues} call. These issues were
+ * removed because they were duplicates of other issues.
+ */
+ List<SafetySourceIssueInfo> getFilteredOutDuplicateIssues() {
+ return mFilteredOutDuplicates;
+ }
+
+ /**
+ * Returns a mapping between a {@link SafetyCenterIssueKey} and {@link SafetySourcesGroup}
+ * IDs, that was a result of the most recent {@link
+ * SafetyCenterIssueDeduplicator#deduplicateIssues} call.
+ *
+ * <p>If present, such an entry represents an issue mapping to all the safety source groups
+ * of others issues which were filtered out as its duplicates. It also contains a mapping to
+ * its own source group.
+ *
+ * <p>If an issue didn't have any duplicates, it won't be present in the result.
+ */
+ Map<SafetyCenterIssueKey, Set<String>> getIssueToGroupMapping() {
+ return mIssueToGroup;
+ }
+
+ /** Returns the deduplication result, the deduplicated list of issues. */
+ List<SafetySourceIssueInfo> getDeduplicatedIssues() {
+ return mDeduplicatedIssues;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof DeduplicationInfo)) return false;
+ DeduplicationInfo that = (DeduplicationInfo) o;
+ return mDeduplicatedIssues.equals(that.mDeduplicatedIssues)
+ && mFilteredOutDuplicates.equals(that.mFilteredOutDuplicates)
+ && mIssueToGroup.equals(that.mIssueToGroup);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDeduplicatedIssues, mFilteredOutDuplicates, mIssueToGroup);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("DeduplicationInfo:");
+
+ sb.append("\n\tDeduplicatedIssues:");
+ for (int i = 0; i < mDeduplicatedIssues.size(); i++) {
+ sb.append("\n\t\tSafetySourceIssueInfo=").append(mDeduplicatedIssues.get(i));
+ }
+
+ sb.append("\n\tFilteredOutDuplicates:");
+ for (int i = 0; i < mFilteredOutDuplicates.size(); i++) {
+ sb.append("\n\t\tSafetySourceIssueInfo=").append(mFilteredOutDuplicates.get(i));
+ }
+
+ sb.append("\n\tIssueToGroupMapping");
+ for (Map.Entry<SafetyCenterIssueKey, Set<String>> entry : mIssueToGroup.entrySet()) {
+ sb.append("\n\t\tSafetyCenterIssueKey=")
+ .append(toUserFriendlyString(entry.getKey()))
+ .append(" maps to groups: ");
+ for (String group : entry.getValue()) {
+ sb.append(group).append(",");
+ }
+ }
+
+ return sb.toString();
+ }
+ }
+
+ private static final class DeduplicationKey {
+
+ private final String mDeduplicationGroup;
+ private final String mDeduplicationId;
+ private final int mUserId;
+
+ private DeduplicationKey(
+ String deduplicationGroup, String deduplicationId, @UserIdInt int userId) {
+ mDeduplicationGroup = deduplicationGroup;
+ mDeduplicationId = deduplicationId;
+ mUserId = userId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDeduplicationGroup, mDeduplicationId, mUserId);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof DeduplicationKey)) return false;
+ DeduplicationKey dedupKey = (DeduplicationKey) o;
+ return mDeduplicationGroup.equals(dedupKey.mDeduplicationGroup)
+ && mDeduplicationId.equals(dedupKey.mDeduplicationId)
+ && mUserId == dedupKey.mUserId;
+ }
+ }
+}
diff --git a/service/java/com/android/safetycenter/data/SafetyCenterIssueDismissalRepository.java b/service/java/com/android/safetycenter/data/SafetyCenterIssueDismissalRepository.java
new file mode 100644
index 000000000..bc9bfb2d6
--- /dev/null
+++ b/service/java/com/android/safetycenter/data/SafetyCenterIssueDismissalRepository.java
@@ -0,0 +1,610 @@
+/*
+ * 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.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;
+import android.os.Handler;
+import android.safetycenter.SafetySourceData;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.modules.utils.BackgroundThread;
+import com.android.safetycenter.ApiLock;
+import com.android.safetycenter.SafetyCenterConfigReader;
+import com.android.safetycenter.SafetyCenterFlags;
+import com.android.safetycenter.internaldata.SafetyCenterIds;
+import com.android.safetycenter.internaldata.SafetyCenterIssueKey;
+import com.android.safetycenter.persistence.PersistedSafetyCenterIssue;
+import com.android.safetycenter.persistence.PersistenceException;
+import com.android.safetycenter.persistence.SafetyCenterIssuesPersistence;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
+/**
+ * Repository to manage data about all issue dismissals in Safety Center.
+ *
+ * <p>It stores the state of this class automatically into a file. After the class is first
+ * instantiated the user should call {@link
+ * SafetyCenterIssueDismissalRepository#loadStateFromFile()} to initialize the state with what was
+ * stored in the file.
+ *
+ * <p>This class isn't thread safe. Thread safety must be handled by the caller.
+ */
+@RequiresApi(TIRAMISU)
+@NotThreadSafe
+final class SafetyCenterIssueDismissalRepository {
+
+ private static final String TAG = "SafetyCenterIssueDis";
+
+ /** The APEX name used to retrieve the APEX owned data directories. */
+ private static final String APEX_MODULE_NAME = "com.android.permission";
+
+ /** The name of the file used to persist the {@link SafetyCenterIssueDismissalRepository}. */
+ private static final String ISSUE_DISMISSAL_REPOSITORY_FILE_NAME = "safety_center_issues.xml";
+
+ /** The time delay used to throttle and aggregate writes to disk. */
+ private static final Duration WRITE_DELAY = Duration.ofMillis(500);
+
+ private final Handler mWriteHandler = BackgroundThread.getHandler();
+
+ private final ApiLock mApiLock;
+
+ private final SafetyCenterConfigReader mSafetyCenterConfigReader;
+
+ private final ArrayMap<SafetyCenterIssueKey, IssueData> mIssues = new ArrayMap<>();
+ private boolean mWriteStateToFileScheduled = false;
+
+ SafetyCenterIssueDismissalRepository(
+ ApiLock apiLock, SafetyCenterConfigReader safetyCenterConfigReader) {
+ mApiLock = apiLock;
+ mSafetyCenterConfigReader = safetyCenterConfigReader;
+ }
+
+ /**
+ * Returns {@code true} if the issue with the given key and severity level is currently
+ * dismissed.
+ *
+ * <p>An issue which is dismissed at one time may become "un-dismissed" later, after the
+ * resurface delay (which depends on severity level) has elapsed.
+ *
+ * <p>If the given issue key is not found in the repository this method returns {@code false}.
+ */
+ boolean isIssueDismissed(
+ SafetyCenterIssueKey safetyCenterIssueKey,
+ @SafetySourceData.SeverityLevel int safetySourceIssueSeverityLevel) {
+ IssueData issueData = getOrWarn(safetyCenterIssueKey, "checking if dismissed");
+ if (issueData == null) {
+ return false;
+ }
+
+ Instant dismissedAt = issueData.getDismissedAt();
+ boolean isNotCurrentlyDismissed = dismissedAt == null;
+ if (isNotCurrentlyDismissed) {
+ return false;
+ }
+
+ long maxCount = SafetyCenterFlags.getResurfaceIssueMaxCount(safetySourceIssueSeverityLevel);
+ Duration delay = SafetyCenterFlags.getResurfaceIssueDelay(safetySourceIssueSeverityLevel);
+
+ boolean hasAlreadyResurfacedTheMaxAllowedNumberOfTimes =
+ issueData.getDismissCount() > maxCount;
+ if (hasAlreadyResurfacedTheMaxAllowedNumberOfTimes) {
+ return true;
+ }
+
+ Duration timeSinceLastDismissal = Duration.between(dismissedAt, Instant.now());
+ boolean isTimeToResurface = timeSinceLastDismissal.compareTo(delay) >= 0;
+ if (isTimeToResurface) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Marks the issue with the given key as dismissed.
+ *
+ * <p>That issue's notification (if any) is also marked as dismissed.
+ */
+ void dismissIssue(SafetyCenterIssueKey safetyCenterIssueKey) {
+ IssueData issueData = getOrWarn(safetyCenterIssueKey, "dismissing");
+ if (issueData == null) {
+ return;
+ }
+ Instant now = Instant.now();
+ issueData.setDismissedAt(now);
+ issueData.setDismissCount(issueData.getDismissCount() + 1);
+ issueData.setNotificationDismissedAt(now);
+ scheduleWriteStateToFile();
+ }
+
+ /**
+ * Copy dismissal data from one issue to the other.
+ *
+ * <p>This will align dismissal state of these issues, unless issues are of different
+ * severities, in which case they can potentially differ in resurface times.
+ */
+ void copyDismissalData(SafetyCenterIssueKey keyFrom, SafetyCenterIssueKey keyTo) {
+ IssueData dataFrom = getOrWarn(keyFrom, "copying dismissal data");
+ IssueData dataTo = getOrWarn(keyTo, "copying dismissal data");
+ if (dataFrom == null || dataTo == null) {
+ return;
+ }
+
+ dataTo.setDismissedAt(dataFrom.getDismissedAt());
+ dataTo.setDismissCount(dataFrom.getDismissCount());
+ scheduleWriteStateToFile();
+ }
+
+ /**
+ * Copy notification dismissal data from one issue to the other.
+ *
+ * <p>This will align notification dismissal state of these issues.
+ */
+ void copyNotificationDismissalData(SafetyCenterIssueKey keyFrom, SafetyCenterIssueKey keyTo) {
+ IssueData dataFrom = getOrWarn(keyFrom, "copying notification dismissal data");
+ IssueData dataTo = getOrWarn(keyTo, "copying notification dismissal data");
+ if (dataFrom == null || dataTo == null) {
+ return;
+ }
+
+ dataTo.setNotificationDismissedAt(dataFrom.getNotificationDismissedAt());
+ scheduleWriteStateToFile();
+ }
+
+ /**
+ * Marks the notification (if any) of the issue with the given key as dismissed.
+ *
+ * <p>The issue itself is <strong>not</strong> marked as dismissed and its warning card can
+ * still appear in the Safety Center UI.
+ */
+ void dismissNotification(SafetyCenterIssueKey safetyCenterIssueKey) {
+ IssueData issueData = getOrWarn(safetyCenterIssueKey, "dismissing notification");
+ if (issueData == null) {
+ return;
+ }
+ issueData.setNotificationDismissedAt(Instant.now());
+ scheduleWriteStateToFile();
+ }
+
+ /**
+ * Returns the {@link Instant} when the issue with the given key was first reported to Safety
+ * Center.
+ */
+ @Nullable
+ Instant getIssueFirstSeenAt(SafetyCenterIssueKey safetyCenterIssueKey) {
+ IssueData issueData = getOrWarn(safetyCenterIssueKey, "getting first seen");
+ if (issueData == null) {
+ return null;
+ }
+ return issueData.getFirstSeenAt();
+ }
+
+ @Nullable
+ private Instant getNotificationDismissedAt(SafetyCenterIssueKey safetyCenterIssueKey) {
+ IssueData issueData = getOrWarn(safetyCenterIssueKey, "getting notification dismissed");
+ if (issueData == null) {
+ return null;
+ }
+ return issueData.getNotificationDismissedAt();
+ }
+
+ /** Returns {@code true} if an issue's notification is dismissed now. */
+ // TODO(b/259084807): Consider extracting notification dismissal logic to separate class
+ boolean isNotificationDismissedNow(
+ SafetyCenterIssueKey issueKey, @SafetySourceData.SeverityLevel int severityLevel) {
+ // The current code for dismissing an issue/warning card also dismisses any
+ // corresponding notification, but it is still necessary to check the issue dismissal
+ // status, in addition to the notification dismissal (below) because issues may have been
+ // dismissed by an earlier version of the code which lacked this functionality.
+ if (isIssueDismissed(issueKey, severityLevel)) {
+ return true;
+ }
+
+ Instant dismissedAt = getNotificationDismissedAt(issueKey);
+ if (dismissedAt == null) {
+ // Notification was never dismissed
+ return false;
+ }
+
+ Duration resurfaceDelay = SafetyCenterFlags.getNotificationResurfaceInterval();
+ if (resurfaceDelay == null) {
+ // Null resurface delay means notifications may never resurface
+ return true;
+ }
+
+ Instant canResurfaceAt = dismissedAt.plus(resurfaceDelay);
+ return Instant.now().isBefore(canResurfaceAt);
+ }
+
+ /**
+ * Updates the issue repository to contain exactly the given {@code safetySourceIssueIds} for
+ * the supplied source and user.
+ */
+ void updateIssuesForSource(
+ ArraySet<String> safetySourceIssueIds, String safetySourceId, @UserIdInt int userId) {
+ boolean someDataChanged = false;
+
+ // Remove issues no longer reported by the source.
+ // Loop in reverse index order to be able to remove entries while iterating.
+ for (int i = mIssues.size() - 1; i >= 0; i--) {
+ SafetyCenterIssueKey issueKey = mIssues.keyAt(i);
+ boolean doesNotBelongToUserOrSource =
+ issueKey.getUserId() != userId
+ || !Objects.equals(issueKey.getSafetySourceId(), safetySourceId);
+ if (doesNotBelongToUserOrSource) {
+ continue;
+ }
+ boolean isIssueNoLongerReported =
+ !safetySourceIssueIds.contains(issueKey.getSafetySourceIssueId());
+ if (isIssueNoLongerReported) {
+ mIssues.removeAt(i);
+ someDataChanged = true;
+ }
+ }
+ // Add newly reported issues.
+ for (int i = 0; i < safetySourceIssueIds.size(); i++) {
+ SafetyCenterIssueKey issueKey =
+ SafetyCenterIssueKey.newBuilder()
+ .setUserId(userId)
+ .setSafetySourceId(safetySourceId)
+ .setSafetySourceIssueId(safetySourceIssueIds.valueAt(i))
+ .build();
+ boolean isIssueNewlyReported = !mIssues.containsKey(issueKey);
+ if (isIssueNewlyReported) {
+ mIssues.put(issueKey, new IssueData(Instant.now()));
+ someDataChanged = true;
+ }
+ }
+ if (someDataChanged) {
+ scheduleWriteStateToFile();
+ }
+ }
+
+ /** Returns whether the issue is currently hidden. */
+ boolean isIssueHidden(SafetyCenterIssueKey safetyCenterIssueKey) {
+ IssueData issueData = getOrWarn(safetyCenterIssueKey, "checking if issue hidden");
+ if (issueData == null || !issueData.isHidden()) {
+ return false;
+ }
+
+ Instant timerStart = issueData.getResurfaceTimerStartTime();
+ if (timerStart == null) {
+ return true;
+ }
+
+ Duration delay = SafetyCenterFlags.getTemporarilyHiddenIssueResurfaceDelay();
+ Duration timeSinceTimerStarted = Duration.between(timerStart, Instant.now());
+ boolean isTimeToResurface = timeSinceTimerStarted.compareTo(delay) >= 0;
+
+ if (isTimeToResurface) {
+ issueData.setHidden(false);
+ issueData.setResurfaceTimerStartTime(null);
+ return false;
+ }
+ return true;
+ }
+
+ /** Hides the issue with the given {@link SafetyCenterIssueKey}. */
+ void hideIssue(SafetyCenterIssueKey safetyCenterIssueKey) {
+ IssueData issueData = getOrWarn(safetyCenterIssueKey, "hiding issue");
+ if (issueData != null) {
+ issueData.setHidden(true);
+ // to abide by the method was called last: hideIssue or resurfaceHiddenIssueAfterPeriod
+ issueData.setResurfaceTimerStartTime(null);
+ }
+ }
+
+ /**
+ * The issue with the given {@link SafetyCenterIssueKey} will be resurfaced (marked as not
+ * hidden) after a period of time defined by {@link
+ * SafetyCenterFlags#getTemporarilyHiddenIssueResurfaceDelay()}, such that {@link
+ * SafetyCenterIssueDismissalRepository#isIssueHidden} will start returning {@code false} for
+ * the given issue.
+ *
+ * <p>If this method is called multiple times in a row, the period will be set by the first call
+ * and all following calls won't have any effect.
+ */
+ void resurfaceHiddenIssueAfterPeriod(SafetyCenterIssueKey safetyCenterIssueKey) {
+ IssueData issueData = getOrWarn(safetyCenterIssueKey, "resurfaceIssueAfterPeriod");
+ if (issueData == null) {
+ return;
+ }
+
+ // if timer already started, we don't want to restart
+ if (issueData.getResurfaceTimerStartTime() == null) {
+ issueData.setResurfaceTimerStartTime(Instant.now());
+ }
+ }
+
+ /** Takes a snapshot of the contents of the repository to be written to persistent storage. */
+ private List<PersistedSafetyCenterIssue> snapshot() {
+ List<PersistedSafetyCenterIssue> persistedIssues = new ArrayList<>();
+ for (int i = 0; i < mIssues.size(); i++) {
+ String encodedKey = SafetyCenterIds.encodeToString(mIssues.keyAt(i));
+ IssueData issueData = mIssues.valueAt(i);
+ persistedIssues.add(issueData.toPersistedIssueBuilder().setKey(encodedKey).build());
+ }
+ return persistedIssues;
+ }
+
+ /**
+ * Replaces the contents of the repository with the given issues read from persistent storage.
+ */
+ private void load(List<PersistedSafetyCenterIssue> persistedSafetyCenterIssues) {
+ boolean someDataChanged = false;
+ mIssues.clear();
+ for (int i = 0; i < persistedSafetyCenterIssues.size(); i++) {
+ PersistedSafetyCenterIssue persistedIssue = persistedSafetyCenterIssues.get(i);
+ SafetyCenterIssueKey key = SafetyCenterIds.issueKeyFromString(persistedIssue.getKey());
+
+ // Only load the issues associated with the "real" config. We do not want to keep on
+ // persisting potentially stray issues from tests (they should supposedly be cleared,
+ // but may stick around if the data is not cleared after a test run).
+ // There is a caveat that if a real source was overridden in tests and the override
+ // provided data without clearing it, we will associate this issue with the real source.
+ if (!mSafetyCenterConfigReader.isExternalSafetySourceFromRealConfig(
+ key.getSafetySourceId())) {
+ someDataChanged = true;
+ continue;
+ }
+
+ IssueData issueData = IssueData.fromPersistedIssue(persistedIssue);
+ mIssues.put(key, issueData);
+ }
+ if (someDataChanged) {
+ scheduleWriteStateToFile();
+ }
+ }
+
+ /** Clears all the data in the repository. */
+ public void clear() {
+ mIssues.clear();
+ scheduleWriteStateToFile();
+ }
+
+ /** Clears all the data in the repository for the given user. */
+ void clearForUser(@UserIdInt int userId) {
+ boolean someDataChanged = false;
+ // Loop in reverse index order to be able to remove entries while iterating.
+ for (int i = mIssues.size() - 1; i >= 0; i--) {
+ SafetyCenterIssueKey issueKey = mIssues.keyAt(i);
+ if (issueKey.getUserId() == userId) {
+ mIssues.removeAt(i);
+ someDataChanged = true;
+ }
+ }
+ if (someDataChanged) {
+ scheduleWriteStateToFile();
+ }
+ }
+
+ /** Dumps state for debugging purposes. */
+ void dump(FileDescriptor fd, PrintWriter fout) {
+ int issueRepositoryCount = mIssues.size();
+ fout.println(
+ "ISSUE DISMISSAL REPOSITORY ("
+ + issueRepositoryCount
+ + ", mWriteStateToFileScheduled="
+ + mWriteStateToFileScheduled
+ + ")");
+ for (int i = 0; i < issueRepositoryCount; i++) {
+ SafetyCenterIssueKey key = mIssues.keyAt(i);
+ IssueData data = mIssues.valueAt(i);
+ fout.println("\t[" + i + "] " + toUserFriendlyString(key) + " -> " + data);
+ }
+ fout.println();
+
+ File issueDismissalRepositoryFile = getIssueDismissalRepositoryFile();
+ fout.println(
+ "ISSUE DISMISSAL REPOSITORY FILE ("
+ + issueDismissalRepositoryFile.getAbsolutePath()
+ + ")");
+ fout.flush();
+ try {
+ Files.copy(issueDismissalRepositoryFile.toPath(), new FileOutputStream(fd));
+ } catch (IOException e) {
+ // TODO(b/266202404)
+ e.printStackTrace(fout);
+ }
+ fout.println();
+ }
+
+ @Nullable
+ private IssueData getOrWarn(SafetyCenterIssueKey issueKey, String reason) {
+ IssueData issueData = mIssues.get(issueKey);
+ if (issueData == null) {
+ Log.w(
+ TAG,
+ "Issue missing when reading from dismissal repository for "
+ + reason
+ + ": "
+ + toUserFriendlyString(issueKey));
+ return null;
+ }
+ return issueData;
+ }
+
+ /** Schedule writing the {@link SafetyCenterIssueDismissalRepository} to file. */
+ private void scheduleWriteStateToFile() {
+ if (!mWriteStateToFileScheduled) {
+ mWriteHandler.postDelayed(this::writeStateToFile, WRITE_DELAY.toMillis());
+ mWriteStateToFileScheduled = true;
+ }
+ }
+
+ @WorkerThread
+ private void writeStateToFile() {
+ List<PersistedSafetyCenterIssue> persistedSafetyCenterIssues;
+
+ synchronized (mApiLock) {
+ mWriteStateToFileScheduled = false;
+ persistedSafetyCenterIssues = snapshot();
+ // Since all write operations are scheduled in the same background thread, we can safely
+ // release the lock after creating a snapshot and know that all snapshots will be
+ // written in the correct order even if we are not holding the lock.
+ }
+
+ SafetyCenterIssuesPersistence.write(
+ persistedSafetyCenterIssues, getIssueDismissalRepositoryFile());
+ }
+
+ /** Read the contents of the file and load them into this class. */
+ void loadStateFromFile() {
+ List<PersistedSafetyCenterIssue> persistedSafetyCenterIssues = new ArrayList<>();
+
+ try {
+ persistedSafetyCenterIssues =
+ SafetyCenterIssuesPersistence.read(getIssueDismissalRepositoryFile());
+ Log.i(TAG, "Safety Center persisted issues read successfully");
+ } catch (PersistenceException e) {
+ Log.e(TAG, "Cannot read Safety Center persisted issues", e);
+ }
+
+ load(persistedSafetyCenterIssues);
+ scheduleWriteStateToFile();
+ }
+
+ private static File getIssueDismissalRepositoryFile() {
+ ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment(APEX_MODULE_NAME);
+ File dataDirectory = apexEnvironment.getDeviceProtectedDataDir();
+ // It should resolve to /data/misc/apexdata/com.android.permission/safety_center_issues.xml
+ return new File(dataDirectory, ISSUE_DISMISSAL_REPOSITORY_FILE_NAME);
+ }
+
+ /**
+ * An internal mutable data structure containing issue metadata which is used to determine
+ * whether an issue should be dismissed/hidden from the user.
+ */
+ private static final class IssueData {
+
+ private static IssueData fromPersistedIssue(PersistedSafetyCenterIssue persistedIssue) {
+ IssueData issueData = new IssueData(persistedIssue.getFirstSeenAt());
+ issueData.setDismissedAt(persistedIssue.getDismissedAt());
+ issueData.setDismissCount(persistedIssue.getDismissCount());
+ issueData.setNotificationDismissedAt(persistedIssue.getNotificationDismissedAt());
+ return issueData;
+ }
+
+ private final Instant mFirstSeenAt;
+
+ @Nullable private Instant mDismissedAt;
+ private int mDismissCount;
+
+ @Nullable private Instant mNotificationDismissedAt;
+
+ // TODO(b/270015734): maybe persist those as well
+ private boolean mHidden = false;
+ // Moment when a theoretical timer starts - when it ends the issue gets unmarked as hidden.
+ @Nullable private Instant mResurfaceTimerStartTime;
+
+ private IssueData(Instant firstSeenAt) {
+ mFirstSeenAt = firstSeenAt;
+ }
+
+ private Instant getFirstSeenAt() {
+ return mFirstSeenAt;
+ }
+
+ @Nullable
+ private Instant getDismissedAt() {
+ return mDismissedAt;
+ }
+
+ private void setDismissedAt(@Nullable Instant dismissedAt) {
+ mDismissedAt = dismissedAt;
+ }
+
+ private int getDismissCount() {
+ return mDismissCount;
+ }
+
+ private void setDismissCount(int dismissCount) {
+ mDismissCount = dismissCount;
+ }
+
+ @Nullable
+ private Instant getNotificationDismissedAt() {
+ return mNotificationDismissedAt;
+ }
+
+ private void setNotificationDismissedAt(@Nullable Instant notificationDismissedAt) {
+ mNotificationDismissedAt = notificationDismissedAt;
+ }
+
+ private boolean isHidden() {
+ return mHidden;
+ }
+
+ private void setHidden(boolean hidden) {
+ mHidden = hidden;
+ }
+
+ @Nullable
+ private Instant getResurfaceTimerStartTime() {
+ return mResurfaceTimerStartTime;
+ }
+
+ private void setResurfaceTimerStartTime(@Nullable Instant resurfaceTimerStartTime) {
+ this.mResurfaceTimerStartTime = resurfaceTimerStartTime;
+ }
+
+ private PersistedSafetyCenterIssue.Builder toPersistedIssueBuilder() {
+ return new PersistedSafetyCenterIssue.Builder()
+ .setFirstSeenAt(mFirstSeenAt)
+ .setDismissedAt(mDismissedAt)
+ .setDismissCount(mDismissCount)
+ .setNotificationDismissedAt(mNotificationDismissedAt);
+ }
+
+ @Override
+ public String toString() {
+ return "SafetySourceIssueInfo{"
+ + "mFirstSeenAt="
+ + mFirstSeenAt
+ + ", mDismissedAt="
+ + mDismissedAt
+ + ", mDismissCount="
+ + mDismissCount
+ + ", mNotificationDismissedAt="
+ + mNotificationDismissedAt
+ + '}';
+ }
+ }
+}
diff --git a/service/java/com/android/safetycenter/data/SafetyCenterIssueRepository.java b/service/java/com/android/safetycenter/data/SafetyCenterIssueRepository.java
new file mode 100644
index 000000000..566c28c1e
--- /dev/null
+++ b/service/java/com/android/safetycenter/data/SafetyCenterIssueRepository.java
@@ -0,0 +1,310 @@
+/*
+ * 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.TIRAMISU;
+
+import static com.android.safetycenter.data.SafetyCenterIssueDeduplicator.DeduplicationInfo;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.emptyMap;
+import static java.util.Collections.emptySet;
+
+import android.annotation.UserIdInt;
+import android.content.Context;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceIssue;
+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;
+import com.android.safetycenter.SafetySourceIssueInfo;
+import com.android.safetycenter.SafetySourceKey;
+import com.android.safetycenter.SafetySources;
+import com.android.safetycenter.UserProfileGroup;
+import com.android.safetycenter.internaldata.SafetyCenterIssueKey;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
+/**
+ * Contains issue related data.
+ *
+ * <p>Responsible for generating lists of issues and deduplication of issues.
+ */
+@RequiresApi(TIRAMISU)
+@NotThreadSafe
+final class SafetyCenterIssueRepository {
+
+ private static final SafetySourceIssuesInfoBySeverityDescending
+ SAFETY_SOURCE_ISSUES_INFO_BY_SEVERITY_DESCENDING =
+ new SafetySourceIssuesInfoBySeverityDescending();
+
+ private static final DeduplicationInfo EMPTY_DEDUP_INFO =
+ new DeduplicationInfo(emptyList(), emptyList(), emptyMap());
+
+ private final Context mContext;
+ private final SafetySourceDataRepository mSafetySourceDataRepository;
+ private final SafetyCenterConfigReader mSafetyCenterConfigReader;
+ private final SafetyCenterIssueDismissalRepository mSafetyCenterIssueDismissalRepository;
+ private final SafetyCenterIssueDeduplicator mSafetyCenterIssueDeduplicator;
+
+ private final SparseArray<DeduplicationInfo> mUserIdToDedupInfo = new SparseArray<>();
+
+ SafetyCenterIssueRepository(
+ Context context,
+ SafetySourceDataRepository safetySourceDataRepository,
+ SafetyCenterConfigReader safetyCenterConfigReader,
+ SafetyCenterIssueDismissalRepository safetyCenterIssueDismissalRepository,
+ SafetyCenterIssueDeduplicator safetyCenterIssueDeduplicator) {
+ mContext = context;
+ mSafetySourceDataRepository = safetySourceDataRepository;
+ mSafetyCenterConfigReader = safetyCenterConfigReader;
+ mSafetyCenterIssueDismissalRepository = safetyCenterIssueDismissalRepository;
+ mSafetyCenterIssueDeduplicator = safetyCenterIssueDeduplicator;
+ }
+
+ /**
+ * 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));
+ }
+
+ private void updateIssues(@UserIdInt int userId, boolean isManagedProfile) {
+ List<SafetySourceIssueInfo> issues =
+ getAllStoredIssuesFromRawSourceData(userId, isManagedProfile);
+
+ issues.sort(SAFETY_SOURCE_ISSUES_INFO_BY_SEVERITY_DESCENDING);
+
+ mUserIdToDedupInfo.put(userId, produceDedupInfo(issues));
+ }
+
+ private DeduplicationInfo produceDedupInfo(List<SafetySourceIssueInfo> issues) {
+ if (SdkLevel.isAtLeastU()) {
+ return mSafetyCenterIssueDeduplicator.deduplicateIssues(issues);
+ }
+ return new DeduplicationInfo(issues, emptyList(), emptyMap());
+ }
+
+ /**
+ * Fetches a list of issues related to the given {@link UserProfileGroup}.
+ *
+ * <p>Issues in the list are sorted in descending order and deduplicated (if applicable, only on
+ * Android U+).
+ *
+ * <p>Only includes issues related to active/running {@code userId}s in the given {@link
+ * UserProfileGroup}.
+ */
+ List<SafetySourceIssueInfo> getIssuesDedupedSortedDescFor(UserProfileGroup userProfileGroup) {
+ List<SafetySourceIssueInfo> issuesInfo = getIssuesFor(userProfileGroup);
+ issuesInfo.sort(SAFETY_SOURCE_ISSUES_INFO_BY_SEVERITY_DESCENDING);
+ return issuesInfo;
+ }
+
+ /**
+ * Counts the total number of issues from loggable sources, in the given {@link
+ * UserProfileGroup}.
+ *
+ * <p>Only includes issues related to active/running {@code userId}s in the given {@link
+ * UserProfileGroup}.
+ */
+ int countLoggableIssuesFor(UserProfileGroup userProfileGroup) {
+ List<SafetySourceIssueInfo> relevantIssues = getIssuesFor(userProfileGroup);
+ int issueCount = 0;
+ for (int i = 0; i < relevantIssues.size(); i++) {
+ SafetySourceIssueInfo safetySourceIssueInfo = relevantIssues.get(i);
+ if (SafetySources.isLoggable(safetySourceIssueInfo.getSafetySource())) {
+ issueCount++;
+ }
+ }
+ return issueCount;
+ }
+
+ /** Gets a list of all issues for the given {@code userId}. */
+ List<SafetySourceIssueInfo> getIssuesForUser(@UserIdInt int userId) {
+ return filterOutHiddenIssues(
+ mUserIdToDedupInfo.get(userId, EMPTY_DEDUP_INFO).getDeduplicatedIssues());
+ }
+
+ /**
+ * Returns a set of {@link SafetySourcesGroup} IDs that the given {@link SafetyCenterIssueKey}
+ * is mapped to, or an empty list if no such mapping is configured.
+ */
+ Set<String> getGroupMappingFor(SafetyCenterIssueKey issueKey) {
+ return mUserIdToDedupInfo
+ .get(issueKey.getUserId(), EMPTY_DEDUP_INFO)
+ .getIssueToGroupMapping()
+ .getOrDefault(issueKey, emptySet());
+ }
+
+ /**
+ * Returns the list of issues for the given {@code userId} which were removed from the given
+ * list of issues in the most recent {@link SafetyCenterIssueDeduplicator#deduplicateIssues}
+ * call. These issues were removed because they were duplicates of other issues.
+ *
+ * <p>If this method is called before any calls to {@link
+ * SafetyCenterIssueDeduplicator#deduplicateIssues} then an empty list is returned.
+ */
+ List<SafetySourceIssueInfo> getLatestDuplicates(@UserIdInt int userId) {
+ return mUserIdToDedupInfo.get(userId, EMPTY_DEDUP_INFO).getFilteredOutDuplicateIssues();
+ }
+
+ private List<SafetySourceIssueInfo> filterOutHiddenIssues(List<SafetySourceIssueInfo> issues) {
+ List<SafetySourceIssueInfo> result = new ArrayList<>();
+ for (int i = 0; i < issues.size(); i++) {
+ SafetySourceIssueInfo issueInfo = issues.get(i);
+ if (!mSafetyCenterIssueDismissalRepository.isIssueHidden(
+ issueInfo.getSafetyCenterIssueKey())) {
+ result.add(issueInfo);
+ }
+ }
+ return result;
+ }
+
+ private List<SafetySourceIssueInfo> getAllStoredIssuesFromRawSourceData(
+ @UserIdInt int userId, boolean isManagedProfile) {
+ List<SafetySourceIssueInfo> allIssuesInfo = new ArrayList<>();
+
+ List<SafetySourcesGroup> safetySourcesGroups =
+ mSafetyCenterConfigReader.getSafetySourcesGroups();
+ for (int j = 0; j < safetySourcesGroups.size(); j++) {
+ addSafetySourceIssuesInfo(
+ allIssuesInfo, safetySourcesGroups.get(j), userId, isManagedProfile);
+ }
+
+ return allIssuesInfo;
+ }
+
+ private void addSafetySourceIssuesInfo(
+ List<SafetySourceIssueInfo> issuesInfo,
+ SafetySourcesGroup safetySourcesGroup,
+ @UserIdInt int userId,
+ boolean isManagedProfile) {
+ List<SafetySource> safetySources = safetySourcesGroup.getSafetySources();
+ for (int i = 0; i < safetySources.size(); i++) {
+ SafetySource safetySource = safetySources.get(i);
+
+ if (!SafetySources.isExternal(safetySource)) {
+ continue;
+ }
+ if (isManagedProfile && !SafetySources.supportsManagedProfiles(safetySource)) {
+ continue;
+ }
+
+ addSafetySourceIssuesInfo(issuesInfo, safetySource, safetySourcesGroup, userId);
+ }
+ }
+
+ private void addSafetySourceIssuesInfo(
+ List<SafetySourceIssueInfo> issuesInfo,
+ SafetySource safetySource,
+ SafetySourcesGroup safetySourcesGroup,
+ @UserIdInt int userId) {
+ SafetySourceKey key = SafetySourceKey.of(safetySource.getId(), userId);
+ SafetySourceData safetySourceData = mSafetySourceDataRepository.getSafetySourceData(key);
+
+ if (safetySourceData == null) {
+ return;
+ }
+
+ List<SafetySourceIssue> safetySourceIssues = safetySourceData.getIssues();
+ for (int i = 0; i < safetySourceIssues.size(); i++) {
+ SafetySourceIssue safetySourceIssue = safetySourceIssues.get(i);
+
+ SafetySourceIssueInfo safetySourceIssueInfo =
+ new SafetySourceIssueInfo(
+ safetySourceIssue, safetySource, safetySourcesGroup, userId);
+ issuesInfo.add(safetySourceIssueInfo);
+ }
+ }
+
+ /**
+ * Only includes issues related to active/running {@code userId}s in the given {@link
+ * UserProfileGroup}.
+ */
+ private List<SafetySourceIssueInfo> getIssuesFor(UserProfileGroup userProfileGroup) {
+ List<SafetySourceIssueInfo> issues =
+ new ArrayList<>(getIssuesForUser(userProfileGroup.getProfileParentUserId()));
+
+ int[] managedRunningProfileUserIds = userProfileGroup.getManagedRunningProfilesUserIds();
+ for (int i = 0; i < managedRunningProfileUserIds.length; i++) {
+ issues.addAll(getIssuesForUser(managedRunningProfileUserIds[i]));
+ }
+
+ return issues;
+ }
+
+ /** A comparator to order {@link SafetySourceIssueInfo} by severity level descending. */
+ private static final class SafetySourceIssuesInfoBySeverityDescending
+ implements Comparator<SafetySourceIssueInfo> {
+
+ private SafetySourceIssuesInfoBySeverityDescending() {}
+
+ @Override
+ public int compare(SafetySourceIssueInfo left, SafetySourceIssueInfo right) {
+ return Integer.compare(
+ right.getSafetySourceIssue().getSeverityLevel(),
+ left.getSafetySourceIssue().getSeverityLevel());
+ }
+ }
+
+ /** Dumps state for debugging purposes. */
+ void dump(PrintWriter fout) {
+ fout.println("ISSUE REPOSITORY");
+ for (int i = 0; i < mUserIdToDedupInfo.size(); i++) {
+ fout.println();
+ fout.println("\tUSER ID=" + mUserIdToDedupInfo.keyAt(i));
+ fout.println("\tDEDUPLICATION INFO=" + mUserIdToDedupInfo.valueAt(i));
+ }
+ fout.println();
+ }
+
+ /** Clears all the data from the repository. */
+ void clear() {
+ mUserIdToDedupInfo.clear();
+ }
+
+ /** Clears all data related to the given {@code userId}. */
+ void clearForUser(@UserIdInt int userId) {
+ mUserIdToDedupInfo.delete(userId);
+ }
+}
diff --git a/service/java/com/android/safetycenter/data/SafetySourceDataRepository.java b/service/java/com/android/safetycenter/data/SafetySourceDataRepository.java
new file mode 100644
index 000000000..b47f7925e
--- /dev/null
+++ b/service/java/com/android/safetycenter/data/SafetySourceDataRepository.java
@@ -0,0 +1,354 @@
+/*
+ * 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.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;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceErrorDetails;
+import android.safetycenter.SafetySourceIssue;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.safetycenter.SafetySourceKey;
+import com.android.safetycenter.internaldata.SafetyCenterIssueActionId;
+import com.android.safetycenter.internaldata.SafetyCenterIssueKey;
+import com.android.safetycenter.logging.SafetyCenterStatsdLogger;
+
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Objects;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
+/**
+ * Repository for {@link SafetySourceData} and other data managed by Safety Center including {@link
+ * SafetySourceErrorDetails}.
+ *
+ * <p>This class isn't thread safe. Thread safety must be handled by the caller.
+ */
+@RequiresApi(TIRAMISU)
+@NotThreadSafe
+final class SafetySourceDataRepository {
+
+ private static final String TAG = "SafetySourceDataRepo";
+
+ private final ArrayMap<SafetySourceKey, SafetySourceData> mSafetySourceData = new ArrayMap<>();
+ private final ArraySet<SafetySourceKey> mSafetySourceErrors = new ArraySet<>();
+ 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}.
+ *
+ * <p>This method does not perform any validation, {@link
+ * SafetyCenterDataManager#setSafetySourceData(SafetySourceData, String, SafetyEvent, String,
+ * int)} should be called wherever validation is required.
+ *
+ * <p>Setting a {@code null} {@link SafetySourceData} evicts the current {@link
+ * SafetySourceData} entry and clears the {@link SafetyCenterIssueDismissalRepository} for the
+ * source.
+ *
+ * <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);
+
+ if (sourceDataDiffers) {
+ setSafetySourceDataInternal(key, safetySourceData);
+ }
+
+ setLastUpdatedNow(key);
+ return sourceDataDiffers || removedSourceError;
+ }
+
+ private void setSafetySourceDataInternal(SafetySourceKey key, @Nullable SafetySourceData data) {
+ ArraySet<String> issueIds = new ArraySet<>();
+ if (data == null) {
+ mSafetySourceData.remove(key);
+ mSourceStates.put(key, SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_CLEARED);
+ } else {
+ mSafetySourceData.put(key, data);
+ for (int i = 0; i < data.getIssues().size(); i++) {
+ issueIds.add(data.getIssues().get(i).getId());
+ }
+ mSourceStates.put(key, SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__DATA_PROVIDED);
+ }
+ mSafetyCenterIssueDismissalRepository.updateIssuesForSource(
+ issueIds, key.getSourceId(), key.getUserId());
+ }
+
+ /**
+ * Returns the latest {@link SafetySourceData} that was set by {@link #setSafetySourceData} for
+ * the given {@link SafetySourceKey}.
+ *
+ * <p>This method does not perform any validation, {@link
+ * SafetyCenterDataManager#getSafetySourceData(String, String, int)} should be called wherever
+ * validation is required.
+ *
+ * <p>Returns {@code null} if it was never set since boot, or if the entry was evicted using
+ * {@link #setSafetySourceData} with a {@code null} value.
+ */
+ @Nullable
+ SafetySourceData getSafetySourceData(SafetySourceKey safetySourceKey) {
+ return mSafetySourceData.get(safetySourceKey);
+ }
+
+ /** Returns {@code true} if the given source has an error. */
+ boolean sourceHasError(SafetySourceKey safetySourceKey) {
+ return mSafetySourceErrors.contains(safetySourceKey);
+ }
+
+ /**
+ * Reports the given {@link SafetySourceErrorDetails} for the given {@code safetySourceId} and
+ * {@code userId}, 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) {
+ SafetyEvent safetyEvent = safetySourceErrorDetails.getSafetyEvent();
+ Log.w(TAG, "Error reported from source: " + safetySourceId + ", for event: " + safetyEvent);
+
+ int safetyEventType = safetyEvent.getType();
+ if (safetyEventType == SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED
+ || safetyEventType == SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED) {
+ return false;
+ }
+
+ SafetySourceKey sourceKey = SafetySourceKey.of(safetySourceId, userId);
+ mSourceStates.put(sourceKey, SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_ERROR);
+ return setSafetySourceError(sourceKey);
+ }
+
+ /**
+ * Marks the given {@link SafetySourceKey} as having timed out during a refresh, and returns
+ * {@code true} if it caused a change to the stored data.
+ *
+ * @param setError whether we should clear the data associated with the source and set an error
+ */
+ boolean markSafetySourceRefreshTimedOut(SafetySourceKey sourceKey, boolean setError) {
+ mSourceStates.put(sourceKey, SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__REFRESH_TIMEOUT);
+ if (!setError) {
+ return false;
+ }
+ return setSafetySourceError(sourceKey);
+ }
+
+ /**
+ * Marks the given {@link SafetySourceKey} as being in an error state and returns {@code true}
+ * if this changed the repository's data.
+ */
+ private boolean setSafetySourceError(SafetySourceKey safetySourceKey) {
+ setLastUpdatedNow(safetySourceKey);
+ boolean removingSafetySourceDataChangedSafetyCenterData =
+ mSafetySourceData.remove(safetySourceKey) != null;
+ boolean addingSafetySourceErrorChangedSafetyCenterData =
+ mSafetySourceErrors.add(safetySourceKey);
+ return removingSafetySourceDataChangedSafetyCenterData
+ || addingSafetySourceErrorChangedSafetyCenterData;
+ }
+
+ /**
+ * Returns the {@link SafetySourceIssue} associated with the given {@link SafetyCenterIssueKey}.
+ *
+ * <p>Returns {@code null} if there is no such {@link SafetySourceIssue}.
+ */
+ @Nullable
+ SafetySourceIssue getSafetySourceIssue(SafetyCenterIssueKey safetyCenterIssueKey) {
+ SafetySourceKey key =
+ SafetySourceKey.of(
+ safetyCenterIssueKey.getSafetySourceId(), safetyCenterIssueKey.getUserId());
+ SafetySourceData safetySourceData = mSafetySourceData.get(key);
+ if (safetySourceData == null) {
+ return null;
+ }
+ List<SafetySourceIssue> safetySourceIssues = safetySourceData.getIssues();
+
+ SafetySourceIssue targetIssue = null;
+ for (int i = 0; i < safetySourceIssues.size(); i++) {
+ SafetySourceIssue safetySourceIssue = safetySourceIssues.get(i);
+
+ if (safetyCenterIssueKey.getSafetySourceIssueId().equals(safetySourceIssue.getId())) {
+ targetIssue = safetySourceIssue;
+ break;
+ }
+ }
+
+ return targetIssue;
+ }
+
+ /**
+ * Returns the {@link SafetySourceIssue.Action} associated with the given {@link
+ * SafetyCenterIssueActionId}.
+ *
+ * <p>Returns {@code null} if there is no associated {@link SafetySourceIssue}.
+ *
+ * <p>Returns {@code null} if the {@link SafetySourceIssue.Action} is currently in flight.
+ */
+ @Nullable
+ SafetySourceIssue.Action getSafetySourceIssueAction(
+ SafetyCenterIssueActionId safetyCenterIssueActionId) {
+ SafetySourceIssue safetySourceIssue =
+ getSafetySourceIssue(safetyCenterIssueActionId.getSafetyCenterIssueKey());
+
+ if (safetySourceIssue == null) {
+ return null;
+ }
+
+ return mSafetyCenterInFlightIssueActionRepository.getSafetySourceIssueAction(
+ safetyCenterIssueActionId, safetySourceIssue);
+ }
+
+ /**
+ * Returns the elapsed realtime millis of when the data of the given {@link SafetySourceKey} was
+ * last updated, or {@code 0L} if no update has occurred.
+ *
+ * @see SystemClock#elapsedRealtime()
+ */
+ @UptimeMillisLong
+ long getSafetySourceLastUpdated(SafetySourceKey sourceKey) {
+ Long lastUpdated = mSafetySourceLastUpdated.get(sourceKey);
+ if (lastUpdated != null) {
+ return lastUpdated;
+ } else {
+ return 0L;
+ }
+ }
+
+ private void setLastUpdatedNow(SafetySourceKey sourceKey) {
+ mSafetySourceLastUpdated.put(sourceKey, SystemClock.elapsedRealtime());
+ }
+
+ /**
+ * Returns the current {@link SafetyCenterStatsdLogger.SourceState} of the given {@link
+ * SafetySourceKey}.
+ */
+ @SafetyCenterStatsdLogger.SourceState
+ int getSourceState(SafetySourceKey sourceKey) {
+ Integer sourceState = mSourceStates.get(sourceKey);
+ if (sourceState != null) {
+ return sourceState;
+ } else {
+ return SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__NO_DATA_PROVIDED;
+ }
+ }
+
+ /** Clears all data for all users. */
+ void clear() {
+ mSafetySourceData.clear();
+ mSafetySourceErrors.clear();
+ mSafetySourceLastUpdated.clear();
+ mSourceStates.clear();
+ }
+
+ /** Clears all data for the given user. */
+ void clearForUser(@UserIdInt int userId) {
+ // Loop in reverse index order to be able to remove entries while iterating.
+ for (int i = mSafetySourceData.size() - 1; i >= 0; i--) {
+ SafetySourceKey sourceKey = mSafetySourceData.keyAt(i);
+ if (sourceKey.getUserId() == userId) {
+ mSafetySourceData.removeAt(i);
+ }
+ }
+ for (int i = mSafetySourceErrors.size() - 1; i >= 0; i--) {
+ SafetySourceKey sourceKey = mSafetySourceErrors.valueAt(i);
+ if (sourceKey.getUserId() == userId) {
+ mSafetySourceErrors.removeAt(i);
+ }
+ }
+ for (int i = mSafetySourceLastUpdated.size() - 1; i >= 0; i--) {
+ SafetySourceKey sourceKey = mSafetySourceLastUpdated.keyAt(i);
+ if (sourceKey.getUserId() == userId) {
+ mSafetySourceLastUpdated.removeAt(i);
+ }
+ }
+ for (int i = mSourceStates.size() - 1; i >= 0; i--) {
+ SafetySourceKey sourceKey = mSourceStates.keyAt(i);
+ if (sourceKey.getUserId() == userId) {
+ mSourceStates.removeAt(i);
+ }
+ }
+ }
+
+ /** Dumps state for debugging purposes. */
+ void dump(PrintWriter fout) {
+ dumpArrayMap(fout, mSafetySourceData, "SOURCE DATA");
+ int errorCount = mSafetySourceErrors.size();
+ fout.println("SOURCE ERRORS (" + errorCount + ")");
+ for (int i = 0; i < errorCount; i++) {
+ SafetySourceKey key = mSafetySourceErrors.valueAt(i);
+ fout.println("\t[" + i + "] " + key);
+ }
+ 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) {
+ int count = map.size();
+ fout.println(label + " (" + count + ")");
+ for (int i = 0; i < count; i++) {
+ fout.println("\t[" + i + "] " + map.keyAt(i) + " -> " + map.valueAt(i));
+ }
+ }
+}
diff --git a/service/java/com/android/safetycenter/data/SafetySourceDataValidator.java b/service/java/com/android/safetycenter/data/SafetySourceDataValidator.java
new file mode 100644
index 000000000..cc265d7f9
--- /dev/null
+++ b/service/java/com/android/safetycenter/data/SafetySourceDataValidator.java
@@ -0,0 +1,224 @@
+/*
+ * 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.TIRAMISU;
+
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceIssue;
+import android.safetycenter.SafetySourceStatus;
+import android.safetycenter.config.SafetySource;
+import android.util.Log;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.modules.utils.build.SdkLevel;
+import com.android.permission.util.UserUtils;
+import com.android.safetycenter.SafetyCenterConfigReader;
+import com.android.safetycenter.SafetyCenterFlags;
+import com.android.safetycenter.SafetySources;
+
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
+/**
+ * Validates calls made to the Safety Center API to get, set or clear {@link SafetySourceData}, or
+ * to report an error.
+ *
+ * <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 final Context mContext;
+ private final SafetyCenterConfigReader mSafetyCenterConfigReader;
+ private final PackageManager mPackageManager;
+
+ SafetySourceDataValidator(Context context, SafetyCenterConfigReader safetyCenterConfigReader) {
+ mContext = context;
+ mSafetyCenterConfigReader = safetyCenterConfigReader;
+ mPackageManager = mContext.getPackageManager();
+ }
+
+ /**
+ * Validates a call to the Safety Center API, from the given {@code packageName} and {@code
+ * userId} to get, set or clear {@link SafetySourceData}, or to report an error, for the given
+ * {@code safetySourceId}. Returns {@code true} if the call is valid and should proceed, or
+ * {@code false} otherwise.
+ *
+ * <p>This method may throw an {@link IllegalArgumentException} in some invalid cases.
+ *
+ * @param safetySourceData being set, or {@code null} if retrieving or clearing data, or
+ * reporting an error
+ */
+ boolean validateRequest(
+ @Nullable SafetySourceData safetySourceData,
+ String safetySourceId,
+ String packageName,
+ @UserIdInt int userId) {
+ SafetyCenterConfigReader.ExternalSafetySource externalSafetySource =
+ mSafetyCenterConfigReader.getExternalSafetySource(safetySourceId, packageName);
+ if (externalSafetySource == null) {
+ throw new IllegalArgumentException("Unexpected safety source: " + safetySourceId);
+ }
+
+ SafetySource safetySource = externalSafetySource.getSafetySource();
+ validateCallingPackage(safetySource, packageName, safetySourceId);
+
+ if (UserUtils.isManagedProfile(userId, mContext)
+ && !SafetySources.supportsManagedProfiles(safetySource)) {
+ throw new IllegalArgumentException(
+ "Unexpected managed profile request for safety source: " + safetySourceId);
+ }
+
+ boolean retrievingOrClearingData = safetySourceData == null;
+ if (retrievingOrClearingData) {
+ return mSafetyCenterConfigReader.isExternalSafetySourceActive(
+ safetySourceId, packageName);
+ }
+
+ SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
+
+ if (safetySource.getType() == SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY
+ && safetySourceStatus != null) {
+ throw new IllegalArgumentException(
+ "Unexpected status for issue only safety source: " + safetySourceId);
+ }
+
+ if (safetySource.getType() == SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC
+ && safetySourceStatus == null) {
+ throw new IllegalArgumentException(
+ "Missing status for dynamic safety source: " + safetySourceId);
+ }
+
+ if (safetySourceStatus != null) {
+ int sourceSeverityLevel = safetySourceStatus.getSeverityLevel();
+
+ if (externalSafetySource.hasEntryInStatelessGroup()
+ && sourceSeverityLevel != SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED) {
+ throw new IllegalArgumentException(
+ "Safety source: "
+ + safetySourceId
+ + " is in a stateless group but specified a severity level: "
+ + sourceSeverityLevel);
+ }
+
+ int maxSourceSeverityLevel =
+ Math.max(
+ SafetySourceData.SEVERITY_LEVEL_INFORMATION,
+ safetySource.getMaxSeverityLevel());
+
+ if (sourceSeverityLevel > maxSourceSeverityLevel) {
+ throw new IllegalArgumentException(
+ "Unexpected severity level: "
+ + sourceSeverityLevel
+ + ", for safety source: "
+ + safetySourceId);
+ }
+ }
+
+ List<SafetySourceIssue> safetySourceIssues = safetySourceData.getIssues();
+
+ for (int i = 0; i < safetySourceIssues.size(); i++) {
+ SafetySourceIssue safetySourceIssue = safetySourceIssues.get(i);
+ int issueSeverityLevel = safetySourceIssue.getSeverityLevel();
+ if (issueSeverityLevel > safetySource.getMaxSeverityLevel()) {
+ throw new IllegalArgumentException(
+ "Unexpected severity level: "
+ + issueSeverityLevel
+ + ", for issue in safety source: "
+ + safetySourceId);
+ }
+
+ int issueCategory = safetySourceIssue.getIssueCategory();
+ if (!SafetyCenterFlags.isIssueCategoryAllowedForSource(issueCategory, safetySourceId)) {
+ throw new IllegalArgumentException(
+ "Unexpected issue category: "
+ + issueCategory
+ + ", for issue in safety source: "
+ + safetySourceId);
+ }
+ }
+
+ return mSafetyCenterConfigReader.isExternalSafetySourceActive(safetySourceId, packageName);
+ }
+
+ private void validateCallingPackage(
+ SafetySource safetySource, String packageName, String safetySourceId) {
+ if (!packageName.equals(safetySource.getPackageName())) {
+ throw new IllegalArgumentException(
+ "Unexpected package name: "
+ + packageName
+ + ", for safety source: "
+ + safetySourceId);
+ }
+
+ if (!SdkLevel.isAtLeastU()) {
+ // No more validation checks possible on T devices
+ return;
+ }
+
+ Set<String> certificateHashes = safetySource.getPackageCertificateHashes();
+ if (certificateHashes.isEmpty()) {
+ Log.d(TAG, "No cert check requested for package " + packageName);
+ return;
+ }
+
+ if (!checkCerts(packageName, certificateHashes)
+ && !checkCerts(
+ packageName,
+ SafetyCenterFlags.getAdditionalAllowedPackageCerts(packageName))) {
+ Log.e(
+ TAG,
+ "Package "
+ + packageName
+ + " for source "
+ + safetySourceId
+ + " signed with invalid signature");
+ throw new IllegalArgumentException("Invalid signature for package " + packageName);
+ }
+ }
+
+ private boolean checkCerts(String packageName, Set<String> certificateHashes) {
+ boolean hasMatchingCert = false;
+ for (String certHash : certificateHashes) {
+ try {
+ byte[] certificate = new Signature(certHash).toByteArray();
+ if (mPackageManager.hasSigningCertificate(
+ packageName, certificate, PackageManager.CERT_INPUT_SHA256)) {
+ Log.d(TAG, "Package " + packageName + " has expected signature");
+ hasMatchingCert = true;
+ }
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Failed to parse signing certificate: " + certHash, e);
+ throw new IllegalStateException(
+ "Failed to parse signing certificate: " + certHash, e);
+ }
+ }
+ return hasMatchingCert;
+ }
+}
diff --git a/service/java/com/android/safetycenter/data/SafetySourceStateCollectedLogger.java b/service/java/com/android/safetycenter/data/SafetySourceStateCollectedLogger.java
new file mode 100644
index 000000000..b6bf280ae
--- /dev/null
+++ b/service/java/com/android/safetycenter/data/SafetySourceStateCollectedLogger.java
@@ -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.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;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceIssue;
+import android.safetycenter.SafetySourceStatus;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.permission.util.UserUtils;
+import com.android.safetycenter.SafetySourceIssueInfo;
+import com.android.safetycenter.SafetySourceKey;
+import com.android.safetycenter.internaldata.SafetyCenterIssueKey;
+import com.android.safetycenter.logging.SafetyCenterStatsdLogger;
+
+import java.util.Collections;
+import java.util.List;
+
+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 {
+
+ private final Context mContext;
+ private final SafetySourceDataRepository mSourceDataRepository;
+ private final SafetyCenterIssueDismissalRepository mIssueDismissalRepository;
+ private final SafetyCenterIssueRepository mIssueRepository;
+
+ SafetySourceStateCollectedLogger(
+ Context context,
+ SafetySourceDataRepository sourceDataRepository,
+ SafetyCenterIssueDismissalRepository issueDismissalRepository,
+ SafetyCenterIssueRepository issueRepository) {
+ mContext = context;
+ mSourceDataRepository = sourceDataRepository;
+ mIssueDismissalRepository = issueDismissalRepository;
+ mIssueRepository = issueRepository;
+ }
+
+ /**
+ * Writes a SafetySourceStateCollected atom for the given source in response to a stats pull.
+ */
+ void writeAutomaticAtom(SafetySourceKey sourceKey, boolean isManagedProfile) {
+ logSafetySourceStateCollected(
+ sourceKey,
+ mSourceDataRepository.getSafetySourceData(sourceKey),
+ /* refreshReason= */ null,
+ /* sourceDataDiffers= */ false,
+ isManagedProfile,
+ /* safetyEvent= */ null,
+ mSourceDataRepository.getSafetySourceLastUpdated(sourceKey));
+ }
+
+ /**
+ * Writes a SafetySourceStateCollected atom for the given source in response to that source
+ * updating its own state.
+ */
+ void writeSourceUpdatedAtom(
+ SafetySourceKey key,
+ @Nullable SafetySourceData safetySourceData,
+ @Nullable @SafetyCenterManager.RefreshReason Integer refreshReason,
+ boolean sourceDataDiffers,
+ int userId,
+ SafetyEvent safetyEvent) {
+ logSafetySourceStateCollected(
+ key,
+ safetySourceData,
+ refreshReason,
+ sourceDataDiffers,
+ UserUtils.isManagedProfile(userId, mContext),
+ safetyEvent,
+ /* lastUpdatedElapsedTimeMillis= */ null);
+ }
+
+ private void logSafetySourceStateCollected(
+ SafetySourceKey sourceKey,
+ @Nullable SafetySourceData sourceData,
+ @Nullable @SafetyCenterManager.RefreshReason Integer refreshReason,
+ boolean sourceDataDiffers,
+ boolean isManagedProfile,
+ @Nullable SafetyEvent safetyEvent,
+ @Nullable @ElapsedRealtimeLong Long lastUpdatedElapsedTimeMillis) {
+ SafetySourceStatus sourceStatus = sourceData == null ? null : sourceData.getStatus();
+ List<SafetySourceIssue> sourceIssues =
+ sourceData == null ? Collections.emptyList() : sourceData.getIssues();
+
+ int maxSeverityLevel = Integer.MIN_VALUE;
+ if (sourceStatus != null) {
+ maxSeverityLevel = sourceStatus.getSeverityLevel();
+ } else if (sourceData != null) {
+ // In this case we know we have an issue-only source because of the checks carried out
+ // in the validateRequest function.
+ maxSeverityLevel = SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED;
+ }
+
+ long openIssuesCount = 0;
+ long dismissedIssuesCount = 0;
+ for (int i = 0; i < sourceIssues.size(); i++) {
+ SafetySourceIssue issue = sourceIssues.get(i);
+ if (isIssueDismissed(issue, sourceKey)) {
+ dismissedIssuesCount++;
+ } else {
+ openIssuesCount++;
+ maxSeverityLevel = Math.max(maxSeverityLevel, issue.getSeverityLevel());
+ }
+ }
+
+ SafetyCenterStatsdLogger.writeSafetySourceStateCollected(
+ sourceKey.getSourceId(),
+ isManagedProfile,
+ maxSeverityLevel > Integer.MIN_VALUE ? maxSeverityLevel : null,
+ openIssuesCount,
+ dismissedIssuesCount,
+ getDuplicateCount(sourceKey),
+ mSourceDataRepository.getSourceState(sourceKey),
+ safetyEvent,
+ refreshReason,
+ sourceDataDiffers,
+ lastUpdatedElapsedTimeMillis);
+ }
+
+ private boolean isIssueDismissed(SafetySourceIssue issue, SafetySourceKey sourceKey) {
+ SafetyCenterIssueKey issueKey =
+ SafetyCenterIssueKey.newBuilder()
+ .setSafetySourceId(sourceKey.getSourceId())
+ .setSafetySourceIssueId(issue.getId())
+ .setUserId(sourceKey.getUserId())
+ .build();
+ return mIssueDismissalRepository.isIssueDismissed(issueKey, issue.getSeverityLevel());
+ }
+
+ private long getDuplicateCount(SafetySourceKey sourceKey) {
+ long count = 0;
+ List<SafetySourceIssueInfo> duplicates =
+ mIssueRepository.getLatestDuplicates(sourceKey.getUserId());
+ for (int i = 0; i < duplicates.size(); i++) {
+ if (duplicates.get(i).getSafetySource().getId().equals(sourceKey.getSourceId())) {
+ count++;
+ }
+ }
+ return count;
+ }
+}
diff --git a/service/java/com/android/safetycenter/data/package-info.java b/service/java/com/android/safetycenter/data/package-info.java
new file mode 100644
index 000000000..597847505
--- /dev/null
+++ b/service/java/com/android/safetycenter/data/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@NonNullByDefault
+package com.android.safetycenter.data;
+
+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
new file mode 100644
index 000000000..d9514f56e
--- /dev/null
+++ b/service/java/com/android/safetycenter/logging/SafetyCenterPullAtomCallback.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.logging;
+
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import static com.android.permission.PermissionStatsLog.SAFETY_STATE;
+
+import android.annotation.UserIdInt;
+import android.app.StatsManager;
+import android.app.StatsManager.StatsPullAtomCallback;
+import android.content.Context;
+import android.safetycenter.SafetyCenterData;
+import android.safetycenter.config.SafetySource;
+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;
+import com.android.safetycenter.ApiLock;
+import com.android.safetycenter.SafetyCenterConfigReader;
+import com.android.safetycenter.SafetyCenterDataFactory;
+import com.android.safetycenter.SafetyCenterFlags;
+import com.android.safetycenter.SafetySourceKey;
+import com.android.safetycenter.SafetySources;
+import com.android.safetycenter.UserProfileGroup;
+import com.android.safetycenter.data.SafetyCenterDataManager;
+
+import java.util.List;
+
+/**
+ * A {@link StatsPullAtomCallback} that provides a {@link PermissionStatsLog#SAFETY_STATE} atom that
+ * when requested by the {@link StatsManager}.
+ *
+ * <p>Whenever that atom, which describes the overall Safety Center, is pulled this class also
+ * separately writes one {@code SAFETY_SOURCE_STATE_COLLECTED} atom for each active source (per
+ * profile).
+ *
+ * @hide
+ */
+@RequiresApi(TIRAMISU)
+public final class SafetyCenterPullAtomCallback implements StatsPullAtomCallback {
+
+ private static final String TAG = "SafetyCenterPullAtom";
+
+ private final Context mContext;
+ private final ApiLock mApiLock;
+
+ @GuardedBy("mApiLock")
+ private final SafetyCenterConfigReader mSafetyCenterConfigReader;
+
+ @GuardedBy("mApiLock")
+ private final SafetyCenterDataFactory mDataFactory;
+
+ @GuardedBy("mApiLock")
+ private final SafetyCenterDataManager mDataManager;
+
+ public SafetyCenterPullAtomCallback(
+ Context context,
+ ApiLock apiLock,
+ SafetyCenterConfigReader safetyCenterConfigReader,
+ SafetyCenterDataFactory dataFactory,
+ SafetyCenterDataManager dataManager) {
+ mContext = context;
+ mApiLock = apiLock;
+ mSafetyCenterConfigReader = safetyCenterConfigReader;
+ mDataFactory = dataFactory;
+ mDataManager = dataManager;
+ }
+
+ @Override
+ public int onPullAtom(int atomTag, List<StatsEvent> statsEvents) {
+ if (atomTag != SAFETY_STATE) {
+ Log.w(TAG, "Attempt to pull atom: " + atomTag + ", but only SAFETY_STATE is supported");
+ return StatsManager.PULL_SKIP;
+ }
+ if (!SafetyCenterFlags.getSafetyCenterEnabled()) {
+ Log.w(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");
+ return StatsManager.PULL_SKIP;
+ }
+ Log.i(TAG, "Pulling and writing atoms…");
+ for (int i = 0; i < userProfileGroups.size(); i++) {
+ UserProfileGroup userProfileGroup = userProfileGroups.get(i);
+ List<SafetySourcesGroup> loggableGroups =
+ mSafetyCenterConfigReader.getLoggableSafetySourcesGroups();
+ 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.
+ writeSafetySourceStateCollectedAtomsLocked(userProfileGroup, loggableGroups);
+ }
+ }
+ return StatsManager.PULL_SUCCESS;
+ }
+
+ @GuardedBy("mApiLock")
+ private StatsEvent createOverallSafetyStateAtomLocked(
+ UserProfileGroup userProfileGroup, List<SafetySourcesGroup> loggableGroups) {
+ SafetyCenterData loggableData =
+ mDataFactory.assembleSafetyCenterData("android", userProfileGroup, loggableGroups);
+ long openIssuesCount = loggableData.getIssues().size();
+ long dismissedIssuesCount = getDismissedIssuesCountLocked(loggableData, userProfileGroup);
+
+ return SafetyCenterStatsdLogger.createSafetyStateEvent(
+ loggableData.getStatus().getSeverityLevel(), openIssuesCount, dismissedIssuesCount);
+ }
+
+ @GuardedBy("mApiLock")
+ private long getDismissedIssuesCountLocked(
+ SafetyCenterData loggableData, UserProfileGroup userProfileGroup) {
+ if (SdkLevel.isAtLeastU()) {
+ return loggableData.getDismissedIssues().size();
+ }
+ long openIssuesCount = loggableData.getIssues().size();
+ return mDataManager.countLoggableIssuesFor(userProfileGroup) - openIssuesCount;
+ }
+
+ @GuardedBy("mApiLock")
+ private void writeSafetySourceStateCollectedAtomsLocked(
+ UserProfileGroup userProfileGroup, List<SafetySourcesGroup> loggableGroups) {
+ for (int i = 0; i < loggableGroups.size(); i++) {
+ List<SafetySource> loggableSources = loggableGroups.get(i).getSafetySources();
+
+ for (int j = 0; j < loggableSources.size(); j++) {
+ SafetySource loggableSource = loggableSources.get(j);
+
+ if (!SafetySources.isExternal(loggableSource)) {
+ continue;
+ }
+
+ writeSafetySourceStateCollectedAtomLocked(
+ loggableSource,
+ userProfileGroup.getProfileParentUserId(),
+ /* isUserManaged= */ false);
+
+ if (!SafetySources.supportsManagedProfiles(loggableSource)) {
+ continue;
+ }
+
+ int[] managedIds = userProfileGroup.getManagedRunningProfilesUserIds();
+ for (int k = 0; k < managedIds.length; k++) {
+ writeSafetySourceStateCollectedAtomLocked(loggableSource, managedIds[k], true);
+ }
+ }
+ }
+ }
+
+ @GuardedBy("mApiLock")
+ private void writeSafetySourceStateCollectedAtomLocked(
+ SafetySource safetySource, @UserIdInt int userId, boolean isUserManaged) {
+ SafetySourceKey sourceKey = SafetySourceKey.of(safetySource.getId(), userId);
+ mDataManager.logSafetySourceStateCollectedAutomatic(sourceKey, isUserManaged);
+ }
+}
diff --git a/service/java/com/android/safetycenter/logging/SafetyCenterStatsdLogger.java b/service/java/com/android/safetycenter/logging/SafetyCenterStatsdLogger.java
new file mode 100644
index 000000000..8ca662d27
--- /dev/null
+++ b/service/java/com/android/safetycenter/logging/SafetyCenterStatsdLogger.java
@@ -0,0 +1,485 @@
+/*
+ * 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.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;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ACTION__NOTIFICATION_DISMISSED;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ACTION__NOTIFICATION_POSTED;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ISSUE_STATE__ACTIVE;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__NAVIGATION_SOURCE__SOURCE_UNKNOWN;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SENSOR__SENSOR_UNKNOWN;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_OK;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_UNSPECIFIED;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__VIEW_TYPE__VIEW_TYPE_NOTIFICATION;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__COMPLETE_GET_NEW_DATA;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__COMPLETE_RESCAN;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_UNKNOWN;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__INLINE_ACTION;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__SINGLE_SOURCE_GET_NEW_DATA;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__SINGLE_SOURCE_RESCAN;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__ERROR;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__SUCCESS;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__TIMEOUT;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL;
+import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_UNKNOWN;
+import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED;
+import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__COLLECTION_TYPE__AUTOMATIC;
+import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__COLLECTION_TYPE__SOURCE_UPDATED;
+import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED;
+import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL;
+import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING;
+import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
+import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_OK;
+import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION;
+import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_UNSPECIFIED;
+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_ERROR;
+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 static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_STATE_UNKNOWN;
+import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__REFRESH_RESPONSE;
+import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__SELF_INITIATED;
+import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__UPDATE_TYPE_UNKNOWN;
+import static com.android.permission.PermissionStatsLog.SAFETY_STATE;
+import static com.android.permission.PermissionStatsLog.SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING;
+import static com.android.permission.PermissionStatsLog.SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
+import static com.android.permission.PermissionStatsLog.SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_OK;
+import static com.android.permission.PermissionStatsLog.SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION;
+
+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;
+import android.safetycenter.SafetyEvent;
+import android.safetycenter.SafetySourceData;
+import android.util.Log;
+import android.util.StatsEvent;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.permission.PermissionStatsLog;
+import com.android.safetycenter.SafetyCenterFlags;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.time.Duration;
+
+/**
+ * Marshalls and writes statsd atoms. Contains implementation details of how atom parameters are
+ * encoded and provides a better-typed interface for other classes to call.
+ *
+ * @hide
+ */
+@RequiresApi(TIRAMISU)
+public final class SafetyCenterStatsdLogger {
+
+ private static final String TAG = "SafetyCenterStatsdLog";
+ private static final long UNSET_SOURCE_ID = 0;
+ private static final long UNSET_ISSUE_TYPE_ID = 0;
+ private static final long UNSET_SESSION_ID = 0;
+ private static final long UNSET_SOURCE_GROUP_ID = 0;
+ private static final long UNSET_REFRESH_REASON = 0L;
+ private static final boolean UNSET_DATA_CHANGED = false;
+ private static final long UNSET_LAST_UPDATED_ELAPSED_TIME_MILLIS = 0L;
+
+ /**
+ * The different results for a system event reported by Safety Center.
+ *
+ * @hide
+ */
+ @IntDef(
+ prefix = {"SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__"},
+ value = {
+ SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__SUCCESS,
+ SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__ERROR,
+ SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__TIMEOUT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SystemEventResult {}
+
+ /**
+ * The different results for a system event reported by Safety Center.
+ *
+ * @hide
+ */
+ @IntDef(
+ prefix = {"SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__"},
+ value = {
+ SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_STATE_UNKNOWN,
+ SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__DATA_PROVIDED,
+ SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__NO_DATA_PROVIDED,
+ SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__REFRESH_TIMEOUT,
+ SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__REFRESH_ERROR,
+ SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_ERROR,
+ SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_CLEARED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SourceState {}
+
+ /**
+ * Creates a {@link PermissionStatsLog#SAFETY_STATE} {@link StatsEvent} with the given
+ * parameters.
+ */
+ static StatsEvent createSafetyStateEvent(
+ @SafetyCenterStatus.OverallSeverityLevel int severityLevel,
+ long openIssueCount,
+ long dismissedIssueCount) {
+ return PermissionStatsLog.buildStatsEvent(
+ SAFETY_STATE,
+ toSafetyStateOverallSeverityLevel(severityLevel),
+ openIssueCount,
+ dismissedIssueCount);
+ }
+
+ /** Writes a {@link PermissionStatsLog#SAFETY_SOURCE_STATE_COLLECTED} atom. */
+ public static void writeSafetySourceStateCollected(
+ String sourceId,
+ boolean isManagedProfile,
+ @Nullable @SafetySourceData.SeverityLevel Integer sourceSeverityLevel,
+ long openIssuesCount,
+ long dismissedIssuesCount,
+ long duplicateFilteredOutIssuesCount,
+ @SourceState int sourceState,
+ @Nullable SafetyEvent safetyEvent,
+ @Nullable @SafetyCenterManager.RefreshReason Integer refreshReason,
+ boolean dataChanged,
+ @Nullable @ElapsedRealtimeLong Long lastUpdatedElapsedTimeMillis) {
+ if (!SafetyCenterFlags.getAllowStatsdLogging()) {
+ return;
+ }
+ int collectionType =
+ safetyEvent != null
+ ? SAFETY_SOURCE_STATE_COLLECTED__COLLECTION_TYPE__SOURCE_UPDATED
+ : SAFETY_SOURCE_STATE_COLLECTED__COLLECTION_TYPE__AUTOMATIC;
+ PermissionStatsLog.write(
+ SAFETY_SOURCE_STATE_COLLECTED,
+ idStringToLong(sourceId),
+ toSourceStateCollectedProfileType(isManagedProfile),
+ toSafetySourceStateCollectedSeverityLevel(sourceSeverityLevel),
+ openIssuesCount,
+ dismissedIssuesCount,
+ duplicateFilteredOutIssuesCount,
+ sourceState,
+ collectionType,
+ toSafetySourceStateCollectedCollectionType(safetyEvent),
+ refreshReason != null ? refreshReason : UNSET_REFRESH_REASON,
+ dataChanged,
+ lastUpdatedElapsedTimeMillis != null
+ ? lastUpdatedElapsedTimeMillis
+ : UNSET_LAST_UPDATED_ELAPSED_TIME_MILLIS);
+ }
+
+ /**
+ * Writes a {@link PermissionStatsLog#SAFETY_CENTER_SYSTEM_EVENT_REPORTED} atom of type {@code
+ * SINGLE_SOURCE_RESCAN} or {@code SINGLE_SOURCE_GET_DATA}.
+ */
+ public static void writeSourceRefreshSystemEvent(
+ @RefreshRequestType int refreshType,
+ String sourceId,
+ boolean isManagedProfile,
+ Duration duration,
+ @SystemEventResult int result,
+ long refreshReason,
+ boolean dataChanged) {
+ if (!SafetyCenterFlags.getAllowStatsdLogging()) {
+ return;
+ }
+ PermissionStatsLog.write(
+ SAFETY_CENTER_SYSTEM_EVENT_REPORTED,
+ toSourceRefreshEventType(refreshType),
+ idStringToLong(sourceId),
+ toSystemEventProfileType(isManagedProfile),
+ UNSET_ISSUE_TYPE_ID,
+ duration.toMillis(),
+ result,
+ refreshReason,
+ dataChanged);
+ }
+
+ /**
+ * Writes a {@link PermissionStatsLog#SAFETY_CENTER_SYSTEM_EVENT_REPORTED} atom of type {@code
+ * COMPLETE_RESCAN} or {@code COMPLETE_GET_DATA}.
+ */
+ public static void writeWholeRefreshSystemEvent(
+ @RefreshRequestType int refreshType,
+ Duration duration,
+ @SystemEventResult int result,
+ long refreshReason,
+ boolean dataChanged) {
+ if (!SafetyCenterFlags.getAllowStatsdLogging()) {
+ return;
+ }
+ PermissionStatsLog.write(
+ SAFETY_CENTER_SYSTEM_EVENT_REPORTED,
+ toWholeRefreshEventType(refreshType),
+ UNSET_SOURCE_ID,
+ SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_UNKNOWN,
+ UNSET_ISSUE_TYPE_ID,
+ duration.toMillis(),
+ result,
+ refreshReason,
+ dataChanged);
+ }
+
+ /**
+ * Writes a {@link PermissionStatsLog#SAFETY_CENTER_SYSTEM_EVENT_REPORTED} atom of type {@code
+ * INLINE_ACTION}.
+ */
+ public static void writeInlineActionSystemEvent(
+ String sourceId,
+ boolean isManagedProfile,
+ @Nullable String issueTypeId,
+ Duration duration,
+ @SystemEventResult int result) {
+ if (!SafetyCenterFlags.getAllowStatsdLogging()) {
+ return;
+ }
+ PermissionStatsLog.write(
+ SAFETY_CENTER_SYSTEM_EVENT_REPORTED,
+ SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__INLINE_ACTION,
+ idStringToLong(sourceId),
+ toSystemEventProfileType(isManagedProfile),
+ issueTypeId == null ? UNSET_ISSUE_TYPE_ID : idStringToLong(issueTypeId),
+ duration.toMillis(),
+ result,
+ UNSET_REFRESH_REASON,
+ UNSET_DATA_CHANGED);
+ }
+
+ /**
+ * Writes a {@link PermissionStatsLog#SAFETY_CENTER_INTERACTION_REPORTED} atom with the action
+ * {@code NOTIFICATION_POSTED}.
+ */
+ public static void writeNotificationPostedEvent(
+ String sourceId,
+ boolean isManagedProfile,
+ String issueTypeId,
+ @SafetySourceData.SeverityLevel int sourceSeverityLevel) {
+ writeNotificationInteractionReportedEvent(
+ SAFETY_CENTER_INTERACTION_REPORTED__ACTION__NOTIFICATION_POSTED,
+ sourceId,
+ isManagedProfile,
+ issueTypeId,
+ sourceSeverityLevel);
+ }
+
+ /**
+ * Writes a {@link PermissionStatsLog#SAFETY_CENTER_INTERACTION_REPORTED} atom with the action
+ * {@code NOTIFICATION_DISMISSED}.
+ */
+ public static void writeNotificationDismissedEvent(
+ String sourceId,
+ boolean isManagedProfile,
+ String issueTypeId,
+ @SafetySourceData.SeverityLevel int sourceSeverityLevel) {
+ writeNotificationInteractionReportedEvent(
+ SAFETY_CENTER_INTERACTION_REPORTED__ACTION__NOTIFICATION_DISMISSED,
+ sourceId,
+ isManagedProfile,
+ issueTypeId,
+ sourceSeverityLevel);
+ }
+
+ /**
+ * Writes a {@link PermissionStatsLog#SAFETY_CENTER_INTERACTION_REPORTED} atom with the action
+ * {@code ISSUE_PRIMARY_ACTION_CLICKED} or {@code ISSUE_SECONDARY_ACTION_CLICKED}.
+ */
+ public static void writeNotificationActionClickedEvent(
+ String sourceId,
+ boolean isManagedProfile,
+ String issueTypeId,
+ @SafetySourceData.SeverityLevel int sourceSeverityLevel,
+ boolean isPrimaryAction) {
+ int action =
+ isPrimaryAction
+ ? SAFETY_CENTER_INTERACTION_REPORTED__ACTION__ISSUE_PRIMARY_ACTION_CLICKED
+ : SAFETY_CENTER_INTERACTION_REPORTED__ACTION__ISSUE_SECONDARY_ACTION_CLICKED;
+ writeNotificationInteractionReportedEvent(
+ action, sourceId, isManagedProfile, issueTypeId, sourceSeverityLevel);
+ }
+
+ private static void writeNotificationInteractionReportedEvent(
+ int interactionReportedAction,
+ String sourceId,
+ boolean isManagedProfile,
+ String issueTypeId,
+ @SafetySourceData.SeverityLevel int sourceSeverityLevel) {
+ if (!SafetyCenterFlags.getAllowStatsdLogging()) {
+ return;
+ }
+ PermissionStatsLog.write(
+ SAFETY_CENTER_INTERACTION_REPORTED,
+ UNSET_SESSION_ID,
+ interactionReportedAction,
+ SAFETY_CENTER_INTERACTION_REPORTED__VIEW_TYPE__VIEW_TYPE_NOTIFICATION,
+ SAFETY_CENTER_INTERACTION_REPORTED__NAVIGATION_SOURCE__SOURCE_UNKNOWN,
+ toInteractionReportedSeverityLevel(sourceSeverityLevel),
+ idStringToLong(sourceId),
+ toInteractionReportedProfileType(isManagedProfile),
+ idStringToLong(issueTypeId),
+ SAFETY_CENTER_INTERACTION_REPORTED__SENSOR__SENSOR_UNKNOWN,
+ UNSET_SOURCE_GROUP_ID,
+ SAFETY_CENTER_INTERACTION_REPORTED__ISSUE_STATE__ACTIVE);
+ }
+
+ /**
+ * Returns a {@link SystemEventResult} based on whether the given operation was {@code
+ * successful}.
+ */
+ @SystemEventResult
+ public static int toSystemEventResult(boolean success) {
+ return success
+ ? SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__SUCCESS
+ : SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__ERROR;
+ }
+
+ private static int toSourceRefreshEventType(@RefreshRequestType int refreshType) {
+ switch (refreshType) {
+ case SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_GET_DATA:
+ return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__SINGLE_SOURCE_GET_NEW_DATA;
+ case SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA:
+ return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__SINGLE_SOURCE_RESCAN;
+ }
+ Log.w(TAG, "Unexpected SafetyCenterManager.RefreshRequestType: " + refreshType);
+ return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_UNKNOWN;
+ }
+
+ private static int toWholeRefreshEventType(@RefreshRequestType int refreshType) {
+ switch (refreshType) {
+ case SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_GET_DATA:
+ return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__COMPLETE_GET_NEW_DATA;
+ case SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA:
+ return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__COMPLETE_RESCAN;
+ }
+ Log.w(TAG, "Unexpected SafetyCenterManager.RefreshRequestType: " + refreshType);
+ return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_UNKNOWN;
+ }
+
+ private static int toSourceStateCollectedProfileType(boolean isManagedProfile) {
+ return isManagedProfile
+ ? SAFETY_SOURCE_STATE_COLLECTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED
+ : SAFETY_SOURCE_STATE_COLLECTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL;
+ }
+
+ private static int toSystemEventProfileType(boolean isManagedProfile) {
+ return isManagedProfile
+ ? SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED
+ : SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL;
+ }
+
+ private static int toInteractionReportedProfileType(boolean isManagedProfile) {
+ return isManagedProfile
+ ? SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED
+ : SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL;
+ }
+
+ /**
+ * Converts a {@link String} ID (e.g. a Safety Source ID) to a {@code long} suitable for logging
+ * to statsd.
+ */
+ private static long idStringToLong(String id) {
+ MessageDigest messageDigest;
+ try {
+ messageDigest = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ Log.w(TAG, "Couldn't encode safety source id: " + id, e);
+ return 0;
+ }
+ messageDigest.update(id.getBytes());
+ return new BigInteger(messageDigest.digest()).longValue();
+ }
+
+ private static int toSafetyStateOverallSeverityLevel(
+ @SafetyCenterStatus.OverallSeverityLevel int severityLevel) {
+ switch (severityLevel) {
+ case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN:
+ return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
+ case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK:
+ return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_OK;
+ case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION:
+ return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION;
+ case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING:
+ return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING;
+ }
+ Log.w(TAG, "Unexpected SafetyCenterStatus.OverallSeverityLevel: " + severityLevel);
+ return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
+ }
+
+ private static int toSafetySourceStateCollectedSeverityLevel(
+ @Nullable @SafetySourceData.SeverityLevel Integer safetySourceSeverityLevel) {
+ if (safetySourceSeverityLevel == null) {
+ return SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
+ }
+ switch (safetySourceSeverityLevel) {
+ case SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED:
+ return SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_UNSPECIFIED;
+ case SafetySourceData.SEVERITY_LEVEL_INFORMATION:
+ return SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_OK;
+ case SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION:
+ return SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION;
+ case SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING:
+ return SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING;
+ }
+ Log.w(TAG, "Unexpected SafetySourceData.SeverityLevel: " + safetySourceSeverityLevel);
+ return SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
+ }
+
+ private static int toInteractionReportedSeverityLevel(
+ @SafetySourceData.SeverityLevel int severityLevel) {
+ switch (severityLevel) {
+ case SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED:
+ return SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_UNSPECIFIED;
+ case SafetySourceData.SEVERITY_LEVEL_INFORMATION:
+ return SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_OK;
+ case SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION:
+ return SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION;
+ case SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING:
+ return SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING;
+ }
+ Log.w(TAG, "Unexpected SafetySourceData.SeverityLevel: " + severityLevel);
+ return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
+ }
+
+ private static int toSafetySourceStateCollectedCollectionType(
+ @Nullable SafetyEvent safetyEvent) {
+ if (safetyEvent == null) {
+ return SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__UPDATE_TYPE_UNKNOWN;
+ }
+ if (safetyEvent.getType() == SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED) {
+ return SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__REFRESH_RESPONSE;
+ } else {
+ return SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__SELF_INITIATED;
+ }
+ }
+}
diff --git a/service/java/com/android/safetycenter/logging/package-info.java b/service/java/com/android/safetycenter/logging/package-info.java
new file mode 100644
index 000000000..dcc1828b4
--- /dev/null
+++ b/service/java/com/android/safetycenter/logging/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@NonNullByDefault
+package com.android.safetycenter.logging;
+
+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
new file mode 100644
index 000000000..e2df717a7
--- /dev/null
+++ b/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationChannels.java
@@ -0,0 +1,205 @@
+/*
+ * 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.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;
+import android.content.Context;
+import android.os.Binder;
+import android.os.UserHandle;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceIssue;
+import android.util.Log;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.permission.util.UserUtils;
+import com.android.safetycenter.resources.SafetyCenterResourcesContext;
+
+import java.util.List;
+
+/**
+ * Class responsible for creating and updating Safety Center's notification channels.
+ *
+ * @hide
+ */
+@RequiresApi(TIRAMISU)
+public final class SafetyCenterNotificationChannels {
+
+ private static final String TAG = "SafetyCenterNC";
+
+ private static final String CHANNEL_GROUP_ID = "safety_center_channels";
+ private static final String CHANNEL_ID_INFORMATION = "safety_center_information";
+ 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;
+
+ public SafetyCenterNotificationChannels(
+ SafetyCenterResourcesContext safetyCenterResourceContext) {
+ mResourcesContext = safetyCenterResourceContext;
+ }
+
+ /** Returns a {@link NotificationManager} which will send notifications to the given user. */
+ @Nullable
+ static NotificationManager getNotificationManagerForUser(
+ Context baseContext, UserHandle userHandle) {
+ Context contextAsUser = getContextAsUser(baseContext, userHandle);
+ NotificationManager notificationManager =
+ (contextAsUser != null)
+ ? contextAsUser.getSystemService(NotificationManager.class)
+ : null;
+ if (notificationManager == null) {
+ Log.w(TAG, "Could not retrieve NotificationManager for user " + userHandle);
+ }
+ return notificationManager;
+ }
+
+ @Nullable
+ private static Context getContextAsUser(Context baseContext, UserHandle userHandle) {
+ try {
+ return baseContext.createContextAsUser(userHandle, 0);
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Could not create Context as user " + userHandle, e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the ID of the appropriate {@link NotificationChannel} for a notification about the
+ * given {@code issue} after ensuring that channel has been created.
+ */
+ @Nullable
+ String getCreatedChannelId(NotificationManager notificationManager, SafetySourceIssue issue) {
+ try {
+ createAllChannelsWithoutCallingIdentity(notificationManager);
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Unable to create notification channels", e);
+ return null;
+ }
+ return getChannelIdForIssue(issue);
+ }
+
+ /**
+ * 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.
+ */
+ public void createAllChannelsForAllUsers(Context context) {
+ List<UserHandle> users = UserUtils.getUserHandles(context);
+ for (int i = 0; i < users.size(); i++) {
+ createAllChannelsForUser(context, users.get(i));
+ }
+ }
+
+ /**
+ * 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) {
+ try {
+ NotificationManager notificationManager =
+ requireNonNull(getNotificationManagerForUser(context, user));
+ createAllChannelsWithoutCallingIdentity(notificationManager);
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Error creating notification channels for user " + user.getIdentifier(), e);
+ }
+ }
+
+ @Nullable
+ private String getChannelIdForIssue(SafetySourceIssue issue) {
+ switch (issue.getSeverityLevel()) {
+ 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);
+ return null;
+ }
+ }
+
+ /**
+ * Creates all Safety Center {@link NotificationChannel}s instances and their group using the
+ * given {@link NotificationManager}, dropping any calling identity so those channels can be
+ * unblockable. Throws a {@link RuntimeException} if any channel is malformed and could not be
+ * created.
+ */
+ private void createAllChannelsWithoutCallingIdentity(NotificationManager notificationManager) {
+ // Clearing calling identity to be able to make unblockable system notification channels
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ notificationManager.createNotificationChannelGroup(getChannelGroupDefinition());
+ notificationManager.createNotificationChannel(getInformationChannelDefinition());
+ notificationManager.createNotificationChannel(getRecommendationChannelDefinition());
+ notificationManager.createNotificationChannel(getCriticalWarningChannelDefinition());
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ private NotificationChannelGroup getChannelGroupDefinition() {
+ return new NotificationChannelGroup(
+ CHANNEL_GROUP_ID, getString("notification_channel_group_name"));
+ }
+
+ private NotificationChannel getInformationChannelDefinition() {
+ NotificationChannel channel =
+ new NotificationChannel(
+ CHANNEL_ID_INFORMATION,
+ getString("notification_channel_name_information"),
+ NotificationManager.IMPORTANCE_LOW);
+ channel.setGroup(CHANNEL_GROUP_ID);
+ channel.setBlockable(true);
+ return channel;
+ }
+
+ private NotificationChannel getRecommendationChannelDefinition() {
+ NotificationChannel channel =
+ new NotificationChannel(
+ CHANNEL_ID_RECOMMENDATION,
+ getString("notification_channel_name_recommendation"),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ channel.setGroup(CHANNEL_GROUP_ID);
+ channel.setBlockable(false);
+ return channel;
+ }
+
+ private NotificationChannel getCriticalWarningChannelDefinition() {
+ NotificationChannel channel =
+ new NotificationChannel(
+ CHANNEL_ID_CRITICAL_WARNING,
+ getString("notification_channel_name_critical_warning"),
+ NotificationManager.IMPORTANCE_HIGH);
+ channel.setGroup(CHANNEL_GROUP_ID);
+ channel.setBlockable(false);
+ return channel;
+ }
+
+ private String getString(String name) {
+ return mResourcesContext.getStringByName(name);
+ }
+}
diff --git a/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationFactory.java b/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationFactory.java
new file mode 100644
index 000000000..62da1fc7d
--- /dev/null
+++ b/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationFactory.java
@@ -0,0 +1,262 @@
+/*
+ * 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.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;
+
+import android.annotation.ColorInt;
+import android.annotation.Nullable;
+import android.app.Notification;
+import android.app.NotificationChannel;
+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;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceIssue;
+import android.text.TextUtils;
+
+import androidx.annotation.RequiresApi;
+
+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 java.time.Duration;
+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;
+
+ SafetyCenterNotificationFactory(
+ Context context,
+ SafetyCenterNotificationChannels notificationChannels,
+ SafetyCenterResourcesContext resourcesContext) {
+ mContext = context;
+ mNotificationChannels = notificationChannels;
+ mResourcesContext = resourcesContext;
+ }
+
+ /**
+ * Creates and returns a new {@link Notification} for a successful action, or {@code null} if
+ * none could be created.
+ *
+ * <p>The provided {@link NotificationManager} is used to create or update the {@link
+ * NotificationChannel} for the notification.
+ */
+ @Nullable
+ Notification newNotificationForSuccessfulAction(
+ NotificationManager notificationManager,
+ SafetySourceIssue issue,
+ SafetySourceIssue.Action action) {
+ String channelId = mNotificationChannels.getCreatedChannelId(notificationManager, issue);
+
+ if (channelId == null) {
+ return null;
+ }
+
+ Notification.Builder builder =
+ new Notification.Builder(mContext, channelId)
+ .setSmallIcon(
+ getNotificationIcon(SafetySourceData.SEVERITY_LEVEL_INFORMATION))
+ .setExtras(getNotificationExtras())
+ .setContentTitle(action.getSuccessMessage())
+ .setShowWhen(true)
+ .setTimeoutAfter(SUCCESS_NOTIFICATION_TIMEOUT.toMillis())
+ .setContentIntent(newSafetyCenterPendingIntent(null));
+
+ Integer color = getNotificationColor(SafetySourceData.SEVERITY_LEVEL_INFORMATION);
+ if (color != null) {
+ builder.setColor(color);
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * Creates and returns a new {@link Notification} instance corresponding to the given issue, or
+ * {@code null} if none could be created.
+ *
+ * <p>The provided {@link NotificationManager} is used to create or update the {@link
+ * NotificationChannel} for the notification.
+ */
+ @Nullable
+ Notification newNotificationForIssue(
+ NotificationManager notificationManager,
+ SafetySourceIssue issue,
+ SafetyCenterIssueKey issueKey) {
+ String channelId = mNotificationChannels.getCreatedChannelId(notificationManager, issue);
+
+ if (channelId == null) {
+ return null;
+ }
+
+ CharSequence title = issue.getTitle();
+ CharSequence text = issue.getSummary();
+ List<SafetySourceIssue.Action> issueActions = issue.getActions();
+
+ if (SdkLevel.isAtLeastU()) {
+ SafetySourceIssue.Notification customNotification = issue.getCustomNotification();
+ if (customNotification != null) {
+ title = customNotification.getTitle();
+ text = customNotification.getText();
+ issueActions = customNotification.getActions();
+ }
+ }
+
+ Notification.Builder builder =
+ new Notification.Builder(mContext, channelId)
+ .setSmallIcon(getNotificationIcon(issue.getSeverityLevel()))
+ .setExtras(getNotificationExtras())
+ .setShowWhen(true)
+ .setContentTitle(title)
+ .setContentText(text)
+ .setContentIntent(newSafetyCenterPendingIntent(issueKey))
+ .setDeleteIntent(
+ SafetyCenterNotificationReceiver.newNotificationDismissedIntent(
+ mContext, issueKey));
+
+ Integer color = getNotificationColor(issue.getSeverityLevel());
+ if (color != null) {
+ builder.setColor(color);
+ }
+
+ for (int i = 0; i < issueActions.size(); i++) {
+ Notification.Action notificationAction =
+ toNotificationAction(issueKey, issueActions.get(i));
+ builder.addAction(notificationAction);
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * Returns a {@link PendingIntent} to open Safety Center, optionally navigating to and/or
+ * highlighting a specific issue if {@code issueKey} is given.
+ */
+ private PendingIntent newSafetyCenterPendingIntent(@Nullable SafetyCenterIssueKey issueKey) {
+ Intent intent = new Intent(Intent.ACTION_SAFETY_CENTER);
+ if (issueKey != null) {
+ // Set the encoded issue key as the intent's identifier to ensure the PendingIntents of
+ // different notifications do not collide:
+ intent.setIdentifier(SafetyCenterIds.encodeToString(issueKey));
+ intent.putExtra(EXTRA_SAFETY_SOURCE_ID, issueKey.getSafetySourceId());
+ intent.putExtra(EXTRA_SAFETY_SOURCE_ISSUE_ID, issueKey.getSafetySourceIssueId());
+ intent.putExtra(EXTRA_SAFETY_SOURCE_USER_HANDLE, UserHandle.of(issueKey.getUserId()));
+ }
+ // This extra is defined in the PermissionController APK, cannot be referenced directly:
+ intent.putExtra("navigation_source_intent_extra", "NOTIFICATION");
+ return PendingIntentFactory.getActivityPendingIntent(
+ mContext, OPEN_SAFETY_CENTER_REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE);
+ }
+
+ private Icon getNotificationIcon(@SafetySourceData.SeverityLevel int severityLevel) {
+ String iconResName = "ic_notification_badge_general";
+ if (severityLevel == SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING) {
+ iconResName = "ic_notification_badge_critical";
+ }
+ Icon icon = mResourcesContext.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:
+ icon = Icon.createWithResource(mContext, android.R.drawable.ic_dialog_alert);
+ }
+ return icon;
+ }
+
+ @ColorInt
+ @Nullable
+ private Integer getNotificationColor(@SafetySourceData.SeverityLevel int severityLevel) {
+ String colorResName = "notification_tint_normal";
+ if (severityLevel == SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING) {
+ colorResName = "notification_tint_critical";
+ }
+ return mResourcesContext.getColorByName(colorResName);
+ }
+
+ private Bundle getNotificationExtras() {
+ Bundle extras = new Bundle();
+ String appName = mResourcesContext.getStringByName("notification_channel_group_name");
+ if (!TextUtils.isEmpty(appName)) {
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, appName);
+ }
+ return extras;
+ }
+
+ private Notification.Action toNotificationAction(
+ SafetyCenterIssueKey issueKey, SafetySourceIssue.Action issueAction) {
+ PendingIntent pendingIntent = getPendingIntentForAction(issueKey, issueAction);
+ return new Notification.Action.Builder(null, issueAction.getLabel(), pendingIntent).build();
+ }
+
+ private PendingIntent getPendingIntentForAction(
+ SafetyCenterIssueKey issueKey, SafetySourceIssue.Action issueAction) {
+ if (issueAction.willResolve()) {
+ return getReceiverPendingIntentForResolvingAction(issueKey, issueAction);
+ } else {
+ return getDirectPendingIntentForNonResolvingAction(issueKey, issueAction);
+ }
+ }
+
+ private PendingIntent getReceiverPendingIntentForResolvingAction(
+ SafetyCenterIssueKey issueKey, SafetySourceIssue.Action issueAction) {
+ // We do not use the action's PendingIntent directly here instead we build a new PI which
+ // will be handled by our SafetyCenterNotificationReceiver which will in turn dispatch
+ // the source-provided action PI. This ensures that action execution is consistent across
+ // between Safety Center UI and notifications, for example executing an action from a
+ // notification will send an "action in-flight" update to any current listeners.
+ SafetyCenterIssueActionId issueActionId =
+ SafetyCenterIssueActionId.newBuilder()
+ .setSafetyCenterIssueKey(issueKey)
+ .setSafetySourceIssueActionId(issueAction.getId())
+ .build();
+ return SafetyCenterNotificationReceiver.newNotificationActionClickedIntent(
+ mContext, issueActionId);
+ }
+
+ private PendingIntent getDirectPendingIntentForNonResolvingAction(
+ SafetyCenterIssueKey issueKey, 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
new file mode 100644
index 000000000..0b4ac5ab3
--- /dev/null
+++ b/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationReceiver.java
@@ -0,0 +1,255 @@
+/*
+ * 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.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;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.safetycenter.SafetySourceIssue;
+import android.util.Log;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.permission.util.UserUtils;
+import com.android.safetycenter.ApiLock;
+import com.android.safetycenter.PendingIntentFactory;
+import com.android.safetycenter.SafetyCenterDataChangeNotifier;
+import com.android.safetycenter.SafetyCenterFlags;
+import com.android.safetycenter.SafetyCenterService;
+import com.android.safetycenter.UserProfileGroup;
+import com.android.safetycenter.data.SafetyCenterDataManager;
+import com.android.safetycenter.internaldata.SafetyCenterIds;
+import com.android.safetycenter.internaldata.SafetyCenterIssueActionId;
+import com.android.safetycenter.internaldata.SafetyCenterIssueKey;
+import com.android.safetycenter.logging.SafetyCenterStatsdLogger;
+
+/**
+ * A Context-registered {@link BroadcastReceiver} that handles intents sent via Safety Center
+ * notifications e.g. when a notification is dismissed.
+ *
+ * <p>Use {@link #register(Context)} to register this receiver with the correct {@link IntentFilter}
+ * and use the {@link #newNotificationDismissedIntent(Context, SafetyCenterIssueKey)} and {@link
+ * #newNotificationActionClickedIntent(Context, SafetyCenterIssueActionId)} factory methods to
+ * create new {@link PendingIntent} instances for this receiver.
+ *
+ * @hide
+ */
+@RequiresApi(TIRAMISU)
+public final class SafetyCenterNotificationReceiver extends BroadcastReceiver {
+
+ private static final String TAG = "SafetyCenterNR";
+
+ private static final String ACTION_NOTIFICATION_DISMISSED =
+ "com.android.safetycenter.action.NOTIFICATION_DISMISSED";
+ private static final String ACTION_NOTIFICATION_ACTION_CLICKED =
+ "com.android.safetycenter.action.NOTIFICATION_ACTION_CLICKED";
+ private static final String EXTRA_ISSUE_KEY = "com.android.safetycenter.extra.ISSUE_KEY";
+ private static final String EXTRA_ISSUE_ACTION_ID =
+ "com.android.safetycenter.extra.ISSUE_ACTION_ID";
+
+ private static final int REQUEST_CODE_UNUSED = 0;
+
+ /**
+ * Creates a broadcast {@code PendingIntent} for this receiver which will handle a Safety Center
+ * notification being dismissed.
+ */
+ static PendingIntent newNotificationDismissedIntent(
+ Context context, SafetyCenterIssueKey issueKey) {
+ String issueKeyString = SafetyCenterIds.encodeToString(issueKey);
+ Intent intent = new Intent(ACTION_NOTIFICATION_DISMISSED);
+ intent.putExtra(EXTRA_ISSUE_KEY, issueKeyString);
+ intent.setIdentifier(issueKeyString);
+ int flags = PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT;
+ return PendingIntentFactory.getNonProtectedSystemOnlyBroadcastPendingIntent(
+ context, REQUEST_CODE_UNUSED, intent, flags);
+ }
+
+ /**
+ * Creates a broadcast {@code PendingIntent} for this receiver which will handle a Safety Center
+ * notification action being clicked.
+ *
+ * <p>Safety Center notification actions correspond to Safety Center issue actions.
+ */
+ static PendingIntent newNotificationActionClickedIntent(
+ Context context, SafetyCenterIssueActionId issueActionId) {
+ String issueActionIdString = SafetyCenterIds.encodeToString(issueActionId);
+ Intent intent = new Intent(ACTION_NOTIFICATION_ACTION_CLICKED);
+ intent.putExtra(EXTRA_ISSUE_ACTION_ID, issueActionIdString);
+ intent.setIdentifier(issueActionIdString);
+ int flags = PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT;
+ return PendingIntentFactory.getNonProtectedSystemOnlyBroadcastPendingIntent(
+ context, REQUEST_CODE_UNUSED, intent, flags);
+ }
+
+ @Nullable
+ private static SafetyCenterIssueKey getIssueKeyExtra(Intent intent) {
+ String issueKeyString = intent.getStringExtra(EXTRA_ISSUE_KEY);
+ if (issueKeyString == null) {
+ Log.w(TAG, "Received notification dismissed broadcast with null issue key extra");
+ return null;
+ }
+ try {
+ return SafetyCenterIds.issueKeyFromString(issueKeyString);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Could not decode the issue key extra", e);
+ return null;
+ }
+ }
+
+ @Nullable
+ 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");
+ return null;
+ }
+ try {
+ return SafetyCenterIds.issueActionIdFromString(issueActionIdString);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Could not decode the issue action ID", e);
+ return null;
+ }
+ }
+
+ private final SafetyCenterService mService;
+
+ @GuardedBy("mApiLock")
+ private final SafetyCenterDataManager mSafetyCenterDataManager;
+
+ @GuardedBy("mApiLock")
+ private final SafetyCenterDataChangeNotifier mSafetyCenterDataChangeNotifier;
+
+ private final ApiLock mApiLock;
+
+ public SafetyCenterNotificationReceiver(
+ SafetyCenterService service,
+ SafetyCenterDataManager safetyCenterDataManager,
+ SafetyCenterDataChangeNotifier safetyCenterDataChangeNotifier,
+ ApiLock apiLock) {
+ mService = service;
+ mSafetyCenterDataManager = safetyCenterDataManager;
+ mSafetyCenterDataChangeNotifier = safetyCenterDataChangeNotifier;
+ mApiLock = apiLock;
+ }
+
+ /**
+ * Register this receiver in the given {@link Context} with an {@link IntentFilter} that matches
+ * any intents created by this class' static factory methods.
+ *
+ * @see #newNotificationDismissedIntent(Context, SafetyCenterIssueKey)
+ */
+ public void register(Context context) {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_NOTIFICATION_DISMISSED);
+ filter.addAction(ACTION_NOTIFICATION_ACTION_CLICKED);
+ context.registerReceiver(this, filter, Context.RECEIVER_NOT_EXPORTED);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!SafetyCenterFlags.getSafetyCenterEnabled()
+ || !SafetyCenterFlags.getNotificationsEnabled()) {
+ 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!");
+ return;
+ }
+
+ switch (action) {
+ case ACTION_NOTIFICATION_DISMISSED:
+ onNotificationDismissed(context, intent);
+ break;
+ case ACTION_NOTIFICATION_ACTION_CLICKED:
+ onNotificationActionClicked(context, intent);
+ break;
+ default:
+ Log.w(TAG, "Received broadcast with unrecognized action: " + action);
+ break;
+ }
+ }
+
+ private void onNotificationDismissed(Context context, Intent intent) {
+ SafetyCenterIssueKey issueKey = getIssueKeyExtra(intent);
+ if (issueKey == null) {
+ return;
+ }
+
+ int userId = issueKey.getUserId();
+ UserProfileGroup userProfileGroup = UserProfileGroup.fromUser(context, userId);
+
+ SafetySourceIssue dismissedIssue;
+ synchronized (mApiLock) {
+ dismissedIssue = mSafetyCenterDataManager.getSafetySourceIssue(issueKey);
+ mSafetyCenterDataManager.dismissNotification(issueKey);
+ mSafetyCenterDataChangeNotifier.updateDataConsumers(userProfileGroup, userId);
+ }
+
+ if (dismissedIssue != null) {
+ SafetyCenterStatsdLogger.writeNotificationDismissedEvent(
+ issueKey.getSafetySourceId(),
+ UserUtils.isManagedProfile(userId, context),
+ dismissedIssue.getIssueTypeId(),
+ dismissedIssue.getSeverityLevel());
+ }
+ }
+
+ private void onNotificationActionClicked(Context context, Intent intent) {
+ SafetyCenterIssueActionId issueActionId = getIssueActionIdExtra(intent);
+ if (issueActionId == null) {
+ return;
+ }
+
+ mService.executeIssueActionInternal(issueActionId);
+ logNotificationActionClicked(context, issueActionId);
+ }
+
+ private void logNotificationActionClicked(
+ Context context, SafetyCenterIssueActionId issueActionId) {
+ SafetyCenterIssueKey issueKey = issueActionId.getSafetyCenterIssueKey();
+ SafetySourceIssue issue;
+ synchronized (mApiLock) {
+ issue = mSafetyCenterDataManager.getSafetySourceIssue(issueKey);
+ }
+ if (issue != null) {
+ SafetyCenterStatsdLogger.writeNotificationActionClickedEvent(
+ issueKey.getSafetySourceId(),
+ UserUtils.isManagedProfile(issueKey.getUserId(), context),
+ issue.getIssueTypeId(),
+ issue.getSeverityLevel(),
+ isPrimaryAction(issue, issueActionId));
+ }
+ }
+
+ /** 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
new file mode 100644
index 000000000..668158097
--- /dev/null
+++ b/service/java/com/android/safetycenter/notifications/SafetyCenterNotificationSender.java
@@ -0,0 +1,463 @@
+/*
+ * 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.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;
+import android.content.Context;
+import android.os.Binder;
+import android.os.UserHandle;
+import android.safetycenter.SafetyEvent;
+import android.safetycenter.SafetySourceIssue;
+import android.safetycenter.config.SafetySource;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import androidx.annotation.RequiresApi;
+
+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.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 java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.List;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
+/**
+ * Class responsible for posting, updating and dismissing Safety Center notifications each time
+ * Safety Center's issues change.
+ *
+ * <p>This class isn't thread safe. Thread safety must be handled by the caller.
+ *
+ * @hide
+ */
+@RequiresApi(TIRAMISU)
+@NotThreadSafe
+public final class SafetyCenterNotificationSender {
+
+ private static final String TAG = "SafetyCenterNS";
+
+ // We use a fixed notification ID because notifications are keyed by (tag, id) and it easier
+ // to differentiate our notifications using the tag
+ private static final int FIXED_NOTIFICATION_ID = 2345;
+
+ private static final int NOTIFICATION_BEHAVIOR_INTERNAL_NEVER = 100;
+ private static final int NOTIFICATION_BEHAVIOR_INTERNAL_DELAYED = 200;
+ private static final int NOTIFICATION_BEHAVIOR_INTERNAL_IMMEDIATELY = 300;
+
+ /**
+ * Internal notification behavior {@code @IntDef} which is related to the {@code
+ * SafetySourceIssue.NotificationBehavior} type introduced in Android U.
+ *
+ * <p>This definition is available on T+.
+ *
+ * <p>Unlike the U+/external {@code @IntDef}, this one has no "unspecified behavior" value. Any
+ * issues which have unspecified behavior are resolved to one of these specific behaviors based
+ * on their other properties.
+ */
+ @IntDef(
+ prefix = {"NOTIFICATION_BEHAVIOR_INTERNAL"},
+ value = {
+ NOTIFICATION_BEHAVIOR_INTERNAL_NEVER,
+ NOTIFICATION_BEHAVIOR_INTERNAL_DELAYED,
+ NOTIFICATION_BEHAVIOR_INTERNAL_IMMEDIATELY
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface NotificationBehaviorInternal {}
+
+ private final Context mContext;
+
+ private final SafetyCenterNotificationFactory mNotificationFactory;
+
+ private final SafetyCenterDataManager mSafetyCenterDataManager;
+
+ private final ArrayMap<SafetyCenterIssueKey, SafetySourceIssue> mNotifiedIssues =
+ new ArrayMap<>();
+
+ private SafetyCenterNotificationSender(
+ Context context,
+ SafetyCenterNotificationFactory notificationFactory,
+ SafetyCenterDataManager safetyCenterDataManager) {
+ mContext = context;
+ mNotificationFactory = notificationFactory;
+ mSafetyCenterDataManager = safetyCenterDataManager;
+ }
+
+ public static SafetyCenterNotificationSender newInstance(
+ Context context,
+ SafetyCenterResourcesContext resourcesContext,
+ SafetyCenterNotificationChannels notificationChannels,
+ SafetyCenterDataManager dataManager) {
+ return new SafetyCenterNotificationSender(
+ context,
+ new SafetyCenterNotificationFactory(
+ context, notificationChannels, resourcesContext),
+ dataManager);
+ }
+
+ /**
+ * Replaces an issue's notification with one displaying the success message of the {@link
+ * SafetySourceIssue.Action} that resolved that issue.
+ *
+ * <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.
+ *
+ * @param sourceId of the source which reported the issue
+ * @param safetyEvent the source provided upon successful action resolution
+ * @param userId to which the source, issue and notification belong
+ */
+ public void notifyActionSuccess(
+ String sourceId, SafetyEvent safetyEvent, @UserIdInt int userId) {
+ if (safetyEvent.getType() != SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED) {
+ Log.w(TAG, "Received safety event of wrong type");
+ return;
+ }
+
+ String sourceIssueId = safetyEvent.getSafetySourceIssueId();
+ if (sourceIssueId == null) {
+ Log.w(TAG, "Received safety event without a safety source issue id");
+ return;
+ }
+
+ String sourceIssueActionId = safetyEvent.getSafetySourceIssueActionId();
+ if (sourceIssueActionId == null) {
+ Log.w(TAG, "Received safety event without a safety source issue action id");
+ return;
+ }
+
+ SafetyCenterIssueKey issueKey =
+ SafetyCenterIssueKey.newBuilder()
+ .setSafetySourceId(sourceId)
+ .setSafetySourceIssueId(sourceIssueId)
+ .setUserId(userId)
+ .build();
+ SafetySourceIssue notifiedIssue = mNotifiedIssues.get(issueKey);
+ if (notifiedIssue == null) {
+ Log.w(TAG, "No notification for this issue");
+ 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);
+ }
+ }
+ if (successfulAction == null) {
+ Log.w(TAG, "Successful action not found");
+ return;
+ }
+
+ NotificationManager notificationManager = getNotificationManagerForUser(userId);
+
+ if (notificationManager == null) {
+ return;
+ }
+
+ Notification notification =
+ mNotificationFactory.newNotificationForSuccessfulAction(
+ notificationManager, notifiedIssue, successfulAction);
+ if (notification == null) {
+ Log.w(TAG, "Could not create successful action notification");
+ return;
+ }
+ String tag = getNotificationTag(issueKey);
+ boolean wasPosted = notifyFromSystem(notificationManager, tag, notification);
+ if (wasPosted) {
+ // If the original issue notification was successfully replaced the key removed from
+ // mNotifiedIssues to prevent the success notification from being removed by
+ // cancelStaleNotifications below.
+ mNotifiedIssues.remove(issueKey);
+ }
+ }
+
+ /** Updates Safety Center notifications for the given {@link UserProfileGroup}. */
+ public void updateNotifications(UserProfileGroup userProfileGroup) {
+ updateNotifications(userProfileGroup.getProfileParentUserId());
+
+ int[] managedProfileUserIds = userProfileGroup.getManagedProfilesUserIds();
+ for (int i = 0; i < managedProfileUserIds.length; i++) {
+ updateNotifications(managedProfileUserIds[i]);
+ }
+ }
+
+ /**
+ * Updates Safety Center notifications, usually in response to a change in the issues for the
+ * given userId.
+ */
+ public void updateNotifications(@UserIdInt int userId) {
+ if (!SafetyCenterFlags.getNotificationsEnabled()) {
+ return;
+ }
+
+ NotificationManager notificationManager = getNotificationManagerForUser(userId);
+
+ if (notificationManager == null) {
+ return;
+ }
+
+ ArrayMap<SafetyCenterIssueKey, SafetySourceIssue> issuesToNotify =
+ getIssuesToNotify(userId);
+
+ // Post or update notifications for notifiable issues. We keep track of the "fresh" issues
+ // keys of those issues which were just notified because doing so allows us to cancel any
+ // notifications for other, non-fresh issues.
+ ArraySet<SafetyCenterIssueKey> freshIssueKeys = new ArraySet<>();
+ for (int i = 0; i < issuesToNotify.size(); i++) {
+ SafetyCenterIssueKey issueKey = issuesToNotify.keyAt(i);
+ SafetySourceIssue issue = issuesToNotify.valueAt(i);
+
+ boolean unchanged = issue.equals(mNotifiedIssues.get(issueKey));
+ if (unchanged) {
+ freshIssueKeys.add(issueKey);
+ continue;
+ }
+
+ boolean wasPosted = postNotificationForIssue(notificationManager, issue, issueKey);
+ if (wasPosted) {
+ freshIssueKeys.add(issueKey);
+ }
+ }
+
+ cancelStaleNotifications(notificationManager, userId, freshIssueKeys);
+ }
+
+ /** Cancels all notifications previously posted by this class */
+ public void cancelAllNotifications() {
+ // Loop in reverse index order to be able to remove entries while iterating
+ for (int i = mNotifiedIssues.size() - 1; i >= 0; i--) {
+ SafetyCenterIssueKey issueKey = mNotifiedIssues.keyAt(i);
+ int userId = issueKey.getUserId();
+ NotificationManager notificationManager = getNotificationManagerForUser(userId);
+ if (notificationManager == null) {
+ continue;
+ }
+ cancelNotificationFromSystem(notificationManager, getNotificationTag(issueKey));
+ mNotifiedIssues.removeAt(i);
+ }
+ }
+
+ /** Dumps state for debugging purposes. */
+ public void dump(PrintWriter fout) {
+ int notifiedIssuesCount = mNotifiedIssues.size();
+ fout.println("NOTIFICATION SENDER (" + notifiedIssuesCount + " notified issues)");
+ for (int i = 0; i < notifiedIssuesCount; i++) {
+ SafetyCenterIssueKey key = mNotifiedIssues.keyAt(i);
+ SafetySourceIssue issue = mNotifiedIssues.valueAt(i);
+ fout.println("\t[" + i + "] " + toUserFriendlyString(key) + " -> " + issue);
+ }
+ fout.println();
+ }
+
+ /** Get all of 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<>();
+ List<SafetySourceIssueInfo> allIssuesInfo =
+ mSafetyCenterDataManager.getIssuesForUser(userId);
+
+ for (int i = 0; i < allIssuesInfo.size(); i++) {
+ SafetySourceIssueInfo issueInfo = allIssuesInfo.get(i);
+ SafetyCenterIssueKey issueKey = issueInfo.getSafetyCenterIssueKey();
+ SafetySourceIssue issue = issueInfo.getSafetySourceIssue();
+
+ if (!areNotificationsAllowedForSource(issueInfo.getSafetySource())) {
+ continue;
+ }
+
+ if (mSafetyCenterDataManager.isNotificationDismissedNow(
+ issueKey, issue.getSeverityLevel())) {
+ continue;
+ }
+
+ // Get the notification behavior for this issue which determines whether we should
+ // send a notification about it now
+ int behavior = getBehavior(issue, issueKey);
+ if (behavior == NOTIFICATION_BEHAVIOR_INTERNAL_IMMEDIATELY) {
+ result.put(issueKey, issue);
+ } else if (behavior == NOTIFICATION_BEHAVIOR_INTERNAL_DELAYED) {
+ if (canNotifyDelayedIssueNow(issueKey)) {
+ result.put(issueKey, issue);
+ }
+ // TODO(b/259094736): else handle delayed notifications using a scheduled job
+ }
+ }
+ return result;
+ }
+
+ @NotificationBehaviorInternal
+ private int getBehavior(SafetySourceIssue issue, SafetyCenterIssueKey issueKey) {
+ if (SdkLevel.isAtLeastU()) {
+ switch (issue.getNotificationBehavior()) {
+ 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;
+ }
+ }
+ // On Android T all issues are assumed to have "unspecified" behavior
+ return getBehaviorForIssueWithUnspecifiedBehavior(issue, issueKey);
+ }
+
+ @NotificationBehaviorInternal
+ private int getBehaviorForIssueWithUnspecifiedBehavior(
+ SafetySourceIssue issue, SafetyCenterIssueKey issueKey) {
+ String flagKey = issueKey.getSafetySourceId() + "/" + issue.getIssueTypeId();
+ if (SafetyCenterFlags.getImmediateNotificationBehaviorIssues().contains(flagKey)) {
+ return NOTIFICATION_BEHAVIOR_INTERNAL_IMMEDIATELY;
+ } else {
+ return NOTIFICATION_BEHAVIOR_INTERNAL_NEVER;
+ }
+ }
+
+ private boolean areNotificationsAllowedForSource(SafetySource safetySource) {
+ if (SdkLevel.isAtLeastU()) {
+ if (safetySource.areNotificationsAllowed()) {
+ return true;
+ }
+ }
+ return SafetyCenterFlags.getNotificationsAllowedSourceIds().contains(safetySource.getId());
+ }
+
+ private boolean canNotifyDelayedIssueNow(SafetyCenterIssueKey issueKey) {
+ Duration minNotificationsDelay = SafetyCenterFlags.getNotificationsMinDelay();
+ Instant threshold = Instant.now().minus(minNotificationsDelay);
+ Instant seenAt = mSafetyCenterDataManager.getIssueFirstSeenAt(issueKey);
+ return seenAt != null && seenAt.isBefore(threshold);
+ }
+
+ private boolean postNotificationForIssue(
+ NotificationManager notificationManager,
+ SafetySourceIssue issue,
+ SafetyCenterIssueKey key) {
+ Notification notification =
+ mNotificationFactory.newNotificationForIssue(notificationManager, issue, key);
+ if (notification == null) {
+ return false;
+ }
+ String tag = getNotificationTag(key);
+ boolean wasPosted = notifyFromSystem(notificationManager, tag, notification);
+ if (wasPosted) {
+ mNotifiedIssues.put(key, issue);
+ SafetyCenterStatsdLogger.writeNotificationPostedEvent(
+ key.getSafetySourceId(),
+ UserUtils.isManagedProfile(key.getUserId(), mContext),
+ issue.getIssueTypeId(),
+ issue.getSeverityLevel());
+ }
+ return wasPosted;
+ }
+
+ private void cancelStaleNotifications(
+ NotificationManager notificationManager,
+ @UserIdInt int userId,
+ ArraySet<SafetyCenterIssueKey> freshIssueKeys) {
+ // Loop in reverse index order to be able to remove entries while iterating
+ for (int i = mNotifiedIssues.size() - 1; i >= 0; i--) {
+ SafetyCenterIssueKey key = mNotifiedIssues.keyAt(i);
+ if (key.getUserId() == userId && !freshIssueKeys.contains(key)) {
+ String tag = getNotificationTag(key);
+ cancelNotificationFromSystem(notificationManager, tag);
+ mNotifiedIssues.removeAt(i);
+ }
+ }
+ }
+
+ private static String getNotificationTag(SafetyCenterIssueKey issueKey) {
+ // Base 64 encoding of the issueKey proto:
+ return SafetyCenterIds.encodeToString(issueKey);
+ }
+
+ /** Returns a {@link NotificationManager} which will send notifications to the given user. */
+ @Nullable
+ private NotificationManager getNotificationManagerForUser(@UserIdInt int userId) {
+ return SafetyCenterNotificationChannels.getNotificationManagerForUser(
+ mContext, UserHandle.of(userId));
+ }
+
+ /**
+ * Sends a {@link Notification} from the system, dropping any calling identity. Returns {@code
+ * true} if successful or {@code false} otherwise.
+ *
+ * <p>The recipient of the notification depends on the {@link Context} of the given {@link
+ * NotificationManager}. Use {@link #getNotificationManagerForUser(int)} to send notifications
+ * to a specific user.
+ */
+ private boolean notifyFromSystem(
+ NotificationManager notificationManager,
+ @Nullable String tag,
+ Notification notification) {
+ // This call is needed to send a notification from the system and this also grants the
+ // necessary POST_NOTIFICATIONS permission.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ // The fixed notification ID is OK because notifications are keyed by (tag, id)
+ notificationManager.notify(tag, FIXED_NOTIFICATION_ID, notification);
+ return true;
+ } catch (Throwable e) {
+ Log.w(TAG, "Unable to send system notification", e);
+ return false;
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ /**
+ * Cancels a {@link Notification} from the system, dropping any calling identity.
+ *
+ * <p>The recipient of the notification depends on the {@link Context} of the given {@link
+ * NotificationManager}. Use {@link #getNotificationManagerForUser(int)} to cancel notifications
+ * sent to a specific user.
+ */
+ private void cancelNotificationFromSystem(
+ NotificationManager notificationManager, @Nullable String tag) {
+ // This call is needed to cancel a notification previously sent from the system
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ notificationManager.cancel(tag, FIXED_NOTIFICATION_ID);
+ } catch (Throwable e) {
+ Log.w(TAG, "Unable to cancel system notification", e);
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+}
diff --git a/service/java/com/android/safetycenter/notifications/package-info.java b/service/java/com/android/safetycenter/notifications/package-info.java
new file mode 100644
index 000000000..85b487b30
--- /dev/null
+++ b/service/java/com/android/safetycenter/notifications/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@NonNullByDefault
+package com.android.safetycenter.notifications;
+
+import com.android.safetycenter.annotations.NonNullByDefault;
diff --git a/service/java/com/android/access/package-info.java b/service/java/com/android/safetycenter/package-info.java
index 18fcfc69d..0bccf89fa 100644
--- a/service/java/com/android/access/package-info.java
+++ b/service/java/com/android/safetycenter/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 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.
@@ -13,10 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+@NonNullByDefault
+package com.android.safetycenter;
-/**
- * @hide
- * TODO(b/146466118) remove this javadoc tag
- */
-@android.annotation.Hide
-package com.android.access;
+import com.android.safetycenter.annotations.NonNullByDefault;
diff --git a/service/lint-baseline.xml b/service/lint-baseline.xml
new file mode 100644
index 000000000..90ea8d411
--- /dev/null
+++ b/service/lint-baseline.xml
@@ -0,0 +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">
+
+ <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>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 34 (current min is 33): `android.content.pm.PackageManager#getPackageUidAsUser`"
+ errorLine1=" packageManager.getPackageUidAsUser("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/Permission/service/java/com/android/safetycenter/SafetyCenterService.java"
+ line="660"
+ column="40"/>
+ </issue>
+
+</issues> \ No newline at end of file
diff --git a/tests/apex/AndroidTest.xml b/tests/apex/AndroidTest.xml
index 283f008a5..b1af0f53e 100644
--- a/tests/apex/AndroidTest.xml
+++ b/tests/apex/AndroidTest.xml
@@ -23,7 +23,7 @@
<object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
<!-- Install test -->
- <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="test-file-name" value="PermissionApexTests.apk" />
<option name="cleanup-apks" value="true" />
</target_preparer>
diff --git a/tests/apex/java/com/android/permission/persistence/RuntimePermissionsPersistenceTest.kt b/tests/apex/java/com/android/permission/persistence/RuntimePermissionsPersistenceTest.kt
index 2987da087..59bf6a381 100644
--- a/tests/apex/java/com/android/permission/persistence/RuntimePermissionsPersistenceTest.kt
+++ b/tests/apex/java/com/android/permission/persistence/RuntimePermissionsPersistenceTest.kt
@@ -24,6 +24,7 @@ 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
+import java.io.File
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -35,7 +36,6 @@ import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations.initMocks
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-import java.io.File
@RunWith(AndroidJUnit4::class)
class RuntimePermissionsPersistenceTest {
@@ -44,15 +44,17 @@ class RuntimePermissionsPersistenceTest {
private lateinit var mockDataDirectory: File
private lateinit var mockitoSession: MockitoSession
- @Mock
- lateinit var apexEnvironment: ApexEnvironment
+ @Mock lateinit var apexEnvironment: ApexEnvironment
- private val persistence = RuntimePermissionsPersistence.createInstance()
+ private val persistence = RuntimePermissionsPersistenceImpl {}
private val permissionState = RuntimePermissionsState.PermissionState("permission", true, 3)
- private val state = RuntimePermissionsState(
- 1, "fingerprint", mapOf("package" to listOf(permissionState)),
- mapOf("sharedUser" to listOf(permissionState))
- )
+ private val state =
+ RuntimePermissionsState(
+ 1,
+ "fingerprint",
+ mapOf("package" to listOf(permissionState)),
+ mapOf("sharedUser" to listOf(permissionState))
+ )
private val user = Process.myUserHandle()
@Before
@@ -64,10 +66,11 @@ class RuntimePermissionsPersistenceTest {
@Before
fun mockApexEnvironment() {
initMocks(this)
- mockitoSession = mockitoSession()
- .mockStatic(ApexEnvironment::class.java)
- .strictness(Strictness.LENIENT)
- .startMocking()
+ mockitoSession =
+ mockitoSession()
+ .mockStatic(ApexEnvironment::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
`when`(ApexEnvironment.getApexEnvironment(eq(APEX_MODULE_NAME))).thenReturn(apexEnvironment)
`when`(apexEnvironment.getDeviceProtectedDataDirForUser(any(UserHandle::class.java))).then {
File(mockDataDirectory, it.arguments[0].toString()).also { it.mkdirs() }
@@ -80,19 +83,24 @@ class RuntimePermissionsPersistenceTest {
}
@Test
- fun testReadWrite() {
+ fun testWriteRead() {
persistence.writeForUser(state, user)
val persistedState = persistence.readForUser(user)
- assertThat(persistedState).isEqualTo(state)
- assertThat(persistedState!!.version).isEqualTo(state.version)
- assertThat(persistedState.fingerprint).isEqualTo(state.fingerprint)
- assertThat(persistedState.packagePermissions).isEqualTo(state.packagePermissions)
- val persistedPermissionState = persistedState.packagePermissions.values.first().first()
- assertThat(persistedPermissionState.name).isEqualTo(permissionState.name)
- assertThat(persistedPermissionState.isGranted).isEqualTo(permissionState.isGranted)
- assertThat(persistedPermissionState.flags).isEqualTo(permissionState.flags)
- assertThat(persistedState.sharedUserPermissions).isEqualTo(state.sharedUserPermissions)
+ checkPersistedState(persistedState!!)
+ }
+
+ @Test
+ fun testWriteCorruptReadFromReserveCopy() {
+ persistence.writeForUser(state, user)
+ // Corrupt the primary file.
+ RuntimePermissionsPersistenceImpl.getFile(user)
+ .writeText(
+ "<runtime-permissions version=\"10\"><package name=\"com.foo.bar\"><permission"
+ )
+ val persistedState = persistence.readForUser(user)
+
+ checkPersistedState(persistedState!!)
}
@Test
@@ -104,6 +112,18 @@ class RuntimePermissionsPersistenceTest {
assertThat(persistedState).isNull()
}
+ private fun checkPersistedState(persistedState: RuntimePermissionsState) {
+ assertThat(persistedState).isEqualTo(state)
+ assertThat(persistedState.version).isEqualTo(state.version)
+ assertThat(persistedState.fingerprint).isEqualTo(state.fingerprint)
+ assertThat(persistedState.packagePermissions).isEqualTo(state.packagePermissions)
+ val persistedPermissionState = persistedState.packagePermissions.values.first().first()
+ assertThat(persistedPermissionState.name).isEqualTo(permissionState.name)
+ assertThat(persistedPermissionState.isGranted).isEqualTo(permissionState.isGranted)
+ assertThat(persistedPermissionState.flags).isEqualTo(permissionState.flags)
+ assertThat(persistedState.sharedUserPermissions).isEqualTo(state.sharedUserPermissions)
+ }
+
companion object {
private const val APEX_MODULE_NAME = "com.android.permission"
}
diff --git a/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt b/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt
index f9d9d5afb..d90ffade9 100644
--- a/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt
+++ b/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt
@@ -24,6 +24,7 @@ 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
+import java.io.File
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -35,7 +36,6 @@ import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations.initMocks
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-import java.io.File
@RunWith(AndroidJUnit4::class)
class RolesPersistenceTest {
@@ -44,10 +44,9 @@ class RolesPersistenceTest {
private lateinit var mockDataDirectory: File
private lateinit var mockitoSession: MockitoSession
- @Mock
- lateinit var apexEnvironment: ApexEnvironment
+ @Mock lateinit var apexEnvironment: ApexEnvironment
- private val persistence = RolesPersistence.createInstance()
+ private val persistence = RolesPersistenceImpl {}
private val state = RolesState(1, "packagesHash", mapOf("role" to setOf("holder1", "holder2")))
private val user = Process.myUserHandle()
@@ -60,10 +59,11 @@ class RolesPersistenceTest {
@Before
fun mockApexEnvironment() {
initMocks(this)
- mockitoSession = mockitoSession()
- .mockStatic(ApexEnvironment::class.java)
- .strictness(Strictness.LENIENT)
- .startMocking()
+ mockitoSession =
+ mockitoSession()
+ .mockStatic(ApexEnvironment::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
`when`(ApexEnvironment.getApexEnvironment(eq(APEX_MODULE_NAME))).thenReturn(apexEnvironment)
`when`(apexEnvironment.getDeviceProtectedDataDirForUser(any(UserHandle::class.java))).then {
File(mockDataDirectory, it.arguments[0].toString()).also { it.mkdirs() }
@@ -76,14 +76,22 @@ class RolesPersistenceTest {
}
@Test
- fun testReadWrite() {
+ fun testWriteRead() {
persistence.writeForUser(state, user)
val persistedState = persistence.readForUser(user)
- assertThat(persistedState).isEqualTo(state)
- assertThat(persistedState!!.version).isEqualTo(state.version)
- assertThat(persistedState.packagesHash).isEqualTo(state.packagesHash)
- assertThat(persistedState.roles).isEqualTo(state.roles)
+ checkPersistedState(persistedState)
+ }
+
+ @Test
+ fun testWriteCorruptReadFromReserveCopy() {
+ persistence.writeForUser(state, user)
+ // Corrupt the primary file.
+ RolesPersistenceImpl.getFile(user)
+ .writeText("<roles version=\"-1\"><role name=\"com.foo.bar\"><holder")
+ val persistedState = persistence.readForUser(user)
+
+ checkPersistedState(persistedState)
}
@Test
@@ -95,6 +103,13 @@ 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)
+ }
+
companion object {
private const val APEX_MODULE_NAME = "com.android.permission"
}
diff --git a/tests/cts/safetycenter/Android.bp b/tests/cts/safetycenter/Android.bp
index 82b6e76df..347eb9de8 100644
--- a/tests/cts/safetycenter/Android.bp
+++ b/tests/cts/safetycenter/Android.bp
@@ -23,24 +23,24 @@ android_test {
defaults: ["mts-target-sdk-version-current"],
sdk_version: "test_current",
min_sdk_version: "30",
- target_sdk_version: "32",
srcs: [
"src/**/*.java",
"src/**/*.kt",
],
static_libs: [
+ "androidx.core_core-ktx",
"androidx.test.core",
"androidx.test.ext.junit",
"androidx.test.ext.truth",
"androidx.test.uiautomator_uiautomator",
"compatibility-device-util-axt",
"ctstestrunner-axt",
- "guava-android-testlib",
"kotlin-stdlib",
- "kotlinx-coroutines-android",
"kotlin-test",
"safety-center-config",
- "safety-center-resources-lib",
+ "safety-center-pending-intents",
+ "safety-center-test-util-lib",
+ "modules-utils-build",
"truth-prebuilt",
],
test_suites: [
diff --git a/tests/cts/safetycenter/AndroidManifest.xml b/tests/cts/safetycenter/AndroidManifest.xml
index 085dc1bda..a19117836 100644
--- a/tests/cts/safetycenter/AndroidManifest.xml
+++ b/tests/cts/safetycenter/AndroidManifest.xml
@@ -16,23 +16,16 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.safetycenter.cts">
-
<application>
- <receiver android:name=".testing.SafetySourceBroadcastReceiver"
- android:exported="false">
- <intent-filter>
- <action android:name="android.safetycenter.action.REFRESH_SAFETY_SOURCES"/>
- </intent-filter>
- </receiver>
-
<uses-library android:name="android.test.runner"/>
</application>
+
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:label="CTS tests for SafetyCenter"
android:targetPackage="android.safetycenter.cts">
</instrumentation>
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
-
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+ <uses-permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"/>
</manifest>
diff --git a/tests/cts/safetycenter/AndroidTest.xml b/tests/cts/safetycenter/AndroidTest.xml
index 3f76e6998..5ec0c380e 100644
--- a/tests/cts/safetycenter/AndroidTest.xml
+++ b/tests/cts/safetycenter/AndroidTest.xml
@@ -16,10 +16,8 @@
-->
<configuration description="Config for CTS SafetyCenter test cases">
- <!-- TODO(b/207111503): Use Sdk33ModuleController once available, and remove @SdkSuppress
- annotations -->
<object
- class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController"
+ class="com.android.tradefed.testtype.suite.module.Sdk33ModuleController"
type="module_controller"/>
<option name="config-descriptor:metadata" key="component" value="framework"/>
@@ -29,20 +27,27 @@
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="cts"/>
- <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
- <option name="force-skip-system-props"
- value="true"/> <!-- avoid restarting device -->
- </target_preparer>
-
<target_preparer
class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true"/>
<option name="test-file-name" value="CtsSafetyCenterTestCases.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" />
+ <!-- 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" />
+ </target_preparer>
+
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="android.safetycenter.cts"/>
<option name="exclude-annotation" value="org.junit.Ignore"/>
diff --git a/tests/cts/safetycenter/TEST_MAPPING b/tests/cts/safetycenter/TEST_MAPPING
index 3985e563c..e8c210a5d 100644
--- a/tests/cts/safetycenter/TEST_MAPPING
+++ b/tests/cts/safetycenter/TEST_MAPPING
@@ -3,5 +3,15 @@
{
"name": "CtsSafetyCenterTestCases"
}
+ ],
+ "mainline-presubmit": [
+ {
+ "name": "CtsSafetyCenterTestCases[com.google.android.permission.apex]",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ }
+ ]
+ }
]
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterActivityTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterActivityTest.kt
deleted file mode 100644
index 343b15296..000000000
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterActivityTest.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.content.Context
-import android.content.Intent
-import android.content.Intent.ACTION_SAFETY_CENTER
-import android.os.Build
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.safetycenter.cts.testing.SafetyCenterFlags
-import android.safetycenter.cts.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
-import android.safetycenter.cts.testing.SettingsPackage.getSettingsPackageName
-import android.support.test.uiautomator.By
-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.ApiTest
-import com.android.compatibility.common.util.UiAutomatorUtils.waitFindObject
-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.util.Locale
-import java.util.regex.Pattern
-
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
-@ApiTest(apis = ["android.content.Intent#ACTION_SAFETY_CENTER"])
-class SafetyCenterActivityTest {
- private val context: Context = getApplicationContext()
-
- @Before
- fun assumeDeviceSupportsSafetyCenterToRunTests() {
- assumeTrue(context.deviceSupportsSafetyCenter())
- }
-
- @Test
- fun launchActivity_withFlagEnabled_showsSecurityAndPrivacyTitle() {
- SafetyCenterFlags.setSafetyCenterEnabled(true)
-
- startSafetyCenterActivity()
-
- // CollapsingToolbar title can't be found by text, so using description instead.
- waitFindObject(By.desc(Pattern.compile("Security & [Pp]rivacy")))
- }
-
- @Test
- fun launchActivity_withFlagDisabled_opensSettings() {
- // TODO(b/269760296) this is to fix test failure caused by incorrect using of U API. Remove
- // in next release.
- assumeFalse(isCodeNameU())
- SafetyCenterFlags.setSafetyCenterEnabled(false)
-
- startSafetyCenterActivity()
-
- waitFindObject(By.pkg(context.getSettingsPackageName()))
- }
-
- private fun startSafetyCenterActivity() {
- context.startActivity(
- Intent(ACTION_SAFETY_CENTER)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
- }
-
- private fun isCodeNameU(): Boolean {
- val buildCodeName = Build.VERSION.CODENAME.toUpperCase(Locale.ROOT)
- return buildCodeName.compareTo("UPSIDEDOWNCAKE") >= 0
- }
-}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterDataTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterDataTest.kt
index a92cbf0da..33f52b564 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterDataTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterDataTest.kt
@@ -19,7 +19,8 @@ package android.safetycenter.cts
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
-import android.os.Build.VERSION_CODES.TIRAMISU
+import android.os.Build
+import android.os.Bundle
import android.safetycenter.SafetyCenterData
import android.safetycenter.SafetyCenterEntry
import android.safetycenter.SafetyCenterEntryGroup
@@ -28,18 +29,24 @@ import android.safetycenter.SafetyCenterIssue
import android.safetycenter.SafetyCenterStaticEntry
import android.safetycenter.SafetyCenterStaticEntryGroup
import android.safetycenter.SafetyCenterStatus
-import android.safetycenter.cts.testing.EqualsHashCodeToStringTester
import androidx.test.core.app.ApplicationProvider
+import androidx.test.core.os.Parcelables.forceParcel
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.ext.truth.os.ParcelableSubject.assertThat
import androidx.test.filters.SdkSuppress
+import com.android.safetycenter.internaldata.SafetyCenterBundles
+import com.android.safetycenter.internaldata.SafetyCenterBundles.ISSUES_TO_GROUPS_BUNDLE_KEY
+import com.android.safetycenter.internaldata.SafetyCenterBundles.STATIC_ENTRIES_TO_IDS_BUNDLE_KEY
+import com.android.safetycenter.testing.EqualsHashCodeToStringTester
+import com.android.safetycenter.testing.SafetyCenterTestData.Companion.withDismissedIssuesIfAtLeastU
+import com.android.safetycenter.testing.SafetyCenterTestData.Companion.withExtrasIfAtLeastU
import com.google.common.truth.Truth.assertThat
import kotlin.test.assertFailsWith
import org.junit.Test
import org.junit.runner.RunWith
+/** CTS tests for [SafetyCenterData]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class SafetyCenterDataTest {
private val context: Context = ApplicationProvider.getApplicationContext()
@@ -100,12 +107,186 @@ class SafetyCenterDataTest {
private val staticEntryGroup2 =
SafetyCenterStaticEntryGroup("Another static entry group title", listOf(staticEntry2))
+ private val issueToGroupExtra1 =
+ Bundle().apply { putStringArrayList(issue1.id, arrayListOf(entryGroup1.id)) }
+
+ private val filledExtrasIssuesToGroups1 =
+ Bundle().apply { putBundle(ISSUES_TO_GROUPS_BUNDLE_KEY, issueToGroupExtra1) }
+
+ private val issueToGroupExtra2 =
+ Bundle().apply { putStringArrayList(issue2.id, arrayListOf(entryGroup1.id)) }
+
+ private val filledExtrasIssuesToGroups2 =
+ Bundle().apply { putBundle(ISSUES_TO_GROUPS_BUNDLE_KEY, issueToGroupExtra2) }
+
+ private val staticEntryToId1 =
+ Bundle().apply {
+ putString(SafetyCenterBundles.toBundleKey(staticEntry1), "StaticEntryId1")
+ }
+
+ private val filledExtrasStaticEntriesToIds1 =
+ Bundle().apply { putBundle(STATIC_ENTRIES_TO_IDS_BUNDLE_KEY, staticEntryToId1) }
+
+ private val staticEntryToId2 =
+ Bundle().apply {
+ putString(SafetyCenterBundles.toBundleKey(staticEntry2), "StaticEntryId2")
+ }
+
+ private val filledExtrasStaticEntriesToIds2 =
+ Bundle().apply { putBundle(STATIC_ENTRIES_TO_IDS_BUNDLE_KEY, staticEntryToId2) }
+
+ private val filledAllExtras =
+ Bundle().apply {
+ val allIssuesToGroups = Bundle()
+ allIssuesToGroups.putAll(issueToGroupExtra1)
+ allIssuesToGroups.putAll(issueToGroupExtra2)
+ putBundle(ISSUES_TO_GROUPS_BUNDLE_KEY, allIssuesToGroups)
+ val allStaticEntriesToIds = Bundle()
+ allStaticEntriesToIds.putAll(staticEntryToId1)
+ allStaticEntriesToIds.putAll(staticEntryToId2)
+ putBundle(STATIC_ENTRIES_TO_IDS_BUNDLE_KEY, allStaticEntriesToIds)
+ }
+
+ private val filledOneKnownOneUnknown =
+ Bundle().apply {
+ val allIssuesToGroups = Bundle()
+ allIssuesToGroups.putAll(issueToGroupExtra1)
+ allIssuesToGroups.putAll(issueToGroupExtra2)
+ putBundle(ISSUES_TO_GROUPS_BUNDLE_KEY, allIssuesToGroups)
+ putInt("unknown_key", 1)
+ }
+
+ private val unknownExtras = Bundle().apply { putString("key", "value") }
+
private val data1 =
SafetyCenterData(status1, listOf(issue1), listOf(entryOrGroup1), listOf(staticEntryGroup1))
private val data2 =
SafetyCenterData(status2, listOf(issue2), listOf(entryOrGroup2), listOf(staticEntryGroup2))
@Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getStatus_withDefaultBuilder_returnsStatus() {
+ val safetyCenterData = SafetyCenterData.Builder(status1).build()
+
+ assertThat(safetyCenterData.status).isEqualTo(status1)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getIssues_withDefaultBuilder_returnsEmptyList() {
+ val safetyCenterData = SafetyCenterData.Builder(status1).build()
+
+ assertThat(safetyCenterData.issues).isEmpty()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getIssues_whenSetExplicitly_returnsIssues() {
+ val safetyCenterData =
+ SafetyCenterData.Builder(status1).addIssue(issue1).addIssue(issue2).build()
+
+ assertThat(safetyCenterData.issues).containsExactly(issue1, issue2).inOrder()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getEntriesOrGroups_withDefaultBuilder_returnsEmptyList() {
+ val safetyCenterData = SafetyCenterData.Builder(status1).build()
+
+ assertThat(safetyCenterData.entriesOrGroups).isEmpty()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getEntriesOrGroups_whenSetExplicitly_returnsEntriesOrGroups() {
+ val safetyCenterData =
+ SafetyCenterData.Builder(status1)
+ .addEntryOrGroup(entryOrGroup1)
+ .addEntryOrGroup(entryOrGroup2)
+ .build()
+
+ assertThat(safetyCenterData.entriesOrGroups)
+ .containsExactly(entryOrGroup1, entryOrGroup2)
+ .inOrder()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getStaticGroups_withDefaultBuilder_returnsEmptyList() {
+ val safetyCenterData = SafetyCenterData.Builder(status1).build()
+
+ assertThat(safetyCenterData.staticEntryGroups).isEmpty()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getStaticEntryGroups_whenSetExplicitly_returnsStaticEntryGroups() {
+ val safetyCenterData =
+ SafetyCenterData.Builder(status1)
+ .addStaticEntryGroup(staticEntryGroup1)
+ .addStaticEntryGroup(staticEntryGroup2)
+ .build()
+
+ assertThat(safetyCenterData.staticEntryGroups)
+ .containsExactly(staticEntryGroup1, staticEntryGroup2)
+ .inOrder()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getDismissedIssues_withDefaultBuilder_returnsEmptyList() {
+ val safetyCenterData = SafetyCenterData.Builder(status1).build()
+
+ assertThat(safetyCenterData.dismissedIssues).isEmpty()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getDismissedIssues_whenSetExplicitly_returnsIssues() {
+ val safetyCenterData =
+ SafetyCenterData.Builder(status1)
+ .addDismissedIssue(issue1)
+ .addDismissedIssue(issue2)
+ .build()
+
+ assertThat(safetyCenterData.dismissedIssues).containsExactly(issue1, issue2).inOrder()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getExtras_withDefaultBuilder_returnsEmptyBundle() {
+ val safetyCenterData = SafetyCenterData.Builder(status1).build()
+
+ assertThat(safetyCenterData.extras.keySet()).isEmpty()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getExtras_whenSetExplicitly_returnsExtras() {
+ val safetyCenterData =
+ SafetyCenterData.Builder(status1).setExtras(filledExtrasIssuesToGroups1).build()
+
+ val extras = safetyCenterData.extras
+ val issuesToGroups = extras.getBundle(ISSUES_TO_GROUPS_BUNDLE_KEY)
+ val groups = issuesToGroups!!.getStringArrayList(issue1.id)
+
+ assertThat(issuesToGroups.keySet().size).isEqualTo(1)
+ assertThat(groups).isEqualTo(arrayListOf(entryGroup1.id))
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getExtras_whenCleared_returnsEmptyBundle() {
+ val safetyCenterData =
+ SafetyCenterData.Builder(status1)
+ .setExtras(filledExtrasIssuesToGroups1)
+ .clearExtras()
+ .build()
+
+ assertThat(safetyCenterData.extras.keySet()).isEmpty()
+ }
+
+ @Test
fun getStatus_returnsStatus() {
assertThat(data1.status).isEqualTo(status1)
assertThat(data2.status).isEqualTo(status2)
@@ -118,6 +299,23 @@ class SafetyCenterDataTest {
}
@Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getDismissedIssues_returnsDismissedIssues() {
+ val data3 = data1.withDismissedIssuesIfAtLeastU(listOf(issue2))
+
+ assertThat(data1.dismissedIssues).isEmpty()
+ assertThat(data3.dismissedIssues).containsExactly(issue2)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getDismissedIssues_mutationsAreNotAllowed() {
+ val mutatedDismissedIssues = data1.dismissedIssues
+
+ assertFailsWith(UnsupportedOperationException::class) { mutatedDismissedIssues.add(issue2) }
+ }
+
+ @Test
fun getIssues_mutationsAreNotAllowed() {
val mutatedIssues = data1.issues
@@ -155,6 +353,104 @@ class SafetyCenterDataTest {
}
@Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun builder_addIssue_doesNotMutatePreviouslyBuiltInstance() {
+ val safetyCenterDataBuilder = SafetyCenterData.Builder(status1).addIssue(issue1)
+ val issues = safetyCenterDataBuilder.build().issues
+
+ safetyCenterDataBuilder.addIssue(issue2)
+
+ assertThat(issues).containsExactly(issue1)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun builder_clearIssues_removesAllIssues() {
+ val safetyCenterData =
+ SafetyCenterData.Builder(status1)
+ .addIssue(issue1)
+ .addIssue(issue2)
+ .clearIssues()
+ .build()
+
+ assertThat(safetyCenterData.issues).isEmpty()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun builder_addEntryOrGroup_doesNotMutatePreviouslyBuiltInstance() {
+ val safetyCenterDataBuilder =
+ SafetyCenterData.Builder(status1).addEntryOrGroup(entryOrGroup1)
+ val entriesOrGroups = safetyCenterDataBuilder.build().entriesOrGroups
+
+ safetyCenterDataBuilder.addEntryOrGroup(entryOrGroup2)
+
+ assertThat(entriesOrGroups).containsExactly(entryOrGroup1)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun builder_clearEntriesOrGroups_removesAllEntriesOrGroups() {
+ val safetyCenterData =
+ SafetyCenterData.Builder(status1)
+ .addEntryOrGroup(entryOrGroup1)
+ .addEntryOrGroup(entryOrGroup2)
+ .clearEntriesOrGroups()
+ .build()
+
+ assertThat(safetyCenterData.entriesOrGroups).isEmpty()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun builder_addStaticEntryGroup_doesNotMutatePreviouslyBuiltInstance() {
+ val safetyCenterDataBuilder =
+ SafetyCenterData.Builder(status1).addStaticEntryGroup(staticEntryGroup1)
+ val staticEntryGroups = safetyCenterDataBuilder.build().staticEntryGroups
+
+ safetyCenterDataBuilder.addStaticEntryGroup(staticEntryGroup2)
+
+ assertThat(staticEntryGroups).containsExactly(staticEntryGroup1)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun builder_clearStaticEntryGroups_removesAllStaticEntryGroups() {
+ val safetyCenterData =
+ SafetyCenterData.Builder(status1)
+ .addStaticEntryGroup(staticEntryGroup1)
+ .addStaticEntryGroup(staticEntryGroup2)
+ .clearStaticEntryGroups()
+ .build()
+
+ assertThat(safetyCenterData.staticEntryGroups).isEmpty()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun builder_addDismissedIssue_doesNotMutatePreviouslyBuiltInstance() {
+ val safetyCenterDataBuilder = SafetyCenterData.Builder(status1).addDismissedIssue(issue1)
+ val dismissedIssues = safetyCenterDataBuilder.build().dismissedIssues
+
+ safetyCenterDataBuilder.addDismissedIssue(issue2)
+
+ assertThat(dismissedIssues).containsExactly(issue1)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun builder_clearDismissedIssues_removesAllDismissedIssues() {
+ val safetyCenterData =
+ SafetyCenterData.Builder(status1)
+ .addDismissedIssue(issue1)
+ .addDismissedIssue(issue2)
+ .clearDismissedIssues()
+ .build()
+
+ assertThat(safetyCenterData.dismissedIssues).isEmpty()
+ }
+
+ @Test
fun describeContents_returns0() {
assertThat(data1.describeContents()).isEqualTo(0)
assertThat(data2.describeContents()).isEqualTo(0)
@@ -167,31 +463,284 @@ class SafetyCenterDataTest {
}
@Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun parcelRoundTrip_withDismissedIssues_recreatesEqual() {
+ val data3 = data1.withDismissedIssuesIfAtLeastU(listOf(issue2))
+ val data4 = data2.withDismissedIssuesIfAtLeastU(listOf(issue1))
+
+ assertThat(data3).recreatesEqual(SafetyCenterData.CREATOR)
+ assertThat(data4).recreatesEqual(SafetyCenterData.CREATOR)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun parcelRoundTrip_withExtras_recreatesEqual() {
+ val safetyCenterDataWithExtras = data1.withExtrasIfAtLeastU(filledAllExtras)
+ val safetyCenterDatafromParcel =
+ forceParcel(safetyCenterDataWithExtras, SafetyCenterData.CREATOR)
+
+ assertThat(safetyCenterDatafromParcel).isEqualTo(safetyCenterDataWithExtras)
+ }
+
+ @Test
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
+ val equalsHashCodeToStringTester =
+ EqualsHashCodeToStringTester.ofParcelable(parcelableCreator = SafetyCenterData.CREATOR)
+ .addEqualityGroup(
+ data1,
+ SafetyCenterData(
+ status1,
+ listOf(issue1),
+ listOf(entryOrGroup1),
+ listOf(staticEntryGroup1)
+ )
+ )
+ .addEqualityGroup(
+ data2,
+ SafetyCenterData(
+ status2,
+ listOf(issue2),
+ listOf(entryOrGroup2),
+ listOf(staticEntryGroup2)
+ )
+ )
+ .addEqualityGroup(
+ SafetyCenterData(status1, listOf(), listOf(), listOf()),
+ SafetyCenterData(status1, listOf(), listOf(), listOf())
+ )
+ .addEqualityGroup(
+ SafetyCenterData(
+ status2,
+ listOf(issue1),
+ listOf(entryOrGroup1),
+ listOf(staticEntryGroup1)
+ )
+ )
+ .addEqualityGroup(
+ SafetyCenterData(
+ status1,
+ listOf(issue2),
+ listOf(entryOrGroup1),
+ listOf(staticEntryGroup1)
+ )
+ )
+ .addEqualityGroup(
+ SafetyCenterData(
+ status1,
+ listOf(issue1),
+ listOf(entryOrGroup2),
+ listOf(staticEntryGroup1)
+ )
+ )
+ .addEqualityGroup(
+ SafetyCenterData(
+ status1,
+ listOf(issue1),
+ listOf(entryOrGroup1),
+ listOf(staticEntryGroup2)
+ )
+ )
+
+ equalsHashCodeToStringTester.test()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun equalsHashCode_atLeastU_usingEqualsHashCodeToStringTester() {
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetyCenterData.CREATOR,
+ ignoreToString = true,
+ createCopy = { SafetyCenterData.Builder(it).build() }
+ )
.addEqualityGroup(
data1,
SafetyCenterData(
- status1, listOf(issue1), listOf(entryOrGroup1), listOf(staticEntryGroup1)))
+ status1,
+ listOf(issue1),
+ listOf(entryOrGroup1),
+ listOf(staticEntryGroup1)
+ ),
+ SafetyCenterData.Builder(status1)
+ .addIssue(issue1)
+ .addEntryOrGroup(entryOrGroup1)
+ .addStaticEntryGroup(staticEntryGroup1)
+ .build(),
+ SafetyCenterData.Builder(status1)
+ .addIssue(issue1)
+ .addEntryOrGroup(entryOrGroup1)
+ .addStaticEntryGroup(staticEntryGroup1)
+ .setExtras(unknownExtras)
+ .build()
+ )
.addEqualityGroup(
- data2,
- SafetyCenterData(
- status2, listOf(issue2), listOf(entryOrGroup2), listOf(staticEntryGroup2)))
+ SafetyCenterData.Builder(status1)
+ .addIssue(issue1)
+ .addEntryOrGroup(entryOrGroup1)
+ .addStaticEntryGroup(staticEntryGroup1)
+ .setExtras(filledExtrasIssuesToGroups1)
+ .build()
+ )
.addEqualityGroup(
- SafetyCenterData(status1, listOf(), listOf(), listOf()),
- SafetyCenterData(status1, listOf(), listOf(), listOf()))
+ SafetyCenterData.Builder(status1)
+ .addIssue(issue1)
+ .addEntryOrGroup(entryOrGroup1)
+ .addStaticEntryGroup(staticEntryGroup1)
+ .setExtras(filledOneKnownOneUnknown)
+ .build()
+ )
.addEqualityGroup(
- SafetyCenterData(
- status2, listOf(issue1), listOf(entryOrGroup1), listOf(staticEntryGroup1)))
+ SafetyCenterData.Builder(status1)
+ .addIssue(issue1)
+ .addEntryOrGroup(entryOrGroup1)
+ .addStaticEntryGroup(staticEntryGroup1)
+ .setExtras(filledAllExtras)
+ .build()
+ )
.addEqualityGroup(
- SafetyCenterData(
- status1, listOf(issue2), listOf(entryOrGroup1), listOf(staticEntryGroup1)))
+ SafetyCenterData.Builder(status1)
+ .addIssue(issue1)
+ .addEntryOrGroup(entryOrGroup1)
+ .addStaticEntryGroup(staticEntryGroup1)
+ .setExtras(filledExtrasStaticEntriesToIds1)
+ .build()
+ )
.addEqualityGroup(
- SafetyCenterData(
- status1, listOf(issue1), listOf(entryOrGroup2), listOf(staticEntryGroup1)))
+ SafetyCenterData.Builder(status1)
+ .addIssue(issue1)
+ .addEntryOrGroup(entryOrGroup1)
+ .addStaticEntryGroup(staticEntryGroup1)
+ .setExtras(filledExtrasStaticEntriesToIds2)
+ .build()
+ )
.addEqualityGroup(
- SafetyCenterData(
- status1, listOf(issue1), listOf(entryOrGroup1), listOf(staticEntryGroup2)))
+ SafetyCenterData.Builder(status1)
+ .addEntryOrGroup(entryOrGroup1)
+ .addStaticEntryGroup(staticEntryGroup1)
+ .addDismissedIssue(issue1)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterData.Builder(status1)
+ .addEntryOrGroup(entryOrGroup1)
+ .addStaticEntryGroup(staticEntryGroup1)
+ .addDismissedIssue(issue2)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterData.Builder(status1)
+ .addIssue(issue2)
+ .addEntryOrGroup(entryOrGroup1)
+ .addStaticEntryGroup(staticEntryGroup1)
+ .addIssue(issue1)
+ .setExtras(filledExtrasIssuesToGroups1)
+ .build(),
+ SafetyCenterData.Builder(status1)
+ .addIssue(issue2)
+ .addEntryOrGroup(entryOrGroup1)
+ .addStaticEntryGroup(staticEntryGroup1)
+ .addIssue(issue1)
+ .setExtras(filledExtrasIssuesToGroups1)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterData.Builder(status1)
+ .addIssue(issue2)
+ .addEntryOrGroup(entryOrGroup1)
+ .addStaticEntryGroup(staticEntryGroup1)
+ .addIssue(issue1)
+ .setExtras(filledExtrasIssuesToGroups2)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterData.Builder(status1)
+ .addIssue(issue2)
+ .addEntryOrGroup(entryOrGroup1)
+ .addStaticEntryGroup(staticEntryGroup2)
+ .addIssue(issue1)
+ .setExtras(filledExtrasStaticEntriesToIds2)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterData.Builder(status1)
+ .addIssue(issue1)
+ .addEntryOrGroup(entryOrGroup1)
+ .addStaticEntryGroup(staticEntryGroup1)
+ .addDismissedIssue(issue2)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterData.Builder(status1)
+ .addEntryOrGroup(entryOrGroup1)
+ .addStaticEntryGroup(staticEntryGroup1)
+ .addDismissedIssue(issue1)
+ .addDismissedIssue(issue2)
+ .build()
+ )
.test()
}
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun toString_withSingleKnownExtra_containsKnownExtra() {
+ val safetyCenterDataWithExtras = data1.withExtrasIfAtLeastU(filledExtrasIssuesToGroups1)
+
+ val stringRepresentation = safetyCenterDataWithExtras.toString()
+
+ assertThat(stringRepresentation).contains("IssuesToGroups")
+ assertThat(stringRepresentation).doesNotContain("StaticEntriesToIds")
+ assertThat(stringRepresentation).doesNotContain("has unknown extras")
+ assertThat(stringRepresentation).doesNotContain("no extras")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun toString_withAllKnownExtras_containsKnownExtras() {
+ val safetyCenterDataWithAllExtras = data1.withExtrasIfAtLeastU(filledAllExtras)
+
+ val stringRepresentation = safetyCenterDataWithAllExtras.toString()
+
+ assertThat(stringRepresentation).contains("IssuesToGroups")
+ assertThat(stringRepresentation).contains("StaticEntriesToIds")
+ assertThat(stringRepresentation).doesNotContain("has unknown extras")
+ assertThat(stringRepresentation).doesNotContain("no extras")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun toString_withOneKnowAndOneUnknownExtra_containsKnownAndUnknownExtras() {
+ val safetyCenterDataWithExtras = data1.withExtrasIfAtLeastU(filledOneKnownOneUnknown)
+
+ val stringRepresentation = safetyCenterDataWithExtras.toString()
+
+ assertThat(stringRepresentation).contains("IssuesToGroups")
+ assertThat(stringRepresentation).contains("has unknown extras")
+ assertThat(stringRepresentation).doesNotContain("StaticEntriesToIds")
+ assertThat(stringRepresentation).doesNotContain("no extras")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun toString_withSingleUnknownExtra_containsUnknownExtras() {
+ val safetyCenterDataWithExtras = data1.withExtrasIfAtLeastU(unknownExtras)
+
+ val stringRepresentation = safetyCenterDataWithExtras.toString()
+
+ assertThat(stringRepresentation).contains("has unknown extras")
+ assertThat(stringRepresentation).doesNotContain("IssuesToGroups")
+ assertThat(stringRepresentation).doesNotContain("StaticEntriesToIds")
+ assertThat(stringRepresentation).doesNotContain("no extras")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun toString_withoutExtras_containsNoExtras() {
+ val safetyCenterDataWithoutExtras = data1
+
+ val stringRepresentation = safetyCenterDataWithoutExtras.toString()
+
+ assertThat(stringRepresentation).contains("no extras")
+ assertThat(stringRepresentation).doesNotContain("IssuesToGroups")
+ assertThat(stringRepresentation).doesNotContain("StaticEntriesToIds")
+ assertThat(stringRepresentation).doesNotContain("has unknown extras")
+ }
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryGroupTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryGroupTest.kt
index f874bc66d..7ae5fb347 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryGroupTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryGroupTest.kt
@@ -19,21 +19,19 @@ package android.safetycenter.cts
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
-import android.os.Build.VERSION_CODES.TIRAMISU
import android.safetycenter.SafetyCenterEntry
import android.safetycenter.SafetyCenterEntryGroup
-import android.safetycenter.cts.testing.EqualsHashCodeToStringTester
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
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.assertFailsWith
import org.junit.Test
import org.junit.runner.RunWith
+/** CTS tests for [SafetyCenterEntryGroup]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class SafetyCenterEntryGroupTest {
private val context: Context = ApplicationProvider.getApplicationContext()
@@ -97,13 +95,15 @@ class SafetyCenterEntryGroupTest {
SafetyCenterEntryGroup.Builder(entryGroup1)
.setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
.build()
- .severityLevel)
+ .severityLevel
+ )
.isEqualTo(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
assertThat(
SafetyCenterEntryGroup.Builder(entryGroup1)
.setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
.build()
- .severityLevel)
+ .severityLevel
+ )
.isEqualTo(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
}
@@ -114,9 +114,11 @@ class SafetyCenterEntryGroupTest {
assertThat(
SafetyCenterEntryGroup.Builder(entryGroup1)
.setSeverityUnspecifiedIconType(
- SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY)
+ SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY
+ )
.build()
- .severityUnspecifiedIconType)
+ .severityUnspecifiedIconType
+ )
.isEqualTo(SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY)
}
@@ -171,35 +173,46 @@ class SafetyCenterEntryGroupTest {
@Test
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetyCenterEntryGroup.CREATOR,
+ createCopy = { SafetyCenterEntryGroup.Builder(it).build() }
+ )
.addEqualityGroup(
entryGroup1,
- SafetyCenterEntryGroup.Builder(entryGroup1).build(),
SafetyCenterEntryGroup.Builder(groupId1, "A group title")
.setSummary("A group summary")
.setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK)
.setEntries(listOf(entry1))
- .build())
+ .build()
+ )
.addEqualityGroup(entryGroup2)
.addEqualityGroup(
- SafetyCenterEntryGroup.Builder(entryGroup1).setId("different!").build())
+ SafetyCenterEntryGroup.Builder(entryGroup1).setId("different!").build()
+ )
.addEqualityGroup(
- SafetyCenterEntryGroup.Builder(entryGroup1).setTitle("different!").build())
+ SafetyCenterEntryGroup.Builder(entryGroup1).setTitle("different!").build()
+ )
.addEqualityGroup(
- SafetyCenterEntryGroup.Builder(entryGroup1).setSummary("different!").build())
+ SafetyCenterEntryGroup.Builder(entryGroup1).setSummary("different!").build()
+ )
.addEqualityGroup(
SafetyCenterEntryGroup.Builder(entryGroup1)
.setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetyCenterEntryGroup.Builder(entryGroup1)
.setSeverityUnspecifiedIconType(
- SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY)
- .build())
+ SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY
+ )
+ .build()
+ )
.addEqualityGroup(
- SafetyCenterEntryGroup.Builder(entryGroup1).setEntries(listOf(entry2)).build())
+ SafetyCenterEntryGroup.Builder(entryGroup1).setEntries(listOf(entry2)).build()
+ )
.addEqualityGroup(
- SafetyCenterEntryGroup.Builder(entryGroup1).setEntries(emptyList()).build())
+ SafetyCenterEntryGroup.Builder(entryGroup1).setEntries(emptyList()).build()
+ )
.test()
}
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryOrGroupTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryOrGroupTest.kt
index dc14cc131..eb0e96898 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryOrGroupTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryOrGroupTest.kt
@@ -19,21 +19,19 @@ package android.safetycenter.cts
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
-import android.os.Build.VERSION_CODES.TIRAMISU
import android.safetycenter.SafetyCenterEntry
import android.safetycenter.SafetyCenterEntryGroup
import android.safetycenter.SafetyCenterEntryOrGroup
-import android.safetycenter.cts.testing.EqualsHashCodeToStringTester
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
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 org.junit.Test
import org.junit.runner.RunWith
+/** CTS tests for [SafetyCenterEntryOrGroup]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class SafetyCenterEntryOrGroupTest {
private val context: Context = ApplicationProvider.getApplicationContext()
@@ -101,7 +99,9 @@ class SafetyCenterEntryOrGroupTest {
@Test
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetyCenterEntryOrGroup.CREATOR
+ )
.addEqualityGroup(entryOrGroupWithEntry, SafetyCenterEntryOrGroup(entry1))
.addEqualityGroup(entryOrGroupWithGroup, SafetyCenterEntryOrGroup(entryGroup1))
.addEqualityGroup(SafetyCenterEntryOrGroup(entry2))
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryTest.kt
index 848dc12c1..116164288 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryTest.kt
@@ -19,20 +19,18 @@ package android.safetycenter.cts
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
-import android.os.Build.VERSION_CODES.TIRAMISU
import android.safetycenter.SafetyCenterEntry
-import android.safetycenter.cts.testing.EqualsHashCodeToStringTester
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
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.assertFailsWith
import org.junit.Test
import org.junit.runner.RunWith
+/** CTS tests for [SafetyCenterEntry]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class SafetyCenterEntryTest {
private val context: Context = ApplicationProvider.getApplicationContext()
@@ -40,14 +38,22 @@ class SafetyCenterEntryTest {
PendingIntent.getActivity(context, 0, Intent("Fake Data"), PendingIntent.FLAG_IMMUTABLE)
private val pendingIntent2 =
PendingIntent.getActivity(
- context, 0, Intent("Fake Different Data"), PendingIntent.FLAG_IMMUTABLE)
+ context,
+ 0,
+ Intent("Fake Different Data"),
+ PendingIntent.FLAG_IMMUTABLE
+ )
private val iconAction1 =
SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, pendingIntent1)
+ SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR,
+ pendingIntent1
+ )
private val iconAction2 =
SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO, pendingIntent2)
+ SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO,
+ pendingIntent2
+ )
private val entry1 =
SafetyCenterEntry.Builder("eNtRy_iD", "a title")
@@ -86,13 +92,15 @@ class SafetyCenterEntryTest {
SafetyCenterEntry.Builder(entry1)
.setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
.build()
- .severityLevel)
+ .severityLevel
+ )
.isEqualTo(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
assertThat(
SafetyCenterEntry.Builder(entry1)
.setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK)
.build()
- .severityLevel)
+ .severityLevel
+ )
.isEqualTo(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK)
}
@@ -103,9 +111,11 @@ class SafetyCenterEntryTest {
assertThat(
SafetyCenterEntry.Builder(entry1)
.setSeverityUnspecifiedIconType(
- SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY)
+ SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY
+ )
.build()
- .severityUnspecifiedIconType)
+ .severityUnspecifiedIconType
+ )
.isEqualTo(SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY)
}
@@ -122,7 +132,8 @@ class SafetyCenterEntryTest {
.setPendingIntent(pendingIntent1)
.setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN)
.build()
- .isEnabled)
+ .isEnabled
+ )
.isTrue()
}
@@ -132,13 +143,15 @@ class SafetyCenterEntryTest {
SafetyCenterEntry.Builder(entry1)
.setPendingIntent(pendingIntent1)
.build()
- .pendingIntent)
+ .pendingIntent
+ )
.isEqualTo(pendingIntent1)
assertThat(
SafetyCenterEntry.Builder(entry1)
.setPendingIntent(pendingIntent2)
.build()
- .pendingIntent)
+ .pendingIntent
+ )
.isEqualTo(pendingIntent2)
assertThat(SafetyCenterEntry.Builder(entry1).setPendingIntent(null).build().pendingIntent)
.isNull()
@@ -191,50 +204,67 @@ class SafetyCenterEntryTest {
.setSummary(null)
.setPendingIntent(null)
.setIconAction(null)
- .build())
+ .build()
+ )
.recreatesEqual(SafetyCenterEntry.CREATOR)
}
@Test
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
- .addEqualityGroup(entry1, SafetyCenterEntry.Builder(entry1).build())
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetyCenterEntry.CREATOR,
+ createCopy = { SafetyCenterEntry.Builder(it).build() }
+ )
+ .addEqualityGroup(entry1)
.addEqualityGroup(
SafetyCenterEntry.Builder("id", "a title")
.setSummary("a summary")
.setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK)
.setSeverityUnspecifiedIconType(
- SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY)
+ SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY
+ )
.setPendingIntent(pendingIntent1)
.setIconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO, pendingIntent2)
+ SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO,
+ pendingIntent2
+ )
.build(),
SafetyCenterEntry.Builder("id", "a title")
.setSummary("a summary")
.setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK)
.setSeverityUnspecifiedIconType(
- SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY)
+ SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY
+ )
.setPendingIntent(pendingIntent1)
.setIconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO, pendingIntent2)
- .build())
+ SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO,
+ pendingIntent2
+ )
+ .build()
+ )
.addEqualityGroup(SafetyCenterEntry.Builder(entry1).setId("a different id").build())
.addEqualityGroup(
- SafetyCenterEntry.Builder(entry1).setTitle("a different title").build())
+ SafetyCenterEntry.Builder(entry1).setTitle("a different title").build()
+ )
.addEqualityGroup(
- SafetyCenterEntry.Builder(entry1).setSummary("a different summary").build())
+ SafetyCenterEntry.Builder(entry1).setSummary("a different summary").build()
+ )
.addEqualityGroup(
SafetyCenterEntry.Builder(entry1)
.setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetyCenterEntry.Builder(entry1)
.setSeverityUnspecifiedIconType(
- SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY)
- .build())
+ SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY
+ )
+ .build()
+ )
.addEqualityGroup(SafetyCenterEntry.Builder(entry1).setEnabled(false).build())
.addEqualityGroup(
- SafetyCenterEntry.Builder(entry1).setPendingIntent(pendingIntent2).build())
+ SafetyCenterEntry.Builder(entry1).setPendingIntent(pendingIntent2).build()
+ )
.addEqualityGroup(SafetyCenterEntry.Builder(entry1).setIconAction(iconAction2).build())
.test()
}
@@ -243,13 +273,19 @@ class SafetyCenterEntryTest {
fun iconAction_getType_returnsType() {
assertThat(
SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, pendingIntent1)
- .type)
+ SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR,
+ pendingIntent1
+ )
+ .type
+ )
.isEqualTo(SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR)
assertThat(
SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO, pendingIntent1)
- .type)
+ SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO,
+ pendingIntent1
+ )
+ .type
+ )
.isEqualTo(SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO)
}
@@ -257,13 +293,19 @@ class SafetyCenterEntryTest {
fun iconAction_getPendingIntent_returnsPendingIntent() {
assertThat(
SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, pendingIntent1)
- .pendingIntent)
+ SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR,
+ pendingIntent1
+ )
+ .pendingIntent
+ )
.isEqualTo(pendingIntent1)
assertThat(
SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, pendingIntent2)
- .pendingIntent)
+ SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR,
+ pendingIntent2
+ )
+ .pendingIntent
+ )
.isEqualTo(pendingIntent2)
}
@@ -291,21 +333,35 @@ class SafetyCenterEntryTest {
@Test
fun iconAction_equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetyCenterEntry.IconAction.CREATOR
+ )
.addEqualityGroup(
iconAction1,
SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, pendingIntent1))
+ SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR,
+ pendingIntent1
+ )
+ )
.addEqualityGroup(
iconAction2,
SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO, pendingIntent2))
+ SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO,
+ pendingIntent2
+ )
+ )
.addEqualityGroup(
SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO, pendingIntent1))
+ SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO,
+ pendingIntent1
+ )
+ )
.addEqualityGroup(
SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, pendingIntent2))
+ SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR,
+ pendingIntent2
+ )
+ )
.test()
}
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterErrorDetailsTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterErrorDetailsTest.kt
index ab6c44434..0d97026bd 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterErrorDetailsTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterErrorDetailsTest.kt
@@ -16,18 +16,16 @@
package android.safetycenter.cts
-import android.os.Build.VERSION_CODES.TIRAMISU
import android.safetycenter.SafetyCenterErrorDetails
-import android.safetycenter.cts.testing.EqualsHashCodeToStringTester
import androidx.test.ext.junit.runners.AndroidJUnit4
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 org.junit.Test
import org.junit.runner.RunWith
+/** CTS tests for [SafetyCenterErrorDetails]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class SafetyCenterErrorDetailsTest {
private val errorDetails1 = SafetyCenterErrorDetails("an error message")
@@ -53,12 +51,15 @@ class SafetyCenterErrorDetailsTest {
@Test
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetyCenterErrorDetails.CREATOR
+ )
.addEqualityGroup(errorDetails1, SafetyCenterErrorDetails("an error message"))
.addEqualityGroup(errorDetails2, SafetyCenterErrorDetails("another error message"))
.addEqualityGroup(
SafetyCenterErrorDetails("a different error message"),
- SafetyCenterErrorDetails("a different error message"))
+ SafetyCenterErrorDetails("a different error message")
+ )
.test()
}
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterIssueTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterIssueTest.kt
index c7ee0f3bb..8d44f2736 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterIssueTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterIssueTest.kt
@@ -19,20 +19,25 @@ 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
-import android.safetycenter.cts.testing.EqualsHashCodeToStringTester
+import android.safetycenter.SafetyCenterIssue.Action.ConfirmationDialogDetails
+import androidx.annotation.RequiresApi
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
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.assertFailsWith
+import org.junit.Assume.assumeFalse
import org.junit.Test
import org.junit.runner.RunWith
+/** CTS tests for [SafetyCenterIssue]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class SafetyCenterIssueTest {
private val context: Context = ApplicationProvider.getApplicationContext()
@@ -40,7 +45,11 @@ class SafetyCenterIssueTest {
PendingIntent.getActivity(context, 0, Intent("Fake Data"), PendingIntent.FLAG_IMMUTABLE)
private val pendingIntent2 =
PendingIntent.getActivity(
- context, 0, Intent("Fake Different Data"), PendingIntent.FLAG_IMMUTABLE)
+ context,
+ 0,
+ Intent("Fake Different Data"),
+ PendingIntent.FLAG_IMMUTABLE
+ )
private val action1 =
SafetyCenterIssue.Action.Builder("action_id_1", "an action", pendingIntent1)
@@ -88,7 +97,8 @@ class SafetyCenterIssueTest {
assertThat(SafetyCenterIssue.Builder(issue1).setSubtitle("a subtitle").build().subtitle)
.isEqualTo("a subtitle")
assertThat(
- SafetyCenterIssue.Builder(issue1).setSubtitle("another subtitle").build().subtitle)
+ SafetyCenterIssue.Builder(issue1).setSubtitle("another subtitle").build().subtitle
+ )
.isEqualTo("another subtitle")
}
@@ -101,18 +111,49 @@ class SafetyCenterIssueTest {
}
@Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getAttributionTitle_returnsAttributionTitle() {
+ assertThat(
+ SafetyCenterIssue.Builder(issue1)
+ .setAttributionTitle("an attributionTitle")
+ .build()
+ .attributionTitle
+ )
+ .isEqualTo("an attributionTitle")
+ assertThat(
+ SafetyCenterIssue.Builder(issue1)
+ .setAttributionTitle("another attributionTitle")
+ .build()
+ .attributionTitle
+ )
+ .isEqualTo("another attributionTitle")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getAttributionTitle_withNullAttributionTitle_returnsNull() {
+ val safetyCenterIssue =
+ SafetyCenterIssue.Builder("issue_id", "Everything's good", "Please acknowledge this")
+ .build()
+
+ assertThat(safetyCenterIssue.attributionTitle).isNull()
+ }
+
+ @Test
fun getSeverityLevel_returnsSeverityLevel() {
assertThat(
SafetyCenterIssue.Builder(issue1)
.setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION)
.build()
- .severityLevel)
+ .severityLevel
+ )
.isEqualTo(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION)
assertThat(
SafetyCenterIssue.Builder(issue1)
.setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING)
.build()
- .severityLevel)
+ .severityLevel
+ )
.isEqualTo(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING)
}
@@ -135,13 +176,15 @@ class SafetyCenterIssueTest {
SafetyCenterIssue.Builder(issue1)
.setShouldConfirmDismissal(true)
.build()
- .shouldConfirmDismissal())
+ .shouldConfirmDismissal()
+ )
.isTrue()
assertThat(
SafetyCenterIssue.Builder(issue1)
.setShouldConfirmDismissal(false)
.build()
- .shouldConfirmDismissal())
+ .shouldConfirmDismissal()
+ )
.isFalse()
}
@@ -156,7 +199,8 @@ class SafetyCenterIssueTest {
SafetyCenterIssue.Builder(issue1)
.setActions(listOf(action1, action2))
.build()
- .actions)
+ .actions
+ )
.containsExactly(action1, action2)
.inOrder()
assertThat(SafetyCenterIssue.Builder(issue1).setActions(listOf(action2)).build().actions)
@@ -184,6 +228,66 @@ class SafetyCenterIssueTest {
}
@Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getGroupId_withNonNullValue_returnsGroupId() {
+ val issue = SafetyCenterIssue.Builder(issue1).setGroupId("group_id").build()
+
+ assertThat(issue.groupId).isEqualTo("group_id")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getGroupId_withNullValue_returnsNull() {
+ val issue =
+ SafetyCenterIssue.Builder("issue_id", "Everything's good", "Please acknowledge this")
+ .build()
+
+ assertThat(issue.groupId).isNull()
+ }
+
+ @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")
+ 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")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun setGroupId_withNullValue_returnsNull() {
+ val issue = SafetyCenterIssue.Builder(issue1).setGroupId(null).build()
+
+ assertThat(issue.groupId).isNull()
+ }
+
+ @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")
+ }
+
+ @Test
fun describeContents_returns0() {
assertThat(issue1.describeContents()).isEqualTo(0)
assertThat(issueWithRequiredFieldsOnly.describeContents()).isEqualTo(0)
@@ -196,37 +300,39 @@ class SafetyCenterIssueTest {
}
@Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun parcelRoundTrip_recreatesEqual_atLeastAndroidU() {
+ val safetyCenterIssue =
+ SafetyCenterIssue.Builder("issue_id", "Everything's good", "Please acknowledge this")
+ .setSubtitle("In the neighborhood")
+ .setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK)
+ .setDismissible(true)
+ .setShouldConfirmDismissal(true)
+ .setActions(
+ listOf(
+ SafetyCenterIssue.Action.Builder(action1)
+ .setConfirmationDialogDetails(
+ ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+ )
+ .build()
+ )
+ )
+ .setAttributionTitle("Attribution title")
+ .setGroupId("group_id")
+ .build()
+
+ assertThat(safetyCenterIssue).recreatesEqual(SafetyCenterIssue.CREATOR)
+ }
+
+ @Test
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
- .addEqualityGroup(issue1, SafetyCenterIssue.Builder(issue1).build())
- .addEqualityGroup(issueWithRequiredFieldsOnly)
- .addEqualityGroup(
- SafetyCenterIssue.Builder("an id", "a title", "Please acknowledge this")
- .setSubtitle("In the neighborhood")
- .setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK)
- .setActions(listOf(action1))
- .build(),
- SafetyCenterIssue.Builder("an id", "a title", "Please acknowledge this")
- .setSubtitle("In the neighborhood")
- .setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK)
- .setActions(listOf(action1))
- .build())
- .addEqualityGroup(SafetyCenterIssue.Builder(issue1).setId("a different id").build())
- .addEqualityGroup(
- SafetyCenterIssue.Builder(issue1).setTitle("a different title").build())
- .addEqualityGroup(
- SafetyCenterIssue.Builder(issue1).setSubtitle("a different subtitle").build())
- .addEqualityGroup(
- SafetyCenterIssue.Builder(issue1).setSummary("a different summary").build())
- .addEqualityGroup(
- SafetyCenterIssue.Builder(issue1)
- .setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING)
- .build())
- .addEqualityGroup(SafetyCenterIssue.Builder(issue1).setDismissible(false).build())
- .addEqualityGroup(
- SafetyCenterIssue.Builder(issue1).setShouldConfirmDismissal(false).build())
- .addEqualityGroup(SafetyCenterIssue.Builder(issue1).setActions(listOf(action2)).build())
- .test()
+ newTiramisuEqualsHashCodeToStringTester().test()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun equalsHashCodeToString_usingEqualsHashCodeToStringTester_atLeastAndroidU() {
+ newUpsideDownCakeEqualsHashCodeToStringTester().test()
}
@Test
@@ -266,6 +372,53 @@ 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 }
+ }
+
+ @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) {
+ SafetyCenterIssue.Action.Builder("action_id", "Action label", pendingIntent1)
+ .setConfirmationDialogDetails(
+ ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+ )
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun action_getConfirmationDialogDetails_withDefaultBuilder_returnsNull() {
+ val action =
+ SafetyCenterIssue.Action.Builder("action_id", "Action label", pendingIntent1).build()
+
+ assertThat(action.confirmationDialogDetails).isNull()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun action_getConfirmationDialogDetails_whenSetExplicitly_returnsConfirmation() {
+ val action =
+ SafetyCenterIssue.Action.Builder("action_id", "Action label", pendingIntent1)
+ .setConfirmationDialogDetails(
+ ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+ )
+ .build()
+
+ assertThat(action.confirmationDialogDetails)
+ .isEqualTo(ConfirmationDialogDetails("Title", "Text", "Accept", "Deny"))
+ }
+
+ @Test
fun action_describeContents_returns0() {
assertThat(action1.describeContents()).isEqualTo(0)
assertThat(action2.describeContents()).isEqualTo(0)
@@ -278,57 +431,344 @@ class SafetyCenterIssueTest {
}
@Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun action_parcelRoundTrip_recreatesEqual_atLeastAndroidU() {
+ val action =
+ SafetyCenterIssue.Action.Builder(action1)
+ .setConfirmationDialogDetails(
+ ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+ )
+ .build()
+
+ assertThat(action).recreatesEqual(SafetyCenterIssue.Action.CREATOR)
+ }
+
+ @Test
fun action_equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
- .addEqualityGroup(action1)
- .addEqualityGroup(action2)
+ issueActionNewTiramisuEqualsHashCodeToStringTester().test()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun action_equalsHashCodeToString_usingEqualsHashCodeToStringTester_atLeastAndroidU() {
+ val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+ issueActionNewTiramisuEqualsHashCodeToStringTester(
+ createCopyFromBuilder = { SafetyCenterIssue.Action.Builder(it).build() }
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Action.Builder(action1)
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Action.Builder(action2)
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build()
+ )
.addEqualityGroup(
SafetyCenterIssue.Action.Builder("an_id", "a label", pendingIntent1)
.setWillResolve(true)
.setIsInFlight(true)
.setSuccessMessage("a success message")
+ .setConfirmationDialogDetails(confirmationDialogDetails)
.build(),
SafetyCenterIssue.Action.Builder("an_id", "a label", pendingIntent1)
.setWillResolve(true)
.setIsInFlight(true)
.setSuccessMessage("a success message")
- .build())
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build()
+ )
.addEqualityGroup(
SafetyCenterIssue.Action.Builder("an_id", "a label", pendingIntent1)
.setSuccessMessage("a success message")
- .build())
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build()
+ )
.addEqualityGroup(
SafetyCenterIssue.Action.Builder("a_different_id", "a label", pendingIntent1)
.setSuccessMessage("a success message")
- .build())
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build()
+ )
.addEqualityGroup(
SafetyCenterIssue.Action.Builder("an_id", "a different label", pendingIntent1)
.setSuccessMessage("a success message")
- .build())
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build()
+ )
.addEqualityGroup(
SafetyCenterIssue.Action.Builder("an_id", "a label", pendingIntent2)
.setSuccessMessage("a success message")
- .build())
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build()
+ )
.addEqualityGroup(
SafetyCenterIssue.Action.Builder("an_id", "a label", pendingIntent1)
.setWillResolve(true)
.setSuccessMessage("a success message")
- .build())
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build()
+ )
.addEqualityGroup(
SafetyCenterIssue.Action.Builder("an_id", "a label", pendingIntent1)
.setIsInFlight(true)
.setSuccessMessage("a success message")
- .build())
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build()
+ )
.addEqualityGroup(
SafetyCenterIssue.Action.Builder("an_id", "a label", pendingIntent1)
.setSuccessMessage("a different success message")
- .build())
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build()
+ )
.addEqualityGroup(
SafetyCenterIssue.Action.Builder("an_id", "a label", pendingIntent1)
.setId("another_id")
.setLabel("another_label")
.setPendingIntent(pendingIntent2)
- .build())
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build()
+ )
.test()
}
+
+ /**
+ * Creates a new [EqualsHashCodeToStringTester] instance with all the equality groups in the
+ * [newTiramisuEqualsHashCodeToStringTester] plus new equality groups covering all the new
+ * fields added in U.
+ */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ private fun newUpsideDownCakeEqualsHashCodeToStringTester():
+ EqualsHashCodeToStringTester<SafetyCenterIssue> {
+ val issueWithTiramisuFields =
+ SafetyCenterIssue.Builder("issue_id", "Everything's good", "Please acknowledge this")
+ .setSubtitle("In the neighborhood")
+ .setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK)
+ .setDismissible(true)
+ .setShouldConfirmDismissal(true)
+ .setActions(listOf(action1))
+ .build()
+ val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+ return newTiramisuEqualsHashCodeToStringTester(
+ createCopyFromBuilder = { SafetyCenterIssue.Builder(it).build() }
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Builder(issueWithTiramisuFields)
+ .setAttributionTitle("Attribution title")
+ .build(),
+ SafetyCenterIssue.Builder(issueWithTiramisuFields)
+ .setAttributionTitle("Attribution title")
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Builder(issueWithTiramisuFields)
+ .setAttributionTitle("a different attribution title")
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Builder(issueWithTiramisuFields)
+ .setAttributionTitle("Attribution title")
+ .setGroupId("group_id")
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Builder(issueWithTiramisuFields).setGroupId("group_id").build(),
+ SafetyCenterIssue.Builder(issueWithTiramisuFields).setGroupId("group_id").build()
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Builder(issueWithTiramisuFields)
+ .setGroupId("a different group_id")
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Builder(issueWithTiramisuFields)
+ .setActions(
+ listOf(
+ SafetyCenterIssue.Action.Builder(action1)
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build()
+ )
+ )
+ .build()
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun actionConfirmation_getTitle_returnsTitle() {
+ val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+
+ assertThat(confirmationDialogDetails.title).isEqualTo("Title")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun actionConfirmation_getText_returnsText() {
+ val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+
+ assertThat(confirmationDialogDetails.text).isEqualTo("Text")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun actionConfirmation_getAcceptButtonText_returnsAcceptButtonText() {
+ val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+
+ assertThat(confirmationDialogDetails.acceptButtonText).isEqualTo("Accept")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun actionConfirmation_getDenyButtonText_returnsDenyButtonText() {
+ val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+
+ assertThat(confirmationDialogDetails.denyButtonText).isEqualTo("Deny")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun actionConfirmation_describeContents_returns0() {
+ val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+
+ assertThat(confirmationDialogDetails.describeContents()).isEqualTo(0)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun actionConfirmation_parcelRoundTrip_recreatesEqual() {
+ val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+
+ assertThat(confirmationDialogDetails).recreatesEqual(ConfirmationDialogDetails.CREATOR)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun actionConfirmation_equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = ConfirmationDialogDetails.CREATOR
+ )
+ .addEqualityGroup(
+ ConfirmationDialogDetails("Title", "Text", "Accept", "Deny"),
+ ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+ )
+ .addEqualityGroup(ConfirmationDialogDetails("Other title", "Text", "Accept", "Deny"))
+ .addEqualityGroup(ConfirmationDialogDetails("Title", "Other text", "Accept", "Deny"))
+ .addEqualityGroup(ConfirmationDialogDetails("Title", "Text", "Other accept", "Deny"))
+ .addEqualityGroup(ConfirmationDialogDetails("Title", "Text", "Accept", "Other deny"))
+ .test()
+ }
+
+ /**
+ * Creates a new [EqualsHashCodeToStringTester] instance which covers all the fields in the T
+ * API and is safe to use on any T+ API level.
+ */
+ private fun newTiramisuEqualsHashCodeToStringTester(
+ createCopyFromBuilder: ((SafetyCenterIssue) -> SafetyCenterIssue)? = null
+ ) =
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetyCenterIssue.CREATOR,
+ createCopy = createCopyFromBuilder
+ )
+ .addEqualityGroup(issue1, SafetyCenterIssue.Builder(issue1).build())
+ .addEqualityGroup(issueWithRequiredFieldsOnly)
+ .addEqualityGroup(
+ SafetyCenterIssue.Builder("an id", "a title", "Please acknowledge this")
+ .setSubtitle("In the neighborhood")
+ .setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK)
+ .setActions(listOf(action1))
+ .build(),
+ SafetyCenterIssue.Builder("an id", "a title", "Please acknowledge this")
+ .setSubtitle("In the neighborhood")
+ .setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK)
+ .setActions(listOf(action1))
+ .build()
+ )
+ .addEqualityGroup(SafetyCenterIssue.Builder(issue1).setId("a different id").build())
+ .addEqualityGroup(
+ SafetyCenterIssue.Builder(issue1).setTitle("a different title").build()
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Builder(issue1).setSubtitle("a different subtitle").build()
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Builder(issue1).setSummary("a different summary").build()
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Builder(issue1)
+ .setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .build()
+ )
+ .addEqualityGroup(SafetyCenterIssue.Builder(issue1).setDismissible(false).build())
+ .addEqualityGroup(
+ SafetyCenterIssue.Builder(issue1).setShouldConfirmDismissal(false).build()
+ )
+ .addEqualityGroup(SafetyCenterIssue.Builder(issue1).setActions(listOf(action2)).build())
+
+ private fun issueActionNewTiramisuEqualsHashCodeToStringTester(
+ createCopyFromBuilder: ((SafetyCenterIssue.Action) -> SafetyCenterIssue.Action)? = null
+ ) =
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetyCenterIssue.Action.CREATOR,
+ createCopy = createCopyFromBuilder
+ )
+ .addEqualityGroup(action1)
+ .addEqualityGroup(action2)
+ .addEqualityGroup(
+ SafetyCenterIssue.Action.Builder("an_id", "a label", pendingIntent1)
+ .setWillResolve(true)
+ .setIsInFlight(true)
+ .setSuccessMessage("a success message")
+ .build(),
+ SafetyCenterIssue.Action.Builder("an_id", "a label", pendingIntent1)
+ .setWillResolve(true)
+ .setIsInFlight(true)
+ .setSuccessMessage("a success message")
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Action.Builder("an_id", "a label", pendingIntent1)
+ .setSuccessMessage("a success message")
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Action.Builder("a_different_id", "a label", pendingIntent1)
+ .setSuccessMessage("a success message")
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Action.Builder("an_id", "a different label", pendingIntent1)
+ .setSuccessMessage("a success message")
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Action.Builder("an_id", "a label", pendingIntent2)
+ .setSuccessMessage("a success message")
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Action.Builder("an_id", "a label", pendingIntent1)
+ .setWillResolve(true)
+ .setSuccessMessage("a success message")
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Action.Builder("an_id", "a label", pendingIntent1)
+ .setIsInFlight(true)
+ .setSuccessMessage("a success message")
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Action.Builder("an_id", "a label", pendingIntent1)
+ .setSuccessMessage("a different success message")
+ .build()
+ )
+ .addEqualityGroup(
+ SafetyCenterIssue.Action.Builder("an_id", "a label", pendingIntent1)
+ .setId("another_id")
+ .setLabel("another_label")
+ .setPendingIntent(pendingIntent2)
+ .build()
+ )
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt
index 1ae0e03dd..b6bb475d8 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt
@@ -16,155 +16,124 @@
package android.safetycenter.cts
-import android.Manifest.permission.MANAGE_SAFETY_CENTER
-import android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE
-import android.app.PendingIntent
-import android.app.PendingIntent.FLAG_IMMUTABLE
import android.content.Context
-import android.content.Intent
-import android.content.Intent.ACTION_SAFETY_CENTER
+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
+import android.os.UserManager
import android.safetycenter.SafetyCenterData
import android.safetycenter.SafetyCenterErrorDetails
import android.safetycenter.SafetyCenterManager
import android.safetycenter.SafetyCenterManager.OnSafetyCenterDataChangedListener
+import android.safetycenter.SafetyCenterManager.REFRESH_REASON_OTHER
import android.safetycenter.SafetyCenterManager.REFRESH_REASON_PAGE_OPEN
+import android.safetycenter.SafetyCenterManager.REFRESH_REASON_PERIODIC
import android.safetycenter.SafetyCenterManager.REFRESH_REASON_RESCAN_BUTTON_CLICK
-import android.safetycenter.SafetyEvent
-import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
import android.safetycenter.SafetySourceData
-import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING
import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_INFORMATION
-import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED
import android.safetycenter.SafetySourceErrorDetails
-import android.safetycenter.SafetySourceIssue
+import android.safetycenter.SafetySourceIssue.ISSUE_CATEGORY_ACCOUNT
import android.safetycenter.SafetySourceIssue.ISSUE_CATEGORY_DEVICE
-import android.safetycenter.SafetySourceStatus
-import android.safetycenter.config.SafetyCenterConfig
-import android.safetycenter.config.SafetySource
-import android.safetycenter.config.SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC
-import android.safetycenter.config.SafetySourcesGroup
-import android.safetycenter.cts.testing.Coroutines.TIMEOUT_LONG
-import android.safetycenter.cts.testing.Coroutines.TIMEOUT_SHORT
-import android.safetycenter.cts.testing.Coroutines.runBlockingWithTimeout
+import android.safetycenter.SafetySourceIssue.ISSUE_CATEGORY_GENERAL
import android.safetycenter.cts.testing.FakeExecutor
-import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.addOnSafetyCenterDataChangedListenerWithPermission
-import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.clearAllSafetySourceDataForTestsWithPermission
-import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.clearSafetyCenterConfigForTestsWithPermission
-import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.getSafetyCenterConfigWithPermission
-import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.getSafetyCenterDataWithPermission
-import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.getSafetySourceDataWithPermission
-import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.isSafetyCenterEnabledWithPermission
-import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.refreshSafetySourcesWithPermission
-import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.removeOnSafetyCenterDataChangedListenerWithPermission
-import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.setSafetyCenterConfigForTestsWithPermission
-import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.setSafetySourceDataWithPermission
-import android.safetycenter.cts.testing.SafetyCenterFlags
-import android.safetycenter.cts.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
-import android.safetycenter.cts.testing.SafetySourceBroadcastReceiver
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.SystemUtil.callWithShellPermissionIdentity
+import com.android.safetycenter.resources.SafetyCenterResourcesContext
+import com.android.safetycenter.testing.Coroutines.TIMEOUT_LONG
+import com.android.safetycenter.testing.Coroutines.TIMEOUT_SHORT
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.addOnSafetyCenterDataChangedListenerWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.clearAllSafetySourceDataForTestsWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.clearSafetyCenterConfigForTestsWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.dismissSafetyCenterIssueWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.executeSafetyCenterIssueActionWithPermission
+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.isSafetyCenterEnabledWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.refreshSafetySourcesWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.removeOnSafetyCenterDataChangedListenerWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.reportSafetySourceErrorWithPermission
+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
+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
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.DYNAMIC_IN_STATELESS_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.DYNAMIC_OTHER_PACKAGE_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.ISSUE_ONLY_ALL_OPTIONAL_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.ISSUE_ONLY_BAREBONE_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.PACKAGE_CERT_HASH_INVALID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SAMPLE_SOURCE_ID
+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.SafetyCenterTestConfigs.Companion.STATIC_BAREBONE_ID
+import com.android.safetycenter.testing.SafetyCenterTestData
+import com.android.safetycenter.testing.SafetyCenterTestHelper
+import com.android.safetycenter.testing.SafetyCenterTestListener
+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.dismissSafetyCenterIssueWithPermissionAndWait
+import com.android.safetycenter.testing.SafetySourceReceiver.Companion.executeSafetyCenterIssueActionWithPermissionAndWait
+import com.android.safetycenter.testing.SafetySourceReceiver.Companion.refreshSafetySourcesWithReceiverPermissionAndWait
+import com.android.safetycenter.testing.SafetySourceReceiver.Companion.refreshSafetySourcesWithoutReceiverPermissionAndWait
+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 com.android.safetycenter.testing.SafetySourceTestData.Companion.EVENT_SOURCE_STATE_CHANGED
+import com.android.safetycenter.testing.SafetySourceTestData.Companion.RECOMMENDATION_ISSUE_ID
+import com.google.common.base.Preconditions.checkState
import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.MoreExecutors.directExecutor
-import java.time.Duration
import kotlin.test.assertFailsWith
import kotlinx.coroutines.TimeoutCancellationException
-import kotlinx.coroutines.channels.Channel
-import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
import org.junit.After
+import org.junit.Assume.assumeFalse
import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+/** CTS tests for [SafetyCenterManager]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class SafetyCenterManagerTest {
private val context: Context = getApplicationContext()
+ private val safetyCenterResourcesContext = SafetyCenterResourcesContext.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)!!
- private val somePendingIntent =
- PendingIntent.getActivity(
- context, 0 /* requestCode */, Intent(ACTION_SAFETY_CENTER), FLAG_IMMUTABLE)
- private val safetySourceDataUnspecified =
- SafetySourceData.Builder()
- .setStatus(
- SafetySourceStatus.Builder("None title", "None summary", SEVERITY_LEVEL_UNSPECIFIED)
- .setEnabled(false)
- .build())
- .build()
- private val safetySourceDataInformation =
- SafetySourceData.Builder()
- .setStatus(
- SafetySourceStatus.Builder("Ok title", "Ok summary", SEVERITY_LEVEL_INFORMATION)
- .setPendingIntent(somePendingIntent)
- .build())
- .build()
- private val safetySourceDataCritical =
- SafetySourceData.Builder()
- .setStatus(
- SafetySourceStatus.Builder(
- "Critical title", "Critical summary", SEVERITY_LEVEL_CRITICAL_WARNING)
- .setPendingIntent(somePendingIntent)
- .build())
- .addIssue(
- SafetySourceIssue.Builder(
- "critical_issue_id",
- "Critical issue title",
- "Critical issue summary",
- SEVERITY_LEVEL_CRITICAL_WARNING,
- "issue_type_id")
- .addAction(
- SafetySourceIssue.Action.Builder(
- "critical_action_id", "Solve issue", somePendingIntent)
- .build())
- .setIssueCategory(ISSUE_CATEGORY_DEVICE)
- .build())
- .build()
- private val listener =
- object : OnSafetyCenterDataChangedListener {
- private val dataChannel = Channel<SafetyCenterData>(UNLIMITED)
- private val errorChannel = Channel<SafetyCenterErrorDetails>(UNLIMITED)
-
- override fun onSafetyCenterDataChanged(data: SafetyCenterData) {
- runBlockingWithTimeout { dataChannel.send(data) }
- }
-
- override fun onError(errorDetails: SafetyCenterErrorDetails) {
- runBlockingWithTimeout { errorChannel.send(errorDetails) }
- }
- fun receiveSafetyCenterData(timeout: Duration = TIMEOUT_LONG) =
- runBlockingWithTimeout(timeout) { dataChannel.receive() }
-
- fun receiveSafetyCenterErrorDetails(timeout: Duration = TIMEOUT_LONG) =
- runBlockingWithTimeout(timeout) { errorChannel.receive() }
-
- fun cancelChannels() {
- dataChannel.cancel()
- errorChannel.cancel()
- }
- }
+ // 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(context.deviceSupportsSafetyCenter())
+ assumeTrue(shouldRunTests)
}
@Before
- @After
- fun clearDataBetweenTest() {
- SafetyCenterFlags.setSafetyCenterEnabled(true)
- safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(listener)
- safetyCenterManager.clearAllSafetySourceDataForTestsWithPermission()
- safetyCenterManager.clearSafetyCenterConfigForTestsWithPermission()
- SafetySourceBroadcastReceiver.reset()
+ fun enableSafetyCenterBeforeTest() {
+ if (!shouldRunTests) {
+ return
+ }
+ safetyCenterTestHelper.setup()
}
@After
- fun cancelChannelsAfterTest() {
- listener.cancelChannels()
+ fun clearDataAfterTest() {
+ if (!shouldRunTests) {
+ return
+ }
+ safetyCenterTestHelper.reset()
}
@Test
@@ -176,7 +145,7 @@ class SafetyCenterManagerTest {
@Test
fun isSafetyCenterEnabled_withFlagDisabled_returnsFalse() {
- SafetyCenterFlags.setSafetyCenterEnabled(false)
+ safetyCenterTestHelper.setEnabled(false)
val isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabledWithPermission()
@@ -190,53 +159,480 @@ class SafetyCenterManagerTest {
@Test
fun setSafetySourceData_validId_setsValue() {
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceDataUnspecified, EVENT_SOURCE_STATE_CHANGED)
+ val dataToSet = safetySourceTestData.unspecified
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataToSet)
val apiSafetySourceData =
- safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
- assertThat(apiSafetySourceData).isEqualTo(safetySourceDataUnspecified)
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData).isEqualTo(dataToSet)
}
@Test
fun setSafetySourceData_twice_replacesValue() {
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceDataUnspecified, EVENT_SOURCE_STATE_CHANGED)
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.unspecified)
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceDataCritical, EVENT_SOURCE_STATE_CHANGED)
+ val dataToSet = safetySourceTestData.criticalWithResolvingGeneralIssue
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataToSet)
val apiSafetySourceData =
- safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
- assertThat(apiSafetySourceData).isEqualTo(safetySourceDataCritical)
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData).isEqualTo(dataToSet)
}
@Test
fun setSafetySourceData_null_clearsValue() {
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceDataUnspecified, EVENT_SOURCE_STATE_CHANGED)
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.unspecified)
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceData = null, EVENT_SOURCE_STATE_CHANGED)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceData = null)
val apiSafetySourceData =
- safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isNull()
}
@Test
- fun setSafetySourceData_withFlagDisabled_noOp() {
- SafetyCenterFlags.setSafetyCenterEnabled(false)
+ fun setSafetySourceData_sourceInStatelessGroupUnspecified_setsValue() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
+
+ val dataToSet = safetySourceTestData.unspecified
+ safetyCenterTestHelper.setData(DYNAMIC_IN_STATELESS_ID, dataToSet)
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(DYNAMIC_IN_STATELESS_ID)
+ assertThat(apiSafetySourceData).isEqualTo(dataToSet)
+ }
+
+ @Test
+ fun setSafetySourceData_unknownId_throwsIllegalArgumentException() {
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.unspecified)
+ }
+
+ assertThat(thrown).hasMessageThat().isEqualTo("Unexpected safety source: $SINGLE_SOURCE_ID")
+ }
+
+ @Test
+ fun setSafetySourceData_staticId_throwsIllegalArgumentException() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
+
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterTestHelper.setData(STATIC_BAREBONE_ID, safetySourceTestData.unspecified)
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo("Unexpected safety source: $STATIC_BAREBONE_ID")
+ }
+
+ @Test
+ fun setSafetySourceData_differentPackage_throwsIllegalArgumentException() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
+
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterTestHelper.setData(
+ DYNAMIC_OTHER_PACKAGE_ID,
+ safetySourceTestData.unspecified
+ )
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo(
+ "Unexpected package name: ${context.packageName}, for safety source: " +
+ DYNAMIC_OTHER_PACKAGE_ID
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun setSafetySourceData_wronglySignedPackage_throwsIllegalArgumentException() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceWithFakeCert)
+
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.unspecified)
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo("Invalid signature for package " + context.packageName)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun setSafetySourceData_wronglySignedPackageButAllowedByFlag_isAllowed() {
+ SafetyCenterFlags.allowedAdditionalPackageCerts =
+ mapOf(context.packageName to setOf(safetyCenterTestConfigs.packageCertHash))
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceWithFakeCert)
+
+ val dataToSet = safetySourceTestData.unspecified
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataToSet)
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData).isEqualTo(dataToSet)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun setSafetySourceData_invalidPackageCertificate_throwsIllegalArgumentException() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceWithInvalidCert)
+
+ val thrown =
+ assertFailsWith(IllegalStateException::class) {
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.unspecified)
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo("Failed to parse signing certificate: " + PACKAGE_CERT_HASH_INVALID)
+ }
+
+ @Test
+ fun setSafetySourceData_sourceInStatelessGroupNotUnspecified_throwsIllegalArgumentException() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
+
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterTestHelper.setData(
+ DYNAMIC_IN_STATELESS_ID,
+ safetySourceTestData.information
+ )
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo(
+ "Safety source: $DYNAMIC_IN_STATELESS_ID is in a stateless group but specified a " +
+ "severity level: $SEVERITY_LEVEL_INFORMATION"
+ )
+ }
+
+ @Test
+ fun setSafetySourceData_nullUnknownId_throwsIllegalArgumentException() {
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceData = null)
+ }
+
+ assertThat(thrown).hasMessageThat().isEqualTo("Unexpected safety source: $SINGLE_SOURCE_ID")
+ }
+
+ @Test
+ fun setSafetySourceData_nullStaticId_throwsIllegalArgumentException() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
+
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterTestHelper.setData(STATIC_BAREBONE_ID, safetySourceData = null)
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo("Unexpected safety source: $STATIC_BAREBONE_ID")
+ }
+
+ @Test
+ fun setSafetySourceData_nullDifferentPackage_throwsIllegalArgumentException() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
+
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterTestHelper.setData(DYNAMIC_OTHER_PACKAGE_ID, safetySourceData = null)
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo(
+ "Unexpected package name: ${context.packageName}, for safety source: " +
+ DYNAMIC_OTHER_PACKAGE_ID
+ )
+ }
+
+ @Test
+ fun setSafetySourceData_issueOnlyWithStatus_throwsIllegalArgumentException() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
+
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_BAREBONE_ID,
+ safetySourceTestData.unspecified
+ )
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo("Unexpected status for issue only safety source: $ISSUE_ONLY_BAREBONE_ID")
+ }
+
+ @Test
+ fun setSafetySourceData_dynamicWithIssueOnly_throwsIllegalArgumentException() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
+
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterTestHelper.setData(
+ DYNAMIC_BAREBONE_ID,
+ SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue)
+ )
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo("Missing status for dynamic safety source: $DYNAMIC_BAREBONE_ID")
+ }
+
+ @Test
+ fun setSafetySourceData_withMaxSevZeroAndSourceSevUnspecified_setsValue() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.severityZeroConfig)
+
+ val dataToSet = safetySourceTestData.unspecified
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataToSet)
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData).isEqualTo(dataToSet)
+ }
+
+ @Test
+ fun setSafetySourceData_withMaxSevZeroAndSourceSevInformation_setsValue() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.severityZeroConfig)
+
+ val dataToSet = safetySourceTestData.information
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataToSet)
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData).isEqualTo(dataToSet)
+ }
+
+ @Test
+ fun setSafetySourceData_withMaxSevZeroAndSourceSevInformationWithIssue_throwsException() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.severityZeroConfig)
+
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.informationWithIssue
+ )
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo(
+ "Unexpected severity level: ${
+ SafetySourceData.SEVERITY_LEVEL_INFORMATION
+ }, for issue in safety source: $SINGLE_SOURCE_ID"
+ )
+ }
+
+ @Test
+ fun setSafetySourceData_withMaxSevZeroAndSourceSevCritical_throwsException() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.severityZeroConfig)
+
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo(
+ "Unexpected severity level: ${
+ SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING
+ }, for safety source: $SINGLE_SOURCE_ID"
+ )
+ }
+
+ @Test
+ fun setSafetySourceData_withMaxSevRecommendation_met() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
+
+ val dataToSet = safetySourceTestData.recommendationWithGeneralIssue
+ safetyCenterTestHelper.setData(DYNAMIC_ALL_OPTIONAL_ID, dataToSet)
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(DYNAMIC_ALL_OPTIONAL_ID)
+ assertThat(apiSafetySourceData).isEqualTo(dataToSet)
+ }
+
+ @Test
+ fun setSafetySourceData_withMaxSevRecommendation_notMet() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
+
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterTestHelper.setData(
+ DYNAMIC_ALL_OPTIONAL_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo(
+ "Unexpected severity level: ${
+ SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING
+ }, for safety source: $DYNAMIC_ALL_OPTIONAL_ID"
+ )
+ }
+
+ @Test
+ fun setSafetySourceData_issueOnlyWithMaxSevRecommendation_met() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
+
+ val dataToSet =
+ SafetySourceTestData.issuesOnly(safetySourceTestData.recommendationGeneralIssue)
+ safetyCenterTestHelper.setData(ISSUE_ONLY_ALL_OPTIONAL_ID, dataToSet)
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(ISSUE_ONLY_ALL_OPTIONAL_ID)
+ assertThat(apiSafetySourceData).isEqualTo(dataToSet)
+ }
+
+ @Test
+ fun setSafetySourceData_issueOnlyWithMaxSevRecommendation_notMet() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
+
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalResolvingGeneralIssue
+ )
+ )
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo(
+ "Unexpected severity level: ${
+ SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING
+ }, for issue in safety source: $ISSUE_ONLY_ALL_OPTIONAL_ID"
+ )
+ }
+
+ @Test
+ fun setSafetySourceData_withEmptyCategoryAllowlists_met() {
+ SafetyCenterFlags.issueCategoryAllowlists = emptyMap()
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val dataToSet = safetySourceTestData.recommendationWithAccountIssue
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataToSet)
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData).isEqualTo(dataToSet)
+ }
+
+ @Test
+ fun setSafetySourceData_withMissingAllowlistForCategory_met() {
+ SafetyCenterFlags.issueCategoryAllowlists =
+ mapOf(
+ ISSUE_CATEGORY_DEVICE to setOf(SAMPLE_SOURCE_ID),
+ ISSUE_CATEGORY_GENERAL to setOf(SAMPLE_SOURCE_ID)
+ )
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val dataToSet = safetySourceTestData.recommendationWithAccountIssue
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataToSet)
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData).isEqualTo(dataToSet)
+ }
+
+ @Test
+ fun setSafetySourceData_withAllowlistedSourceForCategory_met() {
+ SafetyCenterFlags.issueCategoryAllowlists =
+ mapOf(
+ ISSUE_CATEGORY_ACCOUNT to setOf(SINGLE_SOURCE_ID, SAMPLE_SOURCE_ID),
+ ISSUE_CATEGORY_DEVICE to setOf(SAMPLE_SOURCE_ID),
+ ISSUE_CATEGORY_GENERAL to setOf(SAMPLE_SOURCE_ID)
+ )
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val dataToSet = safetySourceTestData.recommendationWithAccountIssue
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataToSet)
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData).isEqualTo(dataToSet)
+ }
+
+ @Test
+ fun setSafetySourceData_withEmptyAllowlistForCategory_notMet() {
+ SafetyCenterFlags.issueCategoryAllowlists = mapOf(ISSUE_CATEGORY_ACCOUNT to emptySet())
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.recommendationWithAccountIssue
+ )
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo(
+ "Unexpected issue category: $ISSUE_CATEGORY_ACCOUNT, for issue in safety source: " +
+ SINGLE_SOURCE_ID
+ )
+ }
+
+ @Test
+ fun setSafetySourceData_withoutSourceInAllowlistForCategory_notMet() {
+ SafetyCenterFlags.issueCategoryAllowlists =
+ mapOf(
+ ISSUE_CATEGORY_ACCOUNT to setOf(SAMPLE_SOURCE_ID),
+ ISSUE_CATEGORY_DEVICE to setOf(SINGLE_SOURCE_ID)
+ )
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.recommendationWithAccountIssue
+ )
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo(
+ "Unexpected issue category: $ISSUE_CATEGORY_ACCOUNT, for issue in safety source: " +
+ SINGLE_SOURCE_ID
+ )
+ }
+
+ @Test
+ fun setSafetySourceData_withFlagDisabled_doesntSetData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setEnabled(false)
safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceDataUnspecified, EVENT_SOURCE_STATE_CHANGED)
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.unspecified,
+ EVENT_SOURCE_STATE_CHANGED
+ )
+ safetyCenterTestHelper.setEnabled(true)
val apiSafetySourceData =
- safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isNull()
}
@@ -244,16 +640,72 @@ class SafetyCenterManagerTest {
fun setSafetySourceData_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.setSafetySourceData(
- CTS_SOURCE_ID, safetySourceDataUnspecified, EVENT_SOURCE_STATE_CHANGED)
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.unspecified,
+ EVENT_SOURCE_STATE_CHANGED
+ )
}
}
@Test
fun getSafetySourceData_validId_noData_returnsNull() {
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
val apiSafetySourceData =
- safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+
+ assertThat(apiSafetySourceData).isNull()
+ }
+
+ @Test
+ fun getSafetySourceData_unknownId_throwsIllegalArgumentException() {
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ }
+
+ assertThat(thrown).hasMessageThat().isEqualTo("Unexpected safety source: $SINGLE_SOURCE_ID")
+ }
+
+ @Test
+ fun getSafetySourceData_staticId_throwsIllegalArgumentException() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
+
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterManager.getSafetySourceDataWithPermission(STATIC_BAREBONE_ID)
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo("Unexpected safety source: $STATIC_BAREBONE_ID")
+ }
+
+ @Test
+ fun getSafetySourceData_differentPackage_throwsIllegalArgumentException() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
+
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterManager.getSafetySourceDataWithPermission(DYNAMIC_OTHER_PACKAGE_ID)
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo(
+ "Unexpected package name: ${context.packageName}, for safety source: " +
+ DYNAMIC_OTHER_PACKAGE_ID
+ )
+ }
+
+ @Test
+ fun getSafetySourceData_withFlagDisabled_returnsNull() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.unspecified)
+ safetyCenterTestHelper.setEnabled(false)
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isNull()
}
@@ -261,7 +713,89 @@ class SafetyCenterManagerTest {
@Test
fun getSafetySourceData_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
- safetyCenterManager.getSafetySourceData(CTS_SOURCE_ID)
+ safetyCenterManager.getSafetySourceData(SINGLE_SOURCE_ID)
+ }
+ }
+
+ @Test
+ fun reportSafetySourceError_changesSafetyCenterDataButDoesntCallErrorListener() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.reportSafetySourceErrorWithPermission(
+ SINGLE_SOURCE_ID,
+ SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED)
+ )
+
+ listener.receiveSafetyCenterData()
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterErrorDetails(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun reportSafetySourceError_unknownId_throwsIllegalArgumentException() {
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterManager.reportSafetySourceErrorWithPermission(
+ SINGLE_SOURCE_ID,
+ SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED)
+ )
+ }
+
+ assertThat(thrown).hasMessageThat().isEqualTo("Unexpected safety source: $SINGLE_SOURCE_ID")
+ }
+
+ @Test
+ fun reportSafetySourceError_staticId_throwsIllegalArgumentException() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
+
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterManager.reportSafetySourceErrorWithPermission(
+ STATIC_BAREBONE_ID,
+ SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED)
+ )
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo("Unexpected safety source: $STATIC_BAREBONE_ID")
+ }
+
+ @Test
+ fun reportSafetySourceError_differentPackage_throwsIllegalArgumentException() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
+
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterManager.reportSafetySourceErrorWithPermission(
+ DYNAMIC_OTHER_PACKAGE_ID,
+ SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED)
+ )
+ }
+
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo(
+ "Unexpected package name: ${context.packageName}, for safety source: " +
+ DYNAMIC_OTHER_PACKAGE_ID
+ )
+ }
+
+ @Test
+ fun reportSafetySourceError_withFlagDisabled_doesntCallListener() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val listener = safetyCenterTestHelper.addListener()
+ safetyCenterTestHelper.setEnabled(false)
+
+ safetyCenterManager.reportSafetySourceErrorWithPermission(
+ SINGLE_SOURCE_ID,
+ SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED)
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterData(TIMEOUT_SHORT)
}
}
@@ -269,77 +803,834 @@ class SafetyCenterManagerTest {
fun reportSafetySourceError_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.reportSafetySourceError(
- CTS_SOURCE_ID, SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED))
+ SINGLE_SOURCE_ID,
+ SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED)
+ )
}
}
@Test
- fun refreshSafetySources_withRefreshReasonRescanButtonClick_sourceSendsRescanData() {
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
- SafetySourceBroadcastReceiver.safetySourceId = CTS_SOURCE_ID
- SafetySourceBroadcastReceiver.safetySourceDataOnRescanClick = safetySourceDataCritical
+ fun safetyCenterEnabledChanged_whenImplicitReceiverHasPermission_receiverCalled() {
+ // Implicit broadcast is only sent to system user.
+ assumeTrue(context.getSystemService(UserManager::class.java)!!.isSystemUser)
+ val enabledChangedReceiver = SafetyCenterEnabledChangedReceiver(context)
+
+ val receiverValue =
+ enabledChangedReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait(false)
+
+ assertThat(receiverValue).isFalse()
+
+ val toggledReceiverValue =
+ enabledChangedReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait(true)
+
+ assertThat(toggledReceiverValue).isTrue()
+ enabledChangedReceiver.unregister()
+ }
+
+ @Test
+ fun safetyCenterEnabledChanged_whenImplicitReceiverDoesntHavePermission_receiverNotCalled() {
+ // Implicit broadcast is only sent to system user.
+ assumeTrue(context.getSystemService(UserManager::class.java)!!.isSystemUser)
+ val enabledChangedReceiver = SafetyCenterEnabledChangedReceiver(context)
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ enabledChangedReceiver.setSafetyCenterEnabledWithoutReceiverPermissionAndWait(
+ false,
+ TIMEOUT_SHORT
+ )
+ }
+ enabledChangedReceiver.unregister()
+ }
+
+ @Test
+ fun safetyCenterEnabledChanged_whenSourceReceiverHasPermission_receiverCalled() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val receiverValue =
+ SafetySourceReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait(false)
+
+ assertThat(receiverValue).isFalse()
+
+ val toggledReceiverValue =
+ SafetySourceReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait(true)
+
+ assertThat(toggledReceiverValue).isTrue()
+ }
+
+ @Test
+ fun safetyCenterEnabledChanged_valueDoesntChange_receiverNotCalled() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ assertFailsWith(TimeoutCancellationException::class) {
+ SafetySourceReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait(
+ true,
+ TIMEOUT_SHORT
+ )
+ }
+ }
+
+ @Test
+ fun safetyCenterEnabledChanged_whenSourceReceiverDoesntHavePermission_receiverNotCalled() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ SafetySourceReceiver.setSafetyCenterEnabledWithoutReceiverPermissionAndWait(
+ false,
+ TIMEOUT_SHORT
+ )
+ }
+ }
+
+ @Test
+ fun safetyCenterEnabledChanged_whenSourceReceiverNotInConfig_receiverNotCalled() {
+ assertFailsWith(TimeoutCancellationException::class) {
+ SafetySourceReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait(
+ false,
+ TIMEOUT_SHORT
+ )
+ }
+ }
+
+ @Test
+ fun refreshSafetySources_withRefreshReasonRescanButtonClick_sourceSendsRescanData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Rescan(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue)
+ )
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
- REFRESH_REASON_RESCAN_BUTTON_CLICK)
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
val apiSafetySourceData =
- safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
- assertThat(apiSafetySourceData).isEqualTo(safetySourceDataCritical)
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData)
+ .isEqualTo(safetySourceTestData.criticalWithResolvingGeneralIssue)
}
@Test
fun refreshSafetySources_withRefreshReasonPageOpen_sourceSendsPageOpenData() {
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
- SafetySourceBroadcastReceiver.safetySourceId = CTS_SOURCE_ID
- SafetySourceBroadcastReceiver.safetySourceDataOnPageOpen = safetySourceDataInformation
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
- REFRESH_REASON_PAGE_OPEN)
+ REFRESH_REASON_PAGE_OPEN
+ )
val apiSafetySourceData =
- safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
- assertThat(apiSafetySourceData).isEqualTo(safetySourceDataInformation)
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData).isEqualTo(safetySourceTestData.information)
}
@Test
- fun refreshSafetySources_whenReceiverDoesNotHaveSendingPermission_sourceDoesNotSendData() {
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
- SafetySourceBroadcastReceiver.safetySourceId = CTS_SOURCE_ID
- SafetySourceBroadcastReceiver.safetySourceDataOnRescanClick = safetySourceDataCritical
+ fun refreshSafetySources_allowsRefreshingInAForegroundService() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.runInForegroundService = true
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
- safetyCenterManager.refreshSafetySourcesWithPermission(REFRESH_REASON_RESCAN_BUTTON_CLICK)
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN
+ )
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData).isEqualTo(safetySourceTestData.information)
+ }
+
+ @Test
+ fun refreshSafetySources_reasonPageOpen_noConditionsMet_noBroadcastSent() {
+ 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) {
- SafetySourceBroadcastReceiver.waitTillOnReceiveComplete(TIMEOUT_SHORT)
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN,
+ TIMEOUT_SHORT
+ )
}
+
val apiSafetySourceData =
- safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
- assertThat(apiSafetySourceData).isNull()
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData).isEqualTo(safetySourceTestData.information)
+ }
+
+ @Test
+ fun refreshSafetySources_reasonPageOpen_allowedByConfig_broadcastSent() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+ 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_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_withFlagDisabled_noOp() {
- SafetyCenterFlags.setSafetyCenterEnabled(false)
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
- SafetySourceBroadcastReceiver.safetySourceId = CTS_SOURCE_ID
- SafetySourceBroadcastReceiver.safetySourceDataOnPageOpen = safetySourceDataInformation
+ 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)
+ 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)
+ SafetySourceReceiver.setResponse(Request.Rescan(SINGLE_SOURCE_ID), Response.ClearData)
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+
val apiSafetySourceData =
- safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isNull()
}
@Test
+ fun refreshSafetySources_withMultipleSourcesInConfig_multipleSourcesSendData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ SafetySourceReceiver.apply {
+ setResponse(
+ Request.Rescan(SOURCE_ID_1),
+ Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue)
+ )
+ setResponse(
+ Request.Rescan(SOURCE_ID_3),
+ Response.SetData(safetySourceTestData.information)
+ )
+ }
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+
+ val apiSafetySourceData1 =
+ safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_1)
+ assertThat(apiSafetySourceData1)
+ .isEqualTo(safetySourceTestData.criticalWithResolvingGeneralIssue)
+ val apiSafetySourceData2 =
+ safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_2)
+ assertThat(apiSafetySourceData2).isNull()
+ val apiSafetySourceData3 =
+ safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_3)
+ assertThat(apiSafetySourceData3).isEqualTo(safetySourceTestData.information)
+ }
+
+ @Test
+ fun refreshSafetySources_withMultipleSourcesOnPageOpen_onlyUpdatesAllowedSources() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ safetyCenterTestHelper.setData(SOURCE_ID_1, safetySourceTestData.information)
+ safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.information)
+ SafetySourceReceiver.apply {
+ setResponse(
+ Request.Refresh(SOURCE_ID_1),
+ Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue)
+ )
+ setResponse(
+ Request.Refresh(SOURCE_ID_3),
+ Response.SetData(safetySourceTestData.informationWithIssue)
+ )
+ }
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN
+ )
+
+ val apiSafetySourceData1 =
+ safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_1)
+ assertThat(apiSafetySourceData1)
+ .isEqualTo(safetySourceTestData.criticalWithResolvingGeneralIssue)
+ val apiSafetySourceData2 =
+ safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_2)
+ assertThat(apiSafetySourceData2).isNull()
+ // SOURCE_ID_3 doesn't support refresh on page open.
+ val apiSafetySourceData3 =
+ safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_3)
+ assertThat(apiSafetySourceData3).isEqualTo(safetySourceTestData.information)
+ }
+
+ @Test
+ fun refreshSafetySources_whenReceiverDoesntHavePermission_sourceDoesntSendData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Rescan(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue)
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ safetyCenterManager.refreshSafetySourcesWithoutReceiverPermissionAndWait(
+ REFRESH_REASON_RESCAN_BUTTON_CLICK,
+ TIMEOUT_SHORT
+ )
+ }
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData).isNull()
+ }
+
+ @Test
+ fun refreshSafetySources_whenSourceNotInConfig_sourceDoesntSendData() {
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN,
+ TIMEOUT_SHORT
+ )
+ }
+ }
+
+ @Test
+ fun refreshSafetySources_sendsBroadcastId() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val lastReceivedBroadcastId =
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+
+ assertThat(lastReceivedBroadcastId).isNotNull()
+ }
+
+ @Test
+ fun refreshSafetySources_sendsDifferentBroadcastIdsOnEachMethodCall() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Rescan(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+
+ val broadcastId1 =
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+ val broadcastId2 =
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+
+ assertThat(broadcastId1).isNotEqualTo(broadcastId2)
+ }
+
+ @Test
+ fun refreshSafetySources_repliesWithWrongBroadcastId_doesntCompleteRefresh() {
+ SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_SHORT)
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Rescan(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information, overrideBroadcastId = "invalid")
+ )
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+
+ // Because wrong ID, refresh hasn't finished. Wait for timeout.
+ listener.receiveSafetyCenterErrorDetails()
+ SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_LONG)
+
+ SafetySourceReceiver.setResponse(
+ Request.Rescan(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_refreshAfterSuccessfulRefresh_completesSuccessfully() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN
+ )
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue)
+ )
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN
+ )
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData)
+ .isEqualTo(safetySourceTestData.criticalWithResolvingGeneralIssue)
+ }
+
+ @Test
+ fun refreshSafetySources_refreshAfterFailedRefresh_completesSuccessfully() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(Request.Rescan(SINGLE_SOURCE_ID), Response.Error)
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+ SafetySourceReceiver.setResponse(
+ Request.Rescan(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData).isEqualTo(safetySourceTestData.information)
+ }
+
+ @Test
+ fun refreshSafetySources_waitForPreviousRefreshToTimeout_completesSuccessfully() {
+ SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_SHORT)
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN
+ )
+ val apiSafetySourceData1 =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData1).isNull()
+ // Wait for the ongoing refresh to timeout.
+ listener.receiveSafetyCenterErrorDetails()
+ SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_LONG)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN
+ )
+ val apiSafetySourceData2 =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData2).isEqualTo(safetySourceTestData.information)
+ }
+
+ @Test
+ fun refreshSafetySources_withoutAllowingPreviousRefreshToTimeout_completesSuccessfully() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN
+ )
+ 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_withTrackedSourceThatTimesOut_timesOut() {
+ SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_SHORT)
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ // SOURCE_ID_1 will timeout
+ for (sourceId in listOf(SOURCE_ID_2, SOURCE_ID_3)) {
+ SafetySourceReceiver.setResponse(
+ Request.Rescan(sourceId),
+ Response.SetData(safetySourceTestData.information)
+ )
+ }
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+
+ val safetyCenterErrorDetailsFromListener = listener.receiveSafetyCenterErrorDetails()
+ assertThat(safetyCenterErrorDetailsFromListener)
+ .isEqualTo(
+ SafetyCenterErrorDetails(
+ safetyCenterResourcesContext.getStringByName("refresh_timeout")
+ )
+ )
+ }
+
+ @Test
+ fun refreshSafetySources_withUntrackedSourceThatTimesOut_doesNotTimeOut() {
+ SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_SHORT)
+ SafetyCenterFlags.untrackedSources = setOf(SOURCE_ID_1)
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ // SOURCE_ID_1 will timeout
+ for (sourceId in listOf(SOURCE_ID_2, SOURCE_ID_3)) {
+ SafetySourceReceiver.setResponse(
+ Request.Rescan(sourceId),
+ Response.SetData(safetySourceTestData.information)
+ )
+ }
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterErrorDetails(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun refreshSafetySources_withMultipleUntrackedSourcesThatTimeOut_doesNotTimeOut() {
+ SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_SHORT)
+ SafetyCenterFlags.untrackedSources = setOf(SOURCE_ID_1, SOURCE_ID_2)
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ // SOURCE_ID_1 and SOURCE_ID_2 will timeout
+ SafetySourceReceiver.setResponse(
+ Request.Rescan(SOURCE_ID_3),
+ Response.SetData(safetySourceTestData.information)
+ )
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterErrorDetails(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun refreshSafetySources_withEmptyUntrackedSourceConfigAndSourceThatTimesOut_timesOut() {
+ SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_SHORT)
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ // SINGLE_SOURCE_ID will timeout
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+
+ val safetyCenterErrorDetailsFromListener = listener.receiveSafetyCenterErrorDetails()
+ assertThat(safetyCenterErrorDetailsFromListener)
+ .isEqualTo(
+ SafetyCenterErrorDetails(
+ safetyCenterResourcesContext.getStringByName("refresh_timeout")
+ )
+ )
+ }
+
+ @Test
+ fun refreshSafetySources_withTrackedSourceThatHasNoReceiver_doesNotTimeOut() {
+ SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_SHORT)
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceOtherPackageConfig)
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.refreshSafetySourcesWithPermission(REFRESH_REASON_RESCAN_BUTTON_CLICK)
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterErrorDetails(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun refreshSafetySources_withFlagDisabled_doesntRefreshSources() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setEnabled(false)
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN,
+ TIMEOUT_SHORT
+ )
+ }
+ }
+
+ @Test
fun refreshSafetySources_withInvalidRefreshSeason_throwsIllegalArgumentException() {
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterManager.refreshSafetySourcesWithPermission(143201)
}
- assertThat(thrown).hasMessageThat().endsWith("refresh reason: 143201")
+
+ assertThat(thrown).hasMessageThat().isEqualTo("Unexpected refresh reason: 143201")
+ }
+
+ @Test
+ fun refreshSafetySources_withRefreshReasonOther_backgroundRefreshDeniedSourcesDoNotSendData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ // All three sources have data
+ SafetySourceReceiver.apply {
+ setResponse(
+ Request.Refresh(SOURCE_ID_1),
+ Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue)
+ )
+ setResponse(
+ Request.Refresh(SOURCE_ID_2),
+ Response.SetData(safetySourceTestData.information)
+ )
+ setResponse(
+ Request.Refresh(SOURCE_ID_3),
+ Response.SetData(safetySourceTestData.information)
+ )
+ }
+ // But sources 1 and 3 should not be refreshed in background
+ SafetyCenterFlags.backgroundRefreshDeniedSources = setOf(SOURCE_ID_1, SOURCE_ID_3)
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(REFRESH_REASON_OTHER)
+
+ val apiSafetySourceData1 =
+ safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_1)
+ assertThat(apiSafetySourceData1).isNull()
+ val apiSafetySourceData2 =
+ safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_2)
+ assertThat(apiSafetySourceData2).isEqualTo(safetySourceTestData.information)
+ val apiSafetySourceData3 =
+ safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_3)
+ assertThat(apiSafetySourceData3).isNull()
+ }
+
+ @Test
+ fun refreshSafetySources_withRefreshReasonPageOpen_noBackgroundRefreshSourceSendsData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue)
+ )
+ SafetyCenterFlags.backgroundRefreshDeniedSources = setOf(SINGLE_SOURCE_ID)
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN
+ )
+
+ val sourceData = safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(sourceData).isEqualTo(safetySourceTestData.criticalWithResolvingGeneralIssue)
+ }
+
+ @Test
+ fun refreshSafetySources_withRefreshReasonButtonClicked_noBackgroundRefreshSourceSendsData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Rescan(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue)
+ )
+ SafetyCenterFlags.backgroundRefreshDeniedSources = setOf(SINGLE_SOURCE_ID)
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+
+ val sourceData = safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(sourceData).isEqualTo(safetySourceTestData.criticalWithResolvingGeneralIssue)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun refreshSafetySources_withRefreshReasonPeriodic_noBackgroundRefreshSourceDoesNotSendData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+ SafetyCenterFlags.backgroundRefreshDeniedSources = setOf(SINGLE_SOURCE_ID)
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PERIODIC,
+ TIMEOUT_SHORT
+ )
+ }
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceData).isNull()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun refreshSafetySources_withRefreshReasonPeriodic_backgroundRefreshSourceSendsData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue)
+ )
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PERIODIC
+ )
+
+ val sourceData = safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(sourceData).isEqualTo(safetySourceTestData.criticalWithResolvingGeneralIssue)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun refreshSafetySources_withSafetySourceIds_onlySpecifiedSourcesSendData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ SafetySourceReceiver.apply {
+ setResponse(
+ Request.Refresh(SOURCE_ID_1),
+ Response.SetData(safetySourceTestData.information)
+ )
+ setResponse(
+ Request.Refresh(SOURCE_ID_2),
+ Response.SetData(safetySourceTestData.information)
+ )
+ setResponse(
+ Request.Refresh(SOURCE_ID_3),
+ Response.SetData(safetySourceTestData.information)
+ )
+ }
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN,
+ safetySourceIds = listOf(SOURCE_ID_1, SOURCE_ID_2)
+ )
+
+ val apiSafetySourceData1 =
+ safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_1)
+ assertThat(apiSafetySourceData1).isEqualTo(safetySourceTestData.information)
+ val apiSafetySourceData2 =
+ safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_2)
+ assertThat(apiSafetySourceData2).isEqualTo(safetySourceTestData.information)
+ val apiSafetySourceData3 =
+ safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_3)
+ assertThat(apiSafetySourceData3).isNull()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun refreshSafetySources_withEmptySafetySourceIds_noSourcesSendData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue)
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN,
+ TIMEOUT_SHORT,
+ emptyList()
+ )
+ }
+
+ val sourceData = safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(sourceData).isNull()
+ }
+
+ @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")
+ 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")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun refreshSafetySources_withSafetySourceIds_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) {
+ safetyCenterManager.refreshSafetySources(REFRESH_REASON_PAGE_OPEN, listOf())
+ }
}
@Test
@@ -350,60 +1641,49 @@ class SafetyCenterManagerTest {
}
@Test
- fun getSafetyCenterConfig_isNotNull() {
+ fun getSafetyCenterConfig_withFlagEnabled_isNotNull() {
val config = safetyCenterManager.getSafetyCenterConfigWithPermission()
- // TODO(b/225152057): Assert on content.
assertThat(config).isNotNull()
}
@Test
- fun getSafetyCenterConfig_withoutPermission_throwsSecurityException() {
- assertFailsWith(SecurityException::class) { safetyCenterManager.safetyCenterConfig }
- }
+ fun getSafetyCenterConfig_withFlagDisabled_isNotNull() {
+ safetyCenterTestHelper.setEnabled(false)
- @Test
- fun getSafetyCenterData_withoutDataProvided_returnsDataFromConfig() {
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
+ val config = safetyCenterManager.getSafetyCenterConfigWithPermission()
- val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+ assertThat(config).isNotNull()
+ }
- // TODO(b/218830137): Assert on content.
- assertThat(apiSafetyCenterData).isNotNull()
+ @Test
+ fun getSafetyCenterConfig_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) { safetyCenterManager.safetyCenterConfig }
}
@Test
- fun getSafetyCenterData_withSomeDataProvided_returnsDataProvided() {
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceDataUnspecified, EVENT_SOURCE_STATE_CHANGED)
+ fun getSafetyCenterData_withoutDataProvided_isNotNull() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
- // TODO(b/218830137): Assert on content.
assertThat(apiSafetyCenterData).isNotNull()
}
@Test
- fun getSafetyCenterData_withUpdatedData_returnsUpdatedData() {
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceDataInformation, EVENT_SOURCE_STATE_CHANGED)
- val previousApiSafetyCenterData =
- safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceDataCritical, EVENT_SOURCE_STATE_CHANGED)
+ fun getSafetyCenterData_withSomeDataProvided_returnsDifferentData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val previousApiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.unspecified)
val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
- // TODO(b/218830137): Assert on content.
assertThat(apiSafetyCenterData).isNotEqualTo(previousApiSafetyCenterData)
}
@Test
- fun getSafetyCenterData_withFlagDisabled_returnsDefaultData() {
- SafetyCenterFlags.setSafetyCenterEnabled(false)
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
+ fun getSafetyCenterData_withFlagDisabled_isNotNull() {
+ safetyCenterTestHelper.setEnabled(false)
val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
@@ -416,82 +1696,63 @@ class SafetyCenterManagerTest {
}
@Test
- fun addOnSafetyCenterDataChangedListener_listenerCalledWithSafetyCenterDataFromConfig() {
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
- safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- directExecutor(), listener)
- val safetyCenterDataFromListener = listener.receiveSafetyCenterData()
+ fun addOnSafetyCenterDataChangedListener_listenerCalledOnInit() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val listener = safetyCenterTestHelper.addListener(skipInitialData = false)
- // TODO(b/218830137): Assert on content.
+ val safetyCenterDataFromListener = listener.receiveSafetyCenterData()
assertThat(safetyCenterDataFromListener).isNotNull()
}
@Test
fun addOnSafetyCenterDataChangedListener_listenerCalledOnSafetySourceData() {
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
- safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- directExecutor(), listener)
- // Receive initial data.
- listener.receiveSafetyCenterData()
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val listener = safetyCenterTestHelper.addListener()
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceDataInformation, EVENT_SOURCE_STATE_CHANGED)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
val safetyCenterDataFromListener = listener.receiveSafetyCenterData()
- // TODO(b/218830137): Assert on content.
assertThat(safetyCenterDataFromListener).isNotNull()
}
@Test
fun addOnSafetyCenterDataChangedListener_listenerCalledWhenSafetySourceDataChanges() {
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
- safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- directExecutor(), listener)
- // Receive initial data.
- listener.receiveSafetyCenterData()
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceDataInformation, EVENT_SOURCE_STATE_CHANGED)
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val listener = safetyCenterTestHelper.addListener()
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
// Receive update from #setSafetySourceData call.
listener.receiveSafetyCenterData()
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceDataCritical, EVENT_SOURCE_STATE_CHANGED)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
val safetyCenterDataFromListener = listener.receiveSafetyCenterData()
- // TODO(b/218830137): Assert on content.
assertThat(safetyCenterDataFromListener).isNotNull()
}
@Test
fun addOnSafetyCenterDataChangedListener_listenerCalledWhenSafetySourceDataCleared() {
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
- safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- directExecutor(), listener)
- // Receive initial data.
- listener.receiveSafetyCenterData()
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceDataInformation, EVENT_SOURCE_STATE_CHANGED)
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val listener = safetyCenterTestHelper.addListener()
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
// Receive update from #setSafetySourceData call.
listener.receiveSafetyCenterData()
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceData = null, EVENT_SOURCE_STATE_CHANGED)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceData = null)
val safetyCenterDataFromListener = listener.receiveSafetyCenterData()
- // TODO(b/218830137): Assert on content.
assertThat(safetyCenterDataFromListener).isNotNull()
}
@Test
fun addOnSafetyCenterDataChangedListener_listenerNotCalledWhenSafetySourceDataStaysNull() {
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
- safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- directExecutor(), listener)
- // Receive initial data.
- listener.receiveSafetyCenterData()
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val listener = safetyCenterTestHelper.addListener()
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceData = null, EVENT_SOURCE_STATE_CHANGED)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceData = null)
assertFailsWith(TimeoutCancellationException::class) {
listener.receiveSafetyCenterData(TIMEOUT_SHORT)
@@ -500,18 +1761,14 @@ class SafetyCenterManagerTest {
@Test
fun addOnSafetyCenterDataChangedListener_listenerNotCalledWhenSafetySourceDataDoesntChange() {
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
- safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- directExecutor(), listener)
- // Receive initial data.
- listener.receiveSafetyCenterData()
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceDataInformation, EVENT_SOURCE_STATE_CHANGED)
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val listener = safetyCenterTestHelper.addListener()
+ val dataToSet = safetySourceTestData.information
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataToSet)
// Receive update from #setSafetySourceData call.
listener.receiveSafetyCenterData()
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceDataInformation, EVENT_SOURCE_STATE_CHANGED)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataToSet)
assertFailsWith(TimeoutCancellationException::class) {
listener.receiveSafetyCenterData(TIMEOUT_SHORT)
@@ -519,12 +1776,36 @@ class SafetyCenterManagerTest {
}
@Test
+ fun addOnSafetyCenterDataChangedListener_oneShot_doesntDeadlock() {
+ val listener = SafetyCenterTestListener()
+ val oneShotListener =
+ object : OnSafetyCenterDataChangedListener {
+ override fun onSafetyCenterDataChanged(safetyCenterData: SafetyCenterData) {
+ safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(this)
+ listener.onSafetyCenterDataChanged(safetyCenterData)
+ }
+ }
+ safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
+ directExecutor(),
+ oneShotListener
+ )
+
+ // Check that we don't deadlock when using a one-shot listener. This is because adding the
+ // listener could call it while holding a lock; which would cause a deadlock if the listener
+ // wasn't oneway.
+ listener.receiveSafetyCenterData()
+ }
+
+ @Test
fun addOnSafetyCenterDataChangedListener_withFlagDisabled_listenerNotCalled() {
- SafetyCenterFlags.setSafetyCenterEnabled(false)
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setEnabled(false)
+ val listener = SafetyCenterTestListener()
safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- directExecutor(), listener)
+ directExecutor(),
+ listener
+ )
assertFailsWith(TimeoutCancellationException::class) {
listener.receiveSafetyCenterData(TIMEOUT_SHORT)
@@ -533,65 +1814,41 @@ class SafetyCenterManagerTest {
@Test
fun addOnSafetyCenterDataChangedListener_withoutPermission_throwsSecurityException() {
+ val listener = SafetyCenterTestListener()
+
assertFailsWith(SecurityException::class) {
safetyCenterManager.addOnSafetyCenterDataChangedListener(directExecutor(), listener)
}
}
@Test
- // Permission is held for the entire test to avoid a racy scenario where the shell identity is
- // dropped while it's being acquired on another thread.
- fun addOnSafetyCenterDataChangedListener_oneShot_doesntDeadlock() {
- callWithShellPermissionIdentity(
- {
- val oneShotListener =
- object : OnSafetyCenterDataChangedListener {
- override fun onSafetyCenterDataChanged(safetyCenterData: SafetyCenterData) {
- safetyCenterManager.removeOnSafetyCenterDataChangedListener(this)
- listener.onSafetyCenterDataChanged(safetyCenterData)
- }
- }
- safetyCenterManager.addOnSafetyCenterDataChangedListener(
- directExecutor(), oneShotListener)
-
- // Check that we don't deadlock when using a one-shot listener: this is because
- // adding the listener could call the listener while holding a lock on the binder
- // thread-pool; causing a deadlock when attempting to call the `SafetyCenterManager`
- // from that listener.
- listener.receiveSafetyCenterData()
- },
- MANAGE_SAFETY_CENTER)
- }
-
- @Test
- fun removeOnSafetyCenterDataChangedListener_listenerNotCalledOnSafetySourceData() {
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
- safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- directExecutor(), listener)
- // Receive initial data.
- listener.receiveSafetyCenterData()
+ fun removeOnSafetyCenterDataChangedListener_listenerRemovedNotCalledOnSafetySourceData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val listener1 = safetyCenterTestHelper.addListener()
+ val listener2 = safetyCenterTestHelper.addListener()
- safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(listener)
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceDataInformation, EVENT_SOURCE_STATE_CHANGED)
+ safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(listener2)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+ listener1.receiveSafetyCenterData()
assertFailsWith(TimeoutCancellationException::class) {
- listener.receiveSafetyCenterData(TIMEOUT_SHORT)
+ listener2.receiveSafetyCenterData(TIMEOUT_SHORT)
}
}
@Test
fun removeOnSafetyCenterDataChangedListener_listenerNeverCalledAfterRemoving() {
- safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(CTS_CONFIG)
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
val fakeExecutor = FakeExecutor()
+ val listener = SafetyCenterTestListener()
safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- fakeExecutor, listener)
- // Receive initial data.
+ fakeExecutor,
+ listener
+ )
fakeExecutor.getNextTask().run()
listener.receiveSafetyCenterData()
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID, safetySourceDataInformation, EVENT_SOURCE_STATE_CHANGED)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
val callListenerTask = fakeExecutor.getNextTask()
safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(listener)
// Simulate the submitted task being run *after* the remove call completes. Our API should
@@ -605,9 +1862,24 @@ class SafetyCenterManagerTest {
}
@Test
+ fun removeOnSafetyCenterDataChangedListener_withFlagDisabled_removesListener() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val listener = safetyCenterTestHelper.addListener()
+ safetyCenterTestHelper.setEnabled(false)
+
+ safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(listener)
+
+ safetyCenterTestHelper.setEnabled(true)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+ // Listener is removed as a side effect of the ENABLED_CHANGED broadcast.
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterData(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
fun removeOnSafetyCenterDataChangedListener_withoutPermission_throwsSecurityException() {
- safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- directExecutor(), listener)
+ val listener = safetyCenterTestHelper.addListener()
assertFailsWith(SecurityException::class) {
safetyCenterManager.removeOnSafetyCenterDataChangedListener(listener)
@@ -615,6 +1887,136 @@ class SafetyCenterManagerTest {
}
@Test
+ fun dismissSafetyCenterIssue_withDismissPendingIntent_callsDismissPendingIntent() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.recommendationDismissPendingIntentIssue
+ )
+ val apiSafetySourceDataBeforeDismissal =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ checkState(
+ apiSafetySourceDataBeforeDismissal ==
+ safetySourceTestData.recommendationDismissPendingIntentIssue
+ )
+ SafetySourceReceiver.setResponse(
+ Request.DismissIssue(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+
+ safetyCenterManager.dismissSafetyCenterIssueWithPermissionAndWait(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, RECOMMENDATION_ISSUE_ID)
+ )
+
+ val apiSafetySourceDataAfterDismissal =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceDataAfterDismissal).isEqualTo(safetySourceTestData.information)
+ }
+
+ @Test
+ fun dismissSafetyCenterIssue_nonExisting_doesntCallListenerOrDismiss() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, "some_unknown_id")
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterData(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun dismissSafetyCenterIssue_alreadyDismissed_doesntCallListenerOrDismiss() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID)
+ )
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID)
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterData(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun dismissSafetyCenterIssue_dismissedWithDifferentIssueType_doesntCallListenerOrDismiss() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID)
+ )
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ issueTypeId = "some_other_issue_type_id"
+ )
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterData(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun dismissSafetyCenterIssue_withFlagDisabled_doesntCallListenerOrDismiss() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ val listener = safetyCenterTestHelper.addListener()
+ safetyCenterTestHelper.setEnabled(false)
+
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID)
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterData(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun dismissSafetyCenterIssue_invalidId_throwsIllegalArgumentException() {
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission("bleh")
+ }
+ }
+
+ @Test
+ fun dismissSafetyCenterIssue_invalidUser_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) {
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ userId = USER_NULL
+ )
+ )
+ }
+ }
+
+ @Test
fun dismissSafetyCenterIssue_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.dismissSafetyCenterIssue("bleh")
@@ -622,6 +2024,304 @@ class SafetyCenterManagerTest {
}
@Test
+ fun executeSafetyCenterIssueAction_existing_executes() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ val apiSafetySourceDataBeforeExecution =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ checkState(
+ apiSafetySourceDataBeforeExecution ==
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ SafetySourceReceiver.setResponse(
+ Request.ResolveAction(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID
+ )
+ )
+
+ val apiSafetySourceDataAfterExecution =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceDataAfterExecution).isEqualTo(safetySourceTestData.information)
+ }
+
+ @Test
+ fun executeSafetyCenterIssueAction_existing_errorWithDispatchingRedirectingAction() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val criticalWithRedirectingIssue = safetySourceTestData.criticalWithRedirectingIssue
+ criticalWithRedirectingIssue.issues.first().actions.first().pendingIntent.cancel()
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, criticalWithRedirectingIssue)
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID
+ )
+ )
+
+ val error = listener.receiveSafetyCenterErrorDetails()
+ assertThat(error)
+ .isEqualTo(
+ SafetyCenterErrorDetails(
+ safetyCenterResourcesContext.getStringByName("redirecting_error")
+ )
+ )
+ }
+
+ @Test
+ fun executeSafetyCenterIssueAction_existing_errorWithDispatchingResolvingAction() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val criticalWithResolvingIssue = safetySourceTestData.criticalWithResolvingGeneralIssue
+ criticalWithResolvingIssue.issues.first().actions.first().pendingIntent.cancel()
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, criticalWithResolvingIssue)
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID
+ )
+ )
+
+ val error = listener.receiveSafetyCenterErrorDetails()
+ assertThat(error)
+ .isEqualTo(
+ SafetyCenterErrorDetails(
+ safetyCenterResourcesContext.getStringByName("resolving_action_error")
+ )
+ )
+ }
+
+ @Test
+ // This test runs the default no-op implementation of OnSafetyCenterDataChangedListener#onError
+ // for code coverage purposes.
+ fun executeSafetyCenterIssueAction_errorWithDispatchingOnDefaultErrorListener() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val criticalWithRedirectingIssue = safetySourceTestData.criticalWithRedirectingIssue
+ criticalWithRedirectingIssue.issues.first().actions.first().pendingIntent.cancel()
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, criticalWithRedirectingIssue)
+ val fakeExecutor = FakeExecutor()
+ val listener =
+ object : OnSafetyCenterDataChangedListener {
+ override fun onSafetyCenterDataChanged(safetyCenterData: SafetyCenterData) {}
+ }
+ safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
+ fakeExecutor,
+ listener
+ )
+ fakeExecutor.getNextTask().run()
+
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID
+ )
+ )
+ fakeExecutor.getNextTask().run()
+
+ safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(listener)
+ }
+
+ @Test
+ fun executeSafetyCenterIssueAction_nonExisting_doesntCallListenerOrExecute() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+ val listener = safetyCenterTestHelper.addListener()
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID
+ ),
+ TIMEOUT_SHORT
+ )
+ }
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterData(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun executeSafetyCenterIssueAction_alreadyInFlight_doesntCallListenerOrExecute() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ val listener = safetyCenterTestHelper.addListener()
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID
+ )
+ )
+ listener.receiveSafetyCenterData()
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID
+ ),
+ TIMEOUT_SHORT
+ )
+ }
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterData(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun executeSafetyCenterIssueAction_withFlagDisabled_doesntCallListenerOrExecute() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ val listener = safetyCenterTestHelper.addListener()
+ safetyCenterTestHelper.setEnabled(false)
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID
+ ),
+ TIMEOUT_SHORT
+ )
+ }
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterData(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun executeSafetyCenterIssueAction_invalidId_throwsIllegalArgumentException() {
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermission("barf", "burgh")
+ }
+ }
+
+ @Test
+ fun executeSafetyCenterIssueAction_issueIdDoesNotMatch_throwsErrorAndDoesNotResolveIssue() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ val listener = safetyCenterTestHelper.addListener()
+ SafetySourceReceiver.setResponse(
+ Request.ResolveAction(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID + "invalid",
+ CRITICAL_ISSUE_ACTION_ID
+ ),
+ TIMEOUT_SHORT
+ )
+ }
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterData(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun executeSafetyCenterIssueAction_actionIdDoesNotMatch_doesNotResolveIssue() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ val listener = safetyCenterTestHelper.addListener()
+ SafetySourceReceiver.setResponse(
+ Request.ResolveAction(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID + "invalid"
+ ),
+ TIMEOUT_SHORT
+ )
+ }
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterData(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun executeSafetyCenterIssueAction_sourceIdsDontMatch_throwsIllegalArgumentException() {
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SOURCE_ID_1,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID
+ )
+ )
+ }
+ }
+
+ @Test
+ fun executeSafetyCenterIssueAction_invalidUser_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) {
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermission(
+ SafetyCenterTestData.issueId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ userId = USER_NULL
+ ),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID,
+ userId = USER_NULL
+ )
+ )
+ }
+ }
+
+ @Test
fun executeSafetyCenterIssueAction_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.executeSafetyCenterIssueAction("bleh", "blah")
@@ -629,6 +2329,41 @@ class SafetyCenterManagerTest {
}
@Test
+ fun clearAllSafetySourceDataForTests_clearsAllSafetySourceData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ safetyCenterTestHelper.setData(SOURCE_ID_1, safetySourceTestData.unspecified)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+
+ safetyCenterManager.clearAllSafetySourceDataForTestsWithPermission()
+
+ val data1AfterClearing = safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_1)
+ assertThat(data1AfterClearing).isNull()
+ val data2AfterClearing = safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_2)
+ assertThat(data2AfterClearing).isNull()
+ }
+
+ @Test
+ fun clearAllSafetySourceDataForTests_withFlagDisabled_clearsData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ safetyCenterTestHelper.setEnabled(false)
+
+ safetyCenterManager.clearAllSafetySourceDataForTestsWithPermission()
+
+ safetyCenterTestHelper.setEnabled(true)
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ // Data is cleared as a side effect of the ENABLED_CHANGED broadcast.
+ assertThat(apiSafetySourceData).isNull()
+ }
+
+ @Test
fun clearAllSafetySourceDataForTests_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.clearAllSafetySourceDataForTests()
@@ -636,59 +2371,62 @@ class SafetyCenterManagerTest {
}
@Test
+ fun setSafetyCenterConfigForTests_setsConfig() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val config = safetyCenterManager.getSafetyCenterConfigWithPermission()
+ assertThat(config).isEqualTo(safetyCenterTestConfigs.singleSourceConfig)
+ }
+
+ @Test
+ fun setSafetyCenterConfigForTests_withFlagDisabled_doesntSetConfig() {
+ safetyCenterTestHelper.setEnabled(false)
+
+ safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(
+ safetyCenterTestConfigs.singleSourceConfig
+ )
+
+ safetyCenterTestHelper.setEnabled(true)
+ val config = safetyCenterManager.getSafetyCenterConfigWithPermission()
+ assertThat(config).isNotEqualTo(safetyCenterTestConfigs.singleSourceConfig)
+ }
+
+ @Test
fun setSafetyCenterConfigForTests_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
- safetyCenterManager.setSafetyCenterConfigForTests(CTS_CONFIG)
+ safetyCenterManager.setSafetyCenterConfigForTests(
+ safetyCenterTestConfigs.singleSourceConfig
+ )
}
}
@Test
+ fun clearSafetyCenterConfigForTests_clearsConfigSetForTests_doesntSetConfigToNull() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ safetyCenterManager.clearSafetyCenterConfigForTestsWithPermission()
+
+ val config = safetyCenterManager.getSafetyCenterConfigWithPermission()
+ assertThat(config).isNotNull()
+ assertThat(config).isNotEqualTo(safetyCenterTestConfigs.singleSourceConfig)
+ }
+
+ @Test
+ fun clearSafetyCenterConfigForTests_withFlagDisabled_doesntClearConfig() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setEnabled(false)
+
+ safetyCenterManager.clearSafetyCenterConfigForTestsWithPermission()
+
+ safetyCenterTestHelper.setEnabled(true)
+ val config = safetyCenterManager.getSafetyCenterConfigWithPermission()
+ assertThat(config).isEqualTo(safetyCenterTestConfigs.singleSourceConfig)
+ }
+
+ @Test
fun clearSafetyCenterConfigForTests_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.clearSafetyCenterConfigForTests()
}
}
-
- private fun SafetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
- refreshReason: Int,
- timeout: Duration = TIMEOUT_LONG
- ) {
- callWithShellPermissionIdentity(
- {
- refreshSafetySources(refreshReason)
- SafetySourceBroadcastReceiver.waitTillOnReceiveComplete(timeout)
- },
- SEND_SAFETY_CENTER_UPDATE,
- MANAGE_SAFETY_CENTER)
- }
-
- companion object {
- private const val CTS_PACKAGE_NAME = "android.safetycenter.cts"
- private val EVENT_SOURCE_STATE_CHANGED =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
- private const val CTS_SOURCE_ID = "cts_source_id"
- private const val CTS_SOURCE_GROUP_ID = "cts_source_group"
-
- // TODO(b/217944317): Consider moving the following to a file where they can be used by
- // other tests.
- private val CTS_SOURCE =
- SafetySource.Builder(SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(CTS_SOURCE_ID)
- .setPackageName(CTS_PACKAGE_NAME)
- .setTitleResId(android.R.string.ok)
- .setSummaryResId(android.R.string.ok)
- .setIntentAction(ACTION_SAFETY_CENTER)
- .setProfile(SafetySource.PROFILE_PRIMARY)
- .setRefreshOnPageOpenAllowed(true)
- .build()
- private val CTS_SOURCE_GROUP =
- SafetySourcesGroup.Builder()
- .setId(CTS_SOURCE_GROUP_ID)
- .setTitleResId(android.R.string.ok)
- .setSummaryResId(android.R.string.ok)
- .addSafetySource(CTS_SOURCE)
- .build()
- private val CTS_CONFIG =
- SafetyCenterConfig.Builder().addSafetySourcesGroup(CTS_SOURCE_GROUP).build()
- }
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterShellCommandsTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterShellCommandsTest.kt
new file mode 100644
index 000000000..b0860d751
--- /dev/null
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterShellCommandsTest.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.safetycenter.cts
+
+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.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** CTS tests for Safety Center's shell commands. */
+@RunWith(AndroidJUnit4::class)
+class SafetyCenterShellCommandsTest {
+ private val context: Context = getApplicationContext()
+
+ @Test
+ fun enabled_printsEnabledValue() {
+ val enabled = executeShellCommand("cmd safety_center enabled").toBoolean()
+
+ val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
+ assertThat(enabled).isEqualTo(safetyCenterManager.isSafetyCenterEnabledWithPermission())
+ }
+
+ @Test
+ fun supported_printsSupportedValue() {
+ val supported = executeShellCommand("cmd safety_center supported").toBoolean()
+
+ assertThat(supported).isEqualTo(context.deviceSupportsSafetyCenter())
+ }
+
+ @Test
+ fun packageName_printsPackageName() {
+ val packageName = executeShellCommand("cmd safety_center package-name")
+
+ assertThat(packageName).isEqualTo(context.packageManager.permissionControllerPackageName)
+ }
+
+ private fun executeShellCommand(command: String): String =
+ SystemUtil.runShellCommand(command).trim()
+}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryGroupTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryGroupTest.kt
index 2bce8a200..71be3d5eb 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryGroupTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryGroupTest.kt
@@ -19,28 +19,28 @@ package android.safetycenter.cts
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
-import android.os.Build.VERSION_CODES.TIRAMISU
import android.safetycenter.SafetyCenterStaticEntry
import android.safetycenter.SafetyCenterStaticEntryGroup
-import android.safetycenter.cts.testing.EqualsHashCodeToStringTester
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
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.assertFailsWith
import org.junit.Test
import org.junit.runner.RunWith
+/** CTS tests for [SafetyCenterStaticEntryGroup]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class SafetyCenterStaticEntryGroupTest {
private val context: Context = ApplicationProvider.getApplicationContext()
private val pendingIntent1 =
- PendingIntent.getActivity(context, 0, Intent("Fake Data"), PendingIntent.FLAG_IMMUTABLE)
+ PendingIntent.getActivity(context, 0, Intent("Fake Data 1"), PendingIntent.FLAG_IMMUTABLE)
private val pendingIntent2 =
- PendingIntent.getActivity(
- context, 0, Intent("Fake Different Data"), PendingIntent.FLAG_IMMUTABLE)
+ PendingIntent.getActivity(context, 0, Intent("Fake Data 2"), PendingIntent.FLAG_IMMUTABLE)
+ private val pendingIntent3 =
+ PendingIntent.getActivity(context, 0, Intent("Fake Data 3"), PendingIntent.FLAG_IMMUTABLE)
private val staticEntry1 =
SafetyCenterStaticEntry.Builder("an entry title")
@@ -52,6 +52,11 @@ class SafetyCenterStaticEntryGroupTest {
.setSummary("another entry summary")
.setPendingIntent(pendingIntent2)
.build()
+ private val staticEntry3 =
+ SafetyCenterStaticEntry.Builder("yet another entry title")
+ .setSummary("yet another entry summary")
+ .setPendingIntent(pendingIntent3)
+ .build()
private val staticEntryGroup =
SafetyCenterStaticEntryGroup("a title", listOf(staticEntry1, staticEntry2))
@@ -68,13 +73,21 @@ class SafetyCenterStaticEntryGroupTest {
assertThat(SafetyCenterStaticEntryGroup("", listOf(staticEntry1)).staticEntries)
.containsExactly(staticEntry1)
assertThat(
- SafetyCenterStaticEntryGroup("", listOf(staticEntry1, staticEntry2)).staticEntries)
+ SafetyCenterStaticEntryGroup("", listOf(staticEntry1, staticEntry2)).staticEntries
+ )
.containsExactly(staticEntry1, staticEntry2)
.inOrder()
assertThat(SafetyCenterStaticEntryGroup("", listOf()).staticEntries).isEmpty()
}
@Test
+ fun getStaticEntries_mutationsAreNotAllowed() {
+ val staticEntries = staticEntryGroup.staticEntries
+
+ assertFailsWith(UnsupportedOperationException::class) { staticEntries.add(staticEntry3) }
+ }
+
+ @Test
fun describeContents_returns0() {
assertThat(staticEntryGroup.describeContents()).isEqualTo(0)
}
@@ -86,15 +99,20 @@ class SafetyCenterStaticEntryGroupTest {
@Test
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetyCenterStaticEntryGroup.CREATOR
+ )
.addEqualityGroup(
staticEntryGroup,
- SafetyCenterStaticEntryGroup("a title", listOf(staticEntry1, staticEntry2)))
+ SafetyCenterStaticEntryGroup("a title", listOf(staticEntry1, staticEntry2))
+ )
.addEqualityGroup(
SafetyCenterStaticEntryGroup("a title", listOf(staticEntry1)),
- SafetyCenterStaticEntryGroup("a title", listOf(staticEntry1)))
+ SafetyCenterStaticEntryGroup("a title", listOf(staticEntry1))
+ )
.addEqualityGroup(
- SafetyCenterStaticEntryGroup("a different title", listOf(staticEntry1)))
+ SafetyCenterStaticEntryGroup("a different title", listOf(staticEntry1))
+ )
.addEqualityGroup(SafetyCenterStaticEntryGroup("a title", listOf(staticEntry2)))
.test()
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryTest.kt
index 868838163..045a50f75 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryTest.kt
@@ -19,19 +19,17 @@ package android.safetycenter.cts
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
-import android.os.Build.VERSION_CODES.TIRAMISU
import android.safetycenter.SafetyCenterStaticEntry
-import android.safetycenter.cts.testing.EqualsHashCodeToStringTester
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
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 org.junit.Test
import org.junit.runner.RunWith
+/** CTS tests for [SafetyCenterStaticEntry]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class SafetyCenterStaticEntryTest {
private val context: Context = ApplicationProvider.getApplicationContext()
@@ -39,7 +37,11 @@ class SafetyCenterStaticEntryTest {
PendingIntent.getActivity(context, 0, Intent("Fake Data"), PendingIntent.FLAG_IMMUTABLE)
private val pendingIntent2 =
PendingIntent.getActivity(
- context, 0, Intent("Fake Different Data"), PendingIntent.FLAG_IMMUTABLE)
+ context,
+ 0,
+ Intent("Fake Different Data"),
+ PendingIntent.FLAG_IMMUTABLE
+ )
private val title1 = "a title"
private val title2 = "another title"
@@ -63,6 +65,8 @@ class SafetyCenterStaticEntryTest {
fun getTitle_returnsTitle() {
assertThat(staticEntry1.title).isEqualTo(title1)
assertThat(staticEntry2.title).isEqualTo(title2)
+ assertThat(SafetyCenterStaticEntry.Builder(staticEntry1).setTitle(title2).build().title)
+ .isEqualTo(title2)
}
@Test
@@ -95,14 +99,17 @@ class SafetyCenterStaticEntryTest {
@Test
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetyCenterStaticEntry.CREATOR,
+ createCopy = { SafetyCenterStaticEntry.Builder(it).build() }
+ )
.addEqualityGroup(
staticEntry1,
SafetyCenterStaticEntry.Builder("a title")
.setSummary("a summary")
.setPendingIntent(pendingIntent1)
- .build(),
- SafetyCenterStaticEntry.Builder(staticEntry1).build())
+ .build()
+ )
.addEqualityGroup(staticEntry2)
.addEqualityGroup(staticEntryMinimal, SafetyCenterStaticEntry.Builder("").build())
.addEqualityGroup(
@@ -113,22 +120,21 @@ class SafetyCenterStaticEntryTest {
SafetyCenterStaticEntry.Builder("titlee")
.setSummary("sumaree")
.setPendingIntent(pendingIntent1)
- .build())
+ .build()
+ )
.addEqualityGroup(
- SafetyCenterStaticEntry.Builder("a different title")
- .setSummary("a summary")
- .setPendingIntent(pendingIntent1)
- .build())
+ SafetyCenterStaticEntry.Builder(staticEntry1).setTitle("a different title").build()
+ )
.addEqualityGroup(
- SafetyCenterStaticEntry.Builder("a title")
+ SafetyCenterStaticEntry.Builder(staticEntry1)
.setSummary("a different summary")
- .setPendingIntent(pendingIntent1)
- .build())
+ .build()
+ )
.addEqualityGroup(
- SafetyCenterStaticEntry.Builder("a title")
- .setSummary("a summary")
+ SafetyCenterStaticEntry.Builder(staticEntry1)
.setPendingIntent(pendingIntent2)
- .build())
+ .build()
+ )
.test()
}
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStatusTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStatusTest.kt
index 2f20e8477..4df4e5d35 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStatusTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStatusTest.kt
@@ -16,19 +16,17 @@
package android.safetycenter.cts
-import android.os.Build.VERSION_CODES.TIRAMISU
import android.safetycenter.SafetyCenterStatus
-import android.safetycenter.cts.testing.EqualsHashCodeToStringTester
import androidx.test.ext.junit.runners.AndroidJUnit4
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.assertFailsWith
import org.junit.Test
import org.junit.runner.RunWith
+/** CTS tests for [SafetyCenterStatus]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class SafetyCenterStatusTest {
private val baseStatus =
@@ -55,7 +53,8 @@ class SafetyCenterStatusTest {
SafetyCenterStatus.Builder(baseStatus)
.setSummary("different summary")
.build()
- .summary)
+ .summary
+ )
.isEqualTo("different summary")
}
@@ -65,14 +64,16 @@ class SafetyCenterStatusTest {
SafetyCenterStatus.Builder(baseStatus)
.setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK)
.build()
- .severityLevel)
+ .severityLevel
+ )
.isEqualTo(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK)
assertThat(
SafetyCenterStatus.Builder(baseStatus)
.setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
.build()
- .severityLevel)
+ .severityLevel
+ )
.isEqualTo(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
}
@@ -82,7 +83,8 @@ class SafetyCenterStatusTest {
SafetyCenterStatus.Builder("This is my title", "This is my summary")
.setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN)
.build()
- .severityLevel)
+ .severityLevel
+ )
.isEqualTo(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN)
}
@@ -92,14 +94,16 @@ class SafetyCenterStatusTest {
SafetyCenterStatus.Builder(baseStatus)
.setRefreshStatus(SafetyCenterStatus.REFRESH_STATUS_NONE)
.build()
- .refreshStatus)
+ .refreshStatus
+ )
.isEqualTo(SafetyCenterStatus.REFRESH_STATUS_NONE)
assertThat(
SafetyCenterStatus.Builder(baseStatus)
.setRefreshStatus(SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS)
.build()
- .refreshStatus)
+ .refreshStatus
+ )
.isEqualTo(SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS)
}
@@ -109,7 +113,8 @@ class SafetyCenterStatusTest {
SafetyCenterStatus.Builder("This is my title", "This is my summary")
.setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN)
.build()
- .refreshStatus)
+ .refreshStatus
+ )
.isEqualTo(SafetyCenterStatus.REFRESH_STATUS_NONE)
}
@@ -149,33 +154,42 @@ class SafetyCenterStatusTest {
@Test
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetyCenterStatus.CREATOR,
+ createCopy = { SafetyCenterStatus.Builder(it).build() }
+ )
.addEqualityGroup(
baseStatus,
SafetyCenterStatus.Builder("This is my title", "This is my summary")
.setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION)
.setRefreshStatus(SafetyCenterStatus.REFRESH_STATUS_DATA_FETCH_IN_PROGRESS)
.build(),
- SafetyCenterStatus.Builder(baseStatus).build())
+ SafetyCenterStatus.Builder(baseStatus).build()
+ )
.addEqualityGroup(
SafetyCenterStatus.Builder("same title", "same summary")
.setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK)
.build(),
SafetyCenterStatus.Builder("same title", "same summary")
.setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK)
- .build())
+ .build()
+ )
.addEqualityGroup(
- SafetyCenterStatus.Builder(baseStatus).setTitle("that's not it").build())
+ SafetyCenterStatus.Builder(baseStatus).setTitle("that's not it").build()
+ )
.addEqualityGroup(
- SafetyCenterStatus.Builder(baseStatus).setSummary("that's not it").build())
+ SafetyCenterStatus.Builder(baseStatus).setSummary("that's not it").build()
+ )
.addEqualityGroup(
SafetyCenterStatus.Builder(baseStatus)
.setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetyCenterStatus.Builder(baseStatus)
.setRefreshStatus(SafetyCenterStatus.REFRESH_STATUS_NONE)
- .build())
+ .build()
+ )
.test()
}
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt
index 542dc1466..695265059 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt
@@ -17,48 +17,104 @@
package android.safetycenter.cts
import android.content.Context
-import android.content.Intent
-import android.content.Intent.ACTION_SAFETY_CENTER
-import android.os.Build.VERSION_CODES.TIRAMISU
+import android.os.UserManager
import android.safetycenter.SafetyCenterManager
-import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.isSafetyCenterEnabledWithPermission
-import android.safetycenter.cts.testing.SafetyCenterFlags
-import android.safetycenter.cts.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
-import android.safetycenter.cts.testing.SettingsPackage.getSettingsPackageName
-import android.support.test.uiautomator.By
+import android.safetycenter.SafetyCenterManager.REFRESH_REASON_PAGE_OPEN
+import android.safetycenter.SafetyCenterManager.REFRESH_REASON_RESCAN_BUTTON_CLICK
+import android.safetycenter.SafetySourceErrorDetails
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.UiAutomatorUtils.waitFindObject
+import androidx.test.uiautomator.By
+import com.android.compatibility.common.util.DisableAnimationRule
+import com.android.compatibility.common.util.FreezeRotationRule
+import com.android.safetycenter.testing.Coroutines.TIMEOUT_SHORT
+import com.android.safetycenter.testing.SafetyCenterActivityLauncher.launchSafetyCenterActivity
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.addOnSafetyCenterDataChangedListenerWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.clearAllSafetySourceDataForTestsWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.clearSafetyCenterConfigForTestsWithPermission
+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.isSafetyCenterEnabledWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.removeOnSafetyCenterDataChangedListenerWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.reportSafetySourceErrorWithPermission
+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.SafetySourceReceiver
+import com.android.safetycenter.testing.SafetySourceReceiver.Companion.executeSafetyCenterIssueActionWithPermissionAndWait
+import com.android.safetycenter.testing.SafetySourceReceiver.Companion.refreshSafetySourcesWithReceiverPermissionAndWait
+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 com.android.safetycenter.testing.SafetySourceTestData.Companion.EVENT_SOURCE_STATE_CHANGED
+import com.android.safetycenter.testing.SettingsPackage.getSettingsPackageName
+import com.android.safetycenter.testing.UiTestHelper.waitDisplayed
import com.google.common.truth.Truth.assertThat
-import org.junit.Assume.assumeFalse
+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
+/** CTS tests for our APIs and UI on devices that do not support Safety Center. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class SafetyCenterUnsupportedTest {
+
+ @get:Rule val disableAnimationRule = DisableAnimationRule()
+
+ @get:Rule val freezeRotationRule = FreezeRotationRule()
+
private val context: Context = getApplicationContext()
- private val packageManager = context.packageManager
+ 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() {
- assumeFalse(context.deviceSupportsSafetyCenter())
+ assumeTrue(shouldRunTests)
+ }
+
+ @Before
+ fun enableSafetyCenterBeforeTest() {
+ if (!shouldRunTests) {
+ return
+ }
+ safetyCenterTestHelper.setup()
+ }
+
+ @After
+ fun clearDataAfterTest() {
+ if (!shouldRunTests) {
+ return
+ }
+ safetyCenterTestHelper.reset()
}
@Test
fun launchActivity_opensSettings() {
- startSafetyCenterActivity()
-
- waitFindObject(By.pkg(context.getSettingsPackageName()))
+ context.launchSafetyCenterActivity {
+ waitDisplayed(By.pkg(context.getSettingsPackageName()))
+ }
}
@Test
fun isSafetyCenterEnabled_withFlagEnabled_returnsFalse() {
- SafetyCenterFlags.setSafetyCenterEnabled(true)
-
val isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabledWithPermission()
assertThat(isSafetyCenterEnabled).isFalse()
@@ -66,17 +122,349 @@ class SafetyCenterUnsupportedTest {
@Test
fun isSafetyCenterEnabled_withFlagDisabled_returnsFalse() {
- SafetyCenterFlags.setSafetyCenterEnabled(false)
+ safetyCenterTestHelper.setEnabled(false)
val isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabledWithPermission()
assertThat(isSafetyCenterEnabled).isFalse()
}
- private fun startSafetyCenterActivity() {
- context.startActivity(
- Intent(ACTION_SAFETY_CENTER)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
+ @Test
+ fun isSafetyCenterEnabled_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) { safetyCenterManager.isSafetyCenterEnabled }
+ }
+
+ @Test
+ fun setAndGetSafetySourceData_doesntSetData() {
+ safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(
+ safetyCenterTestConfigs.singleSourceConfig
+ )
+ safetyCenterManager.setSafetySourceDataWithPermission(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue,
+ EVENT_SOURCE_STATE_CHANGED
+ )
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+
+ assertThat(apiSafetySourceData).isNull()
+ }
+
+ @Test
+ fun setSafetySourceData_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) {
+ safetyCenterManager.setSafetySourceData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.unspecified,
+ EVENT_SOURCE_STATE_CHANGED
+ )
+ }
+ }
+
+ @Test
+ fun getSafetySourceData_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) {
+ safetyCenterManager.getSafetySourceData(SINGLE_SOURCE_ID)
+ }
+ }
+
+ @Test
+ fun reportSafetySourceError_doesntCallListener() {
+ safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(
+ safetyCenterTestConfigs.singleSourceConfig
+ )
+ val listener = SafetyCenterTestListener()
+ safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
+ directExecutor(),
+ listener
+ )
+
+ safetyCenterManager.reportSafetySourceErrorWithPermission(
+ SINGLE_SOURCE_ID,
+ SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED)
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterData(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun reportSafetySourceError_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) {
+ safetyCenterManager.reportSafetySourceError(
+ SINGLE_SOURCE_ID,
+ SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED)
+ )
+ }
+ }
+
+ @Test
+ fun safetyCenterEnabledChanged_withImplicitReceiver_doesntCallReceiver() {
+ // Implicit broadcast is only sent to system user.
+ assumeTrue(context.getSystemService(UserManager::class.java)!!.isSystemUser)
+ val enabledChangedReceiver = SafetyCenterEnabledChangedReceiver(context)
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ enabledChangedReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait(
+ false,
+ TIMEOUT_SHORT
+ )
+ }
+ enabledChangedReceiver.unregister()
+ }
+
+ @Test
+ fun safetyCenterEnabledChanged_withSourceReceiver_doesntCallReceiver() {
+ safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(
+ safetyCenterTestConfigs.singleSourceConfig
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ SafetySourceReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait(
+ false,
+ TIMEOUT_SHORT
+ )
+ }
+ }
+
+ @Test
+ fun refreshSafetySources_doesntRefreshSources() {
+ safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(
+ safetyCenterTestConfigs.singleSourceConfig
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN,
+ TIMEOUT_SHORT
+ )
+ }
+ }
+
+ @Test
+ fun refreshSafetySources_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) {
+ safetyCenterManager.refreshSafetySources(REFRESH_REASON_RESCAN_BUTTON_CLICK)
+ }
+ }
+
+ @Test
+ fun getSafetyCenterConfig_isNull() {
+ val config = safetyCenterManager.getSafetyCenterConfigWithPermission()
+
+ assertThat(config).isNull()
+ }
+
+ @Test
+ fun getSafetyCenterConfig_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) { safetyCenterManager.safetyCenterConfig }
+ }
+
+ @Test
+ fun getSafetyCenterData_returnsDefaultData() {
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData).isEqualTo(SafetyCenterTestData.DEFAULT)
+ }
+
+ @Test
+ fun getSafetyCenterData_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) { safetyCenterManager.safetyCenterData }
+ }
+
+ @Test
+ fun addOnSafetyCenterDataChangedListener_listenerNotCalled() {
+ safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(
+ safetyCenterTestConfigs.singleSourceConfig
+ )
+ val listener = SafetyCenterTestListener()
+
+ safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
+ directExecutor(),
+ listener
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterData(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun addOnSafetyCenterDataChangedListener_withoutPermission_throwsSecurityException() {
+ val listener = SafetyCenterTestListener()
+
+ assertFailsWith(SecurityException::class) {
+ safetyCenterManager.addOnSafetyCenterDataChangedListener(directExecutor(), listener)
+ }
+ }
+
+ @Test
+ fun removeOnSafetyCenterDataChangedListener_listenerNotCalled() {
+ safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(
+ safetyCenterTestConfigs.singleSourceConfig
+ )
+ val listener = SafetyCenterTestListener()
+ safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
+ directExecutor(),
+ listener
+ )
+
+ safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(listener)
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterData(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun removeOnSafetyCenterDataChangedListener_withoutPermission_throwsSecurityException() {
+ val listener = SafetyCenterTestListener()
+ safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
+ directExecutor(),
+ listener
+ )
+
+ assertFailsWith(SecurityException::class) {
+ safetyCenterManager.removeOnSafetyCenterDataChangedListener(listener)
+ }
+ }
+
+ @Test
+ fun dismissSafetyCenterIssue_doesntCallListenerOrDismiss() {
+ safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(
+ safetyCenterTestConfigs.singleSourceConfig
+ )
+ safetyCenterManager.setSafetySourceDataWithPermission(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue,
+ EVENT_SOURCE_STATE_CHANGED
+ )
+ val listener = SafetyCenterTestListener()
+ safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
+ directExecutor(),
+ listener
+ )
+
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID)
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterData(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun dismissSafetyCenterIssue_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) {
+ safetyCenterManager.dismissSafetyCenterIssue("bleh")
+ }
+ }
+
+ @Test
+ fun executeSafetyCenterIssueAction_doesntCallListenerOrExecute() {
+ safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(
+ safetyCenterTestConfigs.singleSourceConfig
+ )
+ safetyCenterManager.setSafetySourceDataWithPermission(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue,
+ EVENT_SOURCE_STATE_CHANGED
+ )
+ val listener = SafetyCenterTestListener()
+ safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
+ directExecutor(),
+ listener
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID
+ ),
+ TIMEOUT_SHORT
+ )
+ }
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterData(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun executeSafetyCenterIssueAction_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) {
+ safetyCenterManager.executeSafetyCenterIssueAction("bleh", "blah")
+ }
+ }
+
+ @Test
+ fun clearAllSafetySourceDataForTests_doesntClearData() {
+ safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(
+ safetyCenterTestConfigs.singleSourceConfig
+ )
+ safetyCenterManager.setSafetySourceDataWithPermission(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue,
+ EVENT_SOURCE_STATE_CHANGED
+ )
+ val apiSafetySourceDataBeforeClearing =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+
+ safetyCenterManager.clearAllSafetySourceDataForTestsWithPermission()
+
+ val apiSafetySourceDataAfterClearing =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceDataAfterClearing).isEqualTo(apiSafetySourceDataBeforeClearing)
+ }
+
+ @Test
+ fun clearAllSafetySourceDataForTests_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) {
+ safetyCenterManager.clearAllSafetySourceDataForTests()
+ }
+ }
+
+ @Test
+ fun setSafetyCenterConfigForTests_doesntSetConfig() {
+ safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(
+ safetyCenterTestConfigs.singleSourceConfig
+ )
+
+ val config = safetyCenterManager.getSafetyCenterConfigWithPermission()
+ assertThat(config).isNull()
+ }
+
+ @Test
+ fun setSafetyCenterConfigForTests_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) {
+ safetyCenterManager.setSafetyCenterConfigForTests(
+ safetyCenterTestConfigs.singleSourceConfig
+ )
+ }
+ }
+
+ @Test
+ fun clearSafetyCenterConfigForTests_doesntClearConfig() {
+ safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(
+ safetyCenterTestConfigs.singleSourceConfig
+ )
+ val configBeforeClearing = safetyCenterManager.getSafetyCenterConfigWithPermission()
+
+ safetyCenterManager.clearSafetyCenterConfigForTestsWithPermission()
+
+ val configAfterClearing = safetyCenterManager.getSafetyCenterConfigWithPermission()
+ assertThat(configAfterClearing).isEqualTo(configBeforeClearing)
+ }
+
+ @Test
+ fun clearSafetyCenterConfigForTests_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) {
+ safetyCenterManager.clearSafetyCenterConfigForTests()
+ }
}
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt
index 15d8b8a6f..3dec4f509 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt
@@ -24,10 +24,10 @@ import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED
import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED
import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED
import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
-import android.safetycenter.cts.testing.EqualsHashCodeToStringTester
import androidx.test.ext.junit.runners.AndroidJUnit4
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.assertFailsWith
import org.junit.Test
@@ -35,7 +35,6 @@ import org.junit.runner.RunWith
/** CTS tests for [SafetyEvent]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
class SafetyEventTest {
@Test
fun getType_returnsType() {
@@ -87,7 +86,10 @@ class SafetyEventTest {
assertThat(exception)
.hasMessageThat()
- .startsWith("Missing issue action id for resolving action safety event")
+ .isEqualTo(
+ "Missing issue action id for resolving action safety event: " +
+ SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED
+ )
}
@Test
@@ -101,7 +103,10 @@ class SafetyEventTest {
assertThat(exception)
.hasMessageThat()
- .startsWith("Missing issue id for resolving action safety event")
+ .isEqualTo(
+ "Missing issue id for resolving action safety event: " +
+ SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED
+ )
}
@Test
@@ -115,7 +120,10 @@ class SafetyEventTest {
assertThat(exception)
.hasMessageThat()
- .startsWith("Missing issue action id for resolving action safety event")
+ .isEqualTo(
+ "Missing issue action id for resolving action safety event: " +
+ SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED
+ )
}
@Test
@@ -129,7 +137,10 @@ class SafetyEventTest {
assertThat(exception)
.hasMessageThat()
- .startsWith("Missing issue id for resolving action safety event")
+ .isEqualTo(
+ "Missing issue id for resolving action safety event: " +
+ SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED
+ )
}
@Test
@@ -175,7 +186,25 @@ class SafetyEventTest {
@Test
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
+ newTiramisuEqualsHashCodeToStringTester().test()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun equalsHashCodeToString_usingEqualsHashCodeToStringTester_atLeastAndroidU() {
+ newTiramisuEqualsHashCodeToStringTester(
+ createCopyFromBuilder = { SafetyEvent.Builder(it).build() }
+ )
+ .test()
+ }
+
+ private fun newTiramisuEqualsHashCodeToStringTester(
+ createCopyFromBuilder: ((SafetyEvent) -> SafetyEvent)? = null
+ ) =
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetyEvent.CREATOR,
+ createCopy = createCopyFromBuilder
+ )
.addEqualityGroup(SafetyEvent.Builder(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build())
.addEqualityGroup(
SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
@@ -183,7 +212,8 @@ class SafetyEventTest {
.build(),
SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
.setRefreshBroadcastId(REFRESH_BROADCAST_ID)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED)
.setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
@@ -192,7 +222,8 @@ class SafetyEventTest {
SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED)
.setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
.setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
.setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
@@ -201,35 +232,39 @@ class SafetyEventTest {
SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
.setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
.setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build())
+ .build()
+ )
.addEqualityGroup(SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build())
.addEqualityGroup(SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED).build())
.addEqualityGroup(
SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
.setRefreshBroadcastId(OTHER_REFRESH_BROADCAST_ID)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED)
.setSafetySourceIssueId(OTHER_SAFETY_SOURCE_ISSUE_ID)
.setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED)
.setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
.setSafetySourceIssueActionId(OTHER_SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
.setSafetySourceIssueId(OTHER_SAFETY_SOURCE_ISSUE_ID)
.setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
.setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
.setSafetySourceIssueActionId(OTHER_SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build())
- .test()
- }
+ .build()
+ )
companion object {
private const val REFRESH_BROADCAST_ID = "refresh_broadcast_id"
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceDataTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceDataTest.kt
index 278ae5ee2..d7208c098 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceDataTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceDataTest.kt
@@ -20,7 +20,8 @@ import android.app.PendingIntent
import android.app.PendingIntent.FLAG_IMMUTABLE
import android.content.Context
import android.content.Intent
-import android.os.Build.VERSION_CODES.TIRAMISU
+import android.os.Build
+import android.os.Bundle
import android.safetycenter.SafetySourceData
import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING
import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_INFORMATION
@@ -28,11 +29,13 @@ import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION
import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED
import android.safetycenter.SafetySourceIssue
import android.safetycenter.SafetySourceStatus
-import android.safetycenter.cts.testing.EqualsHashCodeToStringTester
+import androidx.core.os.bundleOf
import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.core.os.Parcelables.forceParcel
import androidx.test.ext.junit.runners.AndroidJUnit4
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.assertFailsWith
import org.junit.Test
@@ -40,7 +43,6 @@ import org.junit.runner.RunWith
/** CTS tests for [SafetySourceData]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class SafetySourceDataTest {
private val context: Context = getApplicationContext()
@@ -79,6 +81,71 @@ class SafetySourceDataTest {
}
@Test
+ fun getIssues_mutationsAreNotAllowed() {
+ val data =
+ SafetySourceData.Builder()
+ .setStatus(createStatus(SEVERITY_LEVEL_CRITICAL_WARNING))
+ .addIssue(createIssue(SEVERITY_LEVEL_CRITICAL_WARNING, 0))
+ .addIssue(createIssue(SEVERITY_LEVEL_RECOMMENDATION, 1))
+ .build()
+ val mutatedIssues = data.issues
+
+ assertFailsWith(UnsupportedOperationException::class) {
+ mutatedIssues.add(createIssue(SEVERITY_LEVEL_INFORMATION, 2))
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getExtras_withDefaultBuilder_returnsEmptyBundle() {
+ val safetySourceData =
+ SafetySourceData.Builder().setStatus(createStatus(SEVERITY_LEVEL_INFORMATION)).build()
+
+ assertThat(safetySourceData.extras.keySet()).isEmpty()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getExtras_whenSetExplicitly_returnsExtras() {
+ val safetySourceData =
+ SafetySourceData.Builder()
+ .setStatus(createStatus(SEVERITY_LEVEL_INFORMATION))
+ .setExtras(bundleOf(EXTRA_KEY to EXTRA_VALUE))
+ .build()
+
+ assertThat(safetySourceData.extras.keySet()).containsExactly(EXTRA_KEY)
+ assertThat(safetySourceData.extras.getString(EXTRA_KEY, "")).isEqualTo(EXTRA_VALUE)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getExtras_whenCleared_returnsEmptyBundle() {
+ val safetySourceData =
+ SafetySourceData.Builder()
+ .setStatus(createStatus(SEVERITY_LEVEL_INFORMATION))
+ .setExtras(bundleOf(EXTRA_KEY to EXTRA_VALUE))
+ .clearExtras()
+ .build()
+
+ assertThat(safetySourceData.extras.keySet()).isEmpty()
+ }
+
+ @Test
+ fun builder_addIssue_doesNotMutatePreviouslyBuiltInstance() {
+ val firstIssue = createIssue(SEVERITY_LEVEL_INFORMATION, 1)
+ val secondIssue = createIssue(SEVERITY_LEVEL_INFORMATION, 2)
+ val safetySourceDataBuilder =
+ SafetySourceData.Builder()
+ .setStatus(createStatus(SEVERITY_LEVEL_INFORMATION))
+ .addIssue(firstIssue)
+ val issues = safetySourceDataBuilder.build().issues
+
+ safetySourceDataBuilder.addIssue(secondIssue)
+
+ assertThat(issues).containsExactly(firstIssue)
+ }
+
+ @Test
fun clearIssues_removesAllIssues() {
val firstIssue = createIssue(SEVERITY_LEVEL_INFORMATION, 1)
val secondIssue = createIssue(SEVERITY_LEVEL_INFORMATION, 2)
@@ -158,16 +225,6 @@ class SafetySourceDataTest {
}
@Test
- fun build_withInformationStatusAndRecommendationIssues_throwsIllegalArgumentException() {
- val builder =
- SafetySourceData.Builder()
- .setStatus(createStatus(SEVERITY_LEVEL_INFORMATION))
- .addIssue(createIssue(SEVERITY_LEVEL_RECOMMENDATION))
-
- assertFailsWith(IllegalArgumentException::class) { builder.build() }
- }
-
- @Test
fun build_withRecommendationStatusAndNoIssues_doesNotThrow() {
val builder =
SafetySourceData.Builder().setStatus(createStatus(SEVERITY_LEVEL_RECOMMENDATION))
@@ -196,13 +253,55 @@ class SafetySourceDataTest {
}
@Test
+ fun build_withUnspecifiedStatusAndRecommendationIssues_throwsIllegalArgumentException() {
+ val builder =
+ SafetySourceData.Builder()
+ .setStatus(createStatus(SEVERITY_LEVEL_UNSPECIFIED))
+ .addIssue(createIssue(SEVERITY_LEVEL_RECOMMENDATION))
+
+ val exception = assertFailsWith(IllegalArgumentException::class) { builder.build() }
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo("Safety source data cannot have issues that are more severe than its status")
+ }
+
+ @Test
+ fun build_withInformationStatusAndRecommendationIssues_throwsIllegalArgumentException() {
+ val builder =
+ SafetySourceData.Builder()
+ .setStatus(createStatus(SEVERITY_LEVEL_INFORMATION))
+ .addIssue(createIssue(SEVERITY_LEVEL_RECOMMENDATION))
+
+ val exception = assertFailsWith(IllegalArgumentException::class) { builder.build() }
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo("Safety source data cannot have issues that are more severe than its status")
+ }
+
+ @Test
fun build_withRecommendationStatusAndCriticalIssues_throwsIllegalArgumentException() {
val builder =
SafetySourceData.Builder()
.setStatus(createStatus(SEVERITY_LEVEL_RECOMMENDATION))
.addIssue(createIssue(SEVERITY_LEVEL_CRITICAL_WARNING))
- assertFailsWith(IllegalArgumentException::class) { builder.build() }
+ val exception = assertFailsWith(IllegalArgumentException::class) { builder.build() }
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo("Safety source data cannot have issues that are more severe than its status")
+ }
+
+ @Test
+ fun build_duplicateIssueIds_throwsIllegalArgumentException() {
+ val builder =
+ SafetySourceData.Builder()
+ .addIssue(createIssue(SEVERITY_LEVEL_RECOMMENDATION, id = 0))
+ .addIssue(createIssue(SEVERITY_LEVEL_CRITICAL_WARNING, id = 0))
+
+ val exception = assertFailsWith(IllegalArgumentException::class) { builder.build() }
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo("Safety source data cannot have duplicate issue ids")
}
@Test
@@ -226,18 +325,37 @@ class SafetySourceDataTest {
}
@Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun parcelRoundTrip_withExtras_recreatesEqual() {
+ val safetySourceData =
+ SafetySourceData.Builder()
+ .setStatus(createStatus(SEVERITY_LEVEL_RECOMMENDATION))
+ .addIssue(createIssue(SEVERITY_LEVEL_RECOMMENDATION, 1))
+ .addIssue(createIssue(SEVERITY_LEVEL_INFORMATION, 2))
+ .setExtras(bundleOf(EXTRA_KEY to EXTRA_VALUE))
+ .build()
+ val recreatedSafetySourceData = forceParcel(safetySourceData, SafetySourceData.CREATOR)
+
+ assertThat(recreatedSafetySourceData).isEqualTo(safetySourceData)
+ assertThat(recreatedSafetySourceData.extras.keySet()).containsExactly(EXTRA_KEY)
+ assertThat(recreatedSafetySourceData.extras.getString(EXTRA_KEY, "")).isEqualTo(EXTRA_VALUE)
+ }
+
+ @Test
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
val firstStatus = createStatus(SEVERITY_LEVEL_INFORMATION, 1)
val secondStatus = createStatus(SEVERITY_LEVEL_INFORMATION, 2)
val firstIssue = createIssue(SEVERITY_LEVEL_INFORMATION, 1)
val secondIssue = createIssue(SEVERITY_LEVEL_INFORMATION, 2)
- EqualsHashCodeToStringTester()
+ EqualsHashCodeToStringTester.ofParcelable(parcelableCreator = SafetySourceData.CREATOR)
.addEqualityGroup(
SafetySourceData.Builder().setStatus(firstStatus).build(),
- SafetySourceData.Builder().setStatus(firstStatus).build())
+ SafetySourceData.Builder().setStatus(firstStatus).build()
+ )
.addEqualityGroup(
SafetySourceData.Builder().addIssue(firstIssue).addIssue(secondIssue).build(),
- SafetySourceData.Builder().addIssue(firstIssue).addIssue(secondIssue).build())
+ SafetySourceData.Builder().addIssue(firstIssue).addIssue(secondIssue).build()
+ )
.addEqualityGroup(
SafetySourceData.Builder()
.setStatus(firstStatus)
@@ -248,20 +366,118 @@ class SafetySourceDataTest {
.setStatus(firstStatus)
.addIssue(firstIssue)
.addIssue(secondIssue)
- .build())
+ .build()
+ )
.addEqualityGroup(SafetySourceData.Builder().setStatus(secondStatus).build())
.addEqualityGroup(
- SafetySourceData.Builder().addIssue(secondIssue).addIssue(firstIssue).build())
+ SafetySourceData.Builder().addIssue(secondIssue).addIssue(firstIssue).build()
+ )
.addEqualityGroup(SafetySourceData.Builder().addIssue(firstIssue).build())
.addEqualityGroup(
SafetySourceData.Builder()
.setStatus(secondStatus)
.addIssue(firstIssue)
.addIssue(secondIssue)
- .build())
+ .build()
+ )
.test()
}
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun equalsHashCode_atLeastU_usingEqualsHashCodeToStringTester() {
+ val firstStatus = createStatus(SEVERITY_LEVEL_INFORMATION, 1)
+ val secondStatus = createStatus(SEVERITY_LEVEL_INFORMATION, 2)
+ val firstIssue = createIssue(SEVERITY_LEVEL_INFORMATION, 1)
+ val secondIssue = createIssue(SEVERITY_LEVEL_INFORMATION, 2)
+ val filledExtras = bundleOf(EXTRA_KEY to EXTRA_VALUE)
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetySourceData.CREATOR,
+ ignoreToString = true,
+ createCopy = { SafetySourceData.Builder(it).build() }
+ )
+ .addEqualityGroup(
+ SafetySourceData.Builder().setStatus(firstStatus).build(),
+ SafetySourceData.Builder().setStatus(firstStatus).setExtras(filledExtras).build()
+ )
+ .addEqualityGroup(
+ SafetySourceData.Builder().addIssue(firstIssue).addIssue(secondIssue).build(),
+ SafetySourceData.Builder()
+ .addIssue(firstIssue)
+ .addIssue(secondIssue)
+ .setExtras(filledExtras)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetySourceData.Builder()
+ .setStatus(firstStatus)
+ .addIssue(firstIssue)
+ .addIssue(secondIssue)
+ .build(),
+ SafetySourceData.Builder()
+ .setStatus(firstStatus)
+ .addIssue(firstIssue)
+ .addIssue(secondIssue)
+ .setExtras(filledExtras)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetySourceData.Builder().setStatus(secondStatus).build(),
+ SafetySourceData.Builder().setStatus(secondStatus).setExtras(filledExtras).build()
+ )
+ .addEqualityGroup(
+ SafetySourceData.Builder().addIssue(secondIssue).addIssue(firstIssue).build(),
+ SafetySourceData.Builder()
+ .addIssue(secondIssue)
+ .addIssue(firstIssue)
+ .setExtras(filledExtras)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetySourceData.Builder().addIssue(firstIssue).build(),
+ SafetySourceData.Builder().addIssue(firstIssue).setExtras(filledExtras).build()
+ )
+ .addEqualityGroup(
+ SafetySourceData.Builder()
+ .setStatus(secondStatus)
+ .addIssue(firstIssue)
+ .addIssue(secondIssue)
+ .build(),
+ SafetySourceData.Builder()
+ .setStatus(secondStatus)
+ .addIssue(firstIssue)
+ .addIssue(secondIssue)
+ .setExtras(filledExtras)
+ .build()
+ )
+ .test()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun toString_withExtras_containsHasExtras() {
+ val safetySourceDataWithExtras =
+ SafetySourceData.Builder()
+ .setStatus(createStatus(SEVERITY_LEVEL_INFORMATION))
+ .setExtras(bundleOf(EXTRA_KEY to EXTRA_VALUE))
+ .build()
+
+ val stringRepresentation = safetySourceDataWithExtras.toString()
+
+ assertThat(stringRepresentation).contains("(has extras)")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun toString_withoutExtras_doesNotContainHasExtras() {
+ val safetySourceDataWithoutExtras =
+ SafetySourceData.Builder().setStatus(createStatus(SEVERITY_LEVEL_INFORMATION)).build()
+
+ val stringRepresentation = safetySourceDataWithoutExtras.toString()
+
+ assertThat(stringRepresentation).doesNotContain("(has extras)")
+ }
+
private fun createStatus(severityLevel: Int, id: Int = 0) =
SafetySourceStatus.Builder("Status title $id", "Status summary $id", severityLevel)
.setPendingIntent(
@@ -269,7 +485,9 @@ class SafetySourceDataTest {
context,
/* requestCode = */ 0,
Intent("Status PendingIntent $id"),
- FLAG_IMMUTABLE))
+ FLAG_IMMUTABLE
+ )
+ )
.build()
private fun createIssue(severityLevel: Int, id: Int = 0) =
@@ -278,7 +496,8 @@ class SafetySourceDataTest {
"Issue summary $id",
"Issue summary $id",
severityLevel,
- "Issue type id $id")
+ "Issue type id $id"
+ )
.addAction(
SafetySourceIssue.Action.Builder(
"Action id $id",
@@ -287,7 +506,18 @@ class SafetySourceDataTest {
context,
/* requestCode = */ 0,
Intent("Issue PendingIntent $id"),
- FLAG_IMMUTABLE))
- .build())
+ FLAG_IMMUTABLE
+ )
+ )
+ .build()
+ )
.build()
+
+ private companion object {
+ /** Key of extra data in [Bundle]. */
+ const val EXTRA_KEY = "extra_key"
+
+ /** Value of extra data in [Bundle]. */
+ const val EXTRA_VALUE = "extra_value"
+ }
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceErrorDetailsTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceErrorDetailsTest.kt
index c68da332e..336462491 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceErrorDetailsTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceErrorDetailsTest.kt
@@ -16,20 +16,17 @@
package android.safetycenter.cts
-import android.os.Build
import android.safetycenter.SafetyEvent
import android.safetycenter.SafetySourceErrorDetails
-import android.safetycenter.cts.testing.EqualsHashCodeToStringTester
import androidx.test.ext.junit.runners.AndroidJUnit4
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 org.junit.Test
import org.junit.runner.RunWith
/** CTS tests for [SafetySourceErrorDetails]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
class SafetySourceErrorDetailsTest {
@Test
fun getSafetyEvent_returnsSafetyEvent() {
@@ -47,15 +44,20 @@ class SafetySourceErrorDetailsTest {
@Test
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetySourceErrorDetails.CREATOR
+ )
.addEqualityGroup(
SafetySourceErrorDetails(SAFETY_EVENT),
SafetySourceErrorDetails(
- SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED)
- .build()))
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
+ )
+ )
.addEqualityGroup(
SafetySourceErrorDetails(
- SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build()))
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build()
+ )
+ )
.test()
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceIssueTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceIssueTest.kt
index 328a96f86..4749c3616 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceIssueTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceIssueTest.kt
@@ -20,29 +20,35 @@ 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
import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_INFORMATION
import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED
import android.safetycenter.SafetySourceIssue
import android.safetycenter.SafetySourceIssue.Action
+import android.safetycenter.SafetySourceIssue.Action.ConfirmationDialogDetails
import android.safetycenter.SafetySourceIssue.ISSUE_CATEGORY_ACCOUNT
import android.safetycenter.SafetySourceIssue.ISSUE_CATEGORY_DEVICE
import android.safetycenter.SafetySourceIssue.ISSUE_CATEGORY_GENERAL
-import android.safetycenter.cts.testing.EqualsHashCodeToStringTester
+import android.safetycenter.SafetySourceIssue.Notification
import android.safetycenter.cts.testing.Generic
+import androidx.annotation.RequiresApi
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.ext.truth.os.ParcelableSubject.assertThat
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.assertFailsWith
+import org.junit.Assume.assumeFalse
import org.junit.Test
import org.junit.runner.RunWith
/** CTS tests for [SafetySourceIssue]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class SafetySourceIssueTest {
private val context: Context = getApplicationContext()
@@ -80,7 +86,9 @@ class SafetySourceIssueTest {
@Test
fun action_willResolve_whenSetExplicitly_returnsWillResolve() {
val action =
- Action.Builder("action_id", "Action label", pendingIntent1).setWillResolve(true).build()
+ Action.Builder("action_id", "Action label", pendingIntentService)
+ .setWillResolve(true)
+ .build()
assertThat(action.willResolve()).isTrue()
}
@@ -110,6 +118,53 @@ 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")
+ val action = Action.Builder("action_id", "Action label", pendingIntent1).build()
+
+ assertFailsWith(UnsupportedOperationException::class) { 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) {
+ Action.Builder("action_id", "Action label", pendingIntent1)
+ .setConfirmationDialogDetails(
+ ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+ )
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun action_getConfirmationDialogDetails_withDefaultBuilder_returnsNull() {
+ val action = Action.Builder("action_id", "Action label", pendingIntent1).build()
+
+ assertThat(action.confirmationDialogDetails).isNull()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun action_getConfirmationDialogDetails_whenSetExplicitly_returnsConfirmation() {
+ val action =
+ Action.Builder("action_id", "Action label", pendingIntent1)
+ .setConfirmationDialogDetails(
+ ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+ )
+ .build()
+
+ assertThat(action.confirmationDialogDetails)
+ .isEqualTo(ConfirmationDialogDetails("Title", "Text", "Accept", "Deny"))
+ }
+
+ @Test
fun action_build_withNullId_throwsNullPointerException() {
assertFailsWith(NullPointerException::class) {
Action.Builder(Generic.asNull(), "Action label", pendingIntent1)
@@ -131,6 +186,14 @@ class SafetySourceIssueTest {
}
@Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun action_build_withActivityPendingIntentAndWillResolve_throwsIllegalArgumentException() {
+ assertFailsWith(IllegalArgumentException::class) {
+ Action.Builder("action_id", "Action label", pendingIntent1).setWillResolve(true).build()
+ }
+ }
+
+ @Test
fun action_describeContents_returns0() {
val action = Action.Builder("action_id", "Action label", pendingIntent1).build()
@@ -148,37 +211,346 @@ class SafetySourceIssueTest {
}
@Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun action_parcelRoundTrip_recreatesEqual_atLeastAndroidU() {
+ val action =
+ Action.Builder("action_id", "Action label", pendingIntent1)
+ .setConfirmationDialogDetails(
+ ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+ )
+ .build()
+
+ assertThat(action).recreatesEqual(Action.CREATOR)
+ }
+
+ @Test
fun action_equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
+ actionNewTiramisuEqualsHashCodeToStringTester().test()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun action_equalsHashCodeToString_usingEqualsHashCodeToStringTester_atLeastAndroidU() {
+ val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+ actionNewTiramisuEqualsHashCodeToStringTester(
+ createCopyFromBuilder = { Action.Builder(it).build() }
+ )
.addEqualityGroup(
- Action.Builder("action_id", "Action label", pendingIntent1).build(),
- Action.Builder("action_id", "Action label", pendingIntent1).build(),
Action.Builder("action_id", "Action label", pendingIntent1)
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build(),
+ Action.Builder("action_id", "Action label", pendingIntent1)
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build(),
+ Action.Builder("action_id", "Action label", pendingIntent1)
+ .setConfirmationDialogDetails(confirmationDialogDetails)
.setWillResolve(false)
- .build())
+ .build()
+ )
.addEqualityGroup(
Action.Builder("action_id", "Action label", pendingIntent1)
.setSuccessMessage("Action successfully completed")
- .build())
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build()
+ )
.addEqualityGroup(
- Action.Builder("action_id", "Other action label", pendingIntent1).build())
+ Action.Builder("action_id", "Other action label", pendingIntent1)
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build()
+ )
.addEqualityGroup(
- Action.Builder("other_action_id", "Action label", pendingIntent1).build())
+ Action.Builder("other_action_id", "Action label", pendingIntent1)
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build()
+ )
.addEqualityGroup(
- Action.Builder("action_id", "Action label", pendingIntent1)
+ Action.Builder("action_id", "Action label", pendingIntentService)
.setWillResolve(true)
- .build())
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build()
+ )
.addEqualityGroup(
Action.Builder(
"action_id",
"Action label",
PendingIntent.getActivity(
- context, 0, Intent("Other action PendingIntent"), FLAG_IMMUTABLE))
- .build())
+ context,
+ 0,
+ Intent("Other action PendingIntent"),
+ FLAG_IMMUTABLE
+ )
+ )
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build()
+ )
.addEqualityGroup(
Action.Builder("action_id", "Action label", pendingIntent1)
.setSuccessMessage("Other action successfully completed")
- .build())
+ .setConfirmationDialogDetails(confirmationDialogDetails)
+ .build()
+ )
+ .test()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun notification_getTitle_returnsTitle() {
+ val notification = Notification.Builder("Notification title", "Notification text").build()
+
+ assertThat(notification.title).isEqualTo("Notification title")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun notification_getText_returnsText() {
+ val notification = Notification.Builder("Notification title", "Notification text").build()
+
+ assertThat(notification.text).isEqualTo("Notification text")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun notification_getActions_withDefaultBuilder_returnsEmptyList() {
+ val notification = Notification.Builder("", "").build()
+
+ assertThat(notification.actions).isEmpty()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun notification_getActions_returnsActions() {
+ val notification =
+ Notification.Builder("", "").addAction(action1).addAction(action2).build()
+
+ assertThat(notification.actions).containsExactly(action1, action2).inOrder()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun notification_getActions_mutationsAreNotAllowed() {
+ val notification =
+ Notification.Builder("", "").addAction(action1).addAction(action2).build()
+
+ assertFailsWith(UnsupportedOperationException::class) { notification.actions.add(action3) }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun notification_describeContents_returns0() {
+ val notification =
+ Notification.Builder("Notification title", "Notification text")
+ .addAction(action1)
+ .addAction(action2)
+ .build()
+
+ assertThat(notification.describeContents()).isEqualTo(0)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun notification_parcelRoundTrip_recreatesEqual() {
+ val notification =
+ Notification.Builder("Notification title", "Notification text")
+ .addAction(action1)
+ .addAction(action2)
+ .build()
+
+ assertThat(notification).recreatesEqual(Notification.CREATOR)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun notification_builder_withNullTitle_throwsNullPointerException() {
+ assertFailsWith(NullPointerException::class) {
+ Notification.Builder(Generic.asNull(), "Notification text")
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun notification_builder_withNullText_throwsNullPointerException() {
+ assertFailsWith(NullPointerException::class) {
+ Notification.Builder("Notification title", Generic.asNull())
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun notification_builder_addAction_doesNotMutatePreviouslyBuiltInstance() {
+ val notificationBuilder = Notification.Builder("", "").addAction(action1)
+ val actions = notificationBuilder.build().actions
+
+ notificationBuilder.addAction(action2)
+
+ assertThat(actions).containsExactly(action1)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun notification_builder_addAction_withNull_throwsIllegalArgumentException() {
+ assertFailsWith(NullPointerException::class) {
+ Notification.Builder("", "").addAction(Generic.asNull())
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun notification_builder_addActions_keepsPreviouslyAddedActions() {
+ val notificationBuilder = Notification.Builder("", "").addAction(action1)
+
+ notificationBuilder.addActions(listOf(action2))
+
+ assertThat(notificationBuilder.build().actions).containsExactly(action1, action2).inOrder()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun notification_builder_addActions_doesNotMutatePreviouslyBuiltInstance() {
+ val notificationBuilder = Notification.Builder("", "").addActions(listOf(action1))
+ val actions = notificationBuilder.build().actions
+
+ notificationBuilder.addActions(listOf(action2, action3))
+
+ assertThat(actions).containsExactly(action1)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun notification_builder_addActions_withNull_throwsIllegalArgumentException() {
+ assertFailsWith(NullPointerException::class) {
+ Notification.Builder("", "").addActions(Generic.asNull())
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun notification_builder_clearActions_removesAllActions() {
+ val notification =
+ Notification.Builder("", "")
+ .addAction(action1)
+ .addAction(action2)
+ .clearActions()
+ .addAction(action3)
+ .build()
+
+ assertThat(notification.actions).containsExactly(action3)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun notification_build_withDuplicateActionIds_throwsIllegalArgumentException() {
+ val notificationBuilder =
+ Notification.Builder("Notification title", "Notification text")
+ .addAction(action1)
+ .addAction(action1)
+
+ val exception =
+ assertFailsWith(IllegalArgumentException::class) { notificationBuilder.build() }
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo("Custom notification cannot have duplicate action ids")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun notification_build_withMoreThanTwoActions_throwsIllegalArgumentException() {
+ val notificationBuilder =
+ Notification.Builder("Notification title", "Notification text")
+ .addAction(action1)
+ .addAction(action2)
+ .addAction(action3)
+
+ val exception =
+ assertFailsWith(IllegalArgumentException::class) { notificationBuilder.build() }
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo("Custom notification must not contain more than 2 actions")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun notification_equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = Notification.CREATOR,
+ createCopy = { Notification.Builder(it).build() }
+ )
+ .addEqualityGroup(
+ Notification.Builder("Title", "Text").build(),
+ Notification.Builder("Title", "Text").build(),
+ )
+ .addEqualityGroup(Notification.Builder("Other title", "Text").build())
+ .addEqualityGroup(Notification.Builder("Title", "Other text").build())
+ .addEqualityGroup(Notification.Builder("Title", "Text").addAction(action1).build())
+ .addEqualityGroup(Notification.Builder("Title", "Text").addAction(action2).build())
+ .addEqualityGroup(
+ Notification.Builder("Title", "Text").addAction(action1).addAction(action2).build(),
+ Notification.Builder("Title", "Text").addActions(listOf(action1, action2)).build()
+ )
+ .test()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun actionConfirmation_getTitle_returnsTitle() {
+ val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+
+ assertThat(confirmationDialogDetails.title).isEqualTo("Title")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun actionConfirmation_getText_returnsText() {
+ val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+
+ assertThat(confirmationDialogDetails.text).isEqualTo("Text")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun actionConfirmation_getAcceptButtonText_returnsAcceptButtonText() {
+ val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+
+ assertThat(confirmationDialogDetails.acceptButtonText).isEqualTo("Accept")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun actionConfirmation_getDenyButtonText_returnsDenyButtonText() {
+ val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+
+ assertThat(confirmationDialogDetails.denyButtonText).isEqualTo("Deny")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun actionConfirmation_describeContents_returns0() {
+ val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+
+ assertThat(confirmationDialogDetails.describeContents()).isEqualTo(0)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun actionConfirmation_parcelRoundTrip_recreatesEqual() {
+ val confirmationDialogDetails = ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+
+ assertThat(confirmationDialogDetails).recreatesEqual(ConfirmationDialogDetails.CREATOR)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun actionConfirmation_equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = ConfirmationDialogDetails.CREATOR
+ )
+ .addEqualityGroup(
+ ConfirmationDialogDetails("Title", "Text", "Accept", "Deny"),
+ ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+ )
+ .addEqualityGroup(ConfirmationDialogDetails("Other title", "Text", "Accept", "Deny"))
+ .addEqualityGroup(ConfirmationDialogDetails("Title", "Other text", "Accept", "Deny"))
+ .addEqualityGroup(ConfirmationDialogDetails("Title", "Text", "Other accept", "Deny"))
+ .addEqualityGroup(ConfirmationDialogDetails("Title", "Text", "Accept", "Other deny"))
.test()
}
@@ -190,7 +562,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action1)
.build()
@@ -205,7 +578,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action1)
.build()
@@ -220,7 +594,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action1)
.build()
@@ -235,7 +610,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.setSubtitle("Issue subtitle")
.addAction(action1)
.build()
@@ -251,7 +627,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action1)
.build()
@@ -259,6 +636,81 @@ class SafetySourceIssueTest {
}
@Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getAttributionTitle_withNullAttributionTitle_returnsNull() {
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ .build()
+
+ assertThat(safetySourceIssue.attributionTitle).isNull()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getAttributionTitle_returnsAttributionTitle() {
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ .setAttributionTitle("attribution title")
+ .build()
+
+ assertThat(safetySourceIssue.attributionTitle).isEqualTo("attribution title")
+ }
+
+ @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")
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ .build()
+
+ assertFailsWith(UnsupportedOperationException::class) { 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")
+ val safetySourceIssueBuilder =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+
+ assertFailsWith(UnsupportedOperationException::class) {
+ safetySourceIssueBuilder.setAttributionTitle("title")
+ }
+ }
+
+ @Test
fun getSeverityLevel_returnsSeverityLevel() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -266,7 +718,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action1)
.build()
@@ -281,7 +734,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action1)
.build()
@@ -296,7 +750,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action1)
.setIssueCategory(ISSUE_CATEGORY_DEVICE)
.build()
@@ -305,6 +760,25 @@ class SafetySourceIssueTest {
}
@Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getIssueCategory_whenSetExplicitlyWithUValueOnU_returnsIssueCategory() {
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_PASSWORDS)
+ .build()
+
+ assertThat(safetySourceIssue.issueCategory)
+ .isEqualTo(SafetySourceIssue.ISSUE_CATEGORY_PASSWORDS)
+ }
+
+ @Test
fun getActions_returnsActions() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -312,7 +786,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action1)
.addAction(action2)
.build()
@@ -321,6 +796,42 @@ class SafetySourceIssueTest {
}
@Test
+ fun getActions_mutationsAreNotAllowed() {
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ .addAction(action2)
+ .build()
+ val mutatedActions = safetySourceIssue.actions
+
+ assertFailsWith(UnsupportedOperationException::class) { mutatedActions.add(action3) }
+ }
+
+ @Test
+ fun builder_addAction_doesNotMutatePreviouslyBuiltInstance() {
+ val safetySourceIssueBuilder =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ val actions = safetySourceIssueBuilder.build().actions
+
+ safetySourceIssueBuilder.addAction(action2)
+
+ assertThat(actions).containsExactly(action1)
+ }
+
+ @Test
fun clearActions_removesAllActions() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -328,7 +839,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action1)
.addAction(action2)
.clearActions()
@@ -346,7 +858,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action1)
.build()
@@ -361,7 +874,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action1)
.setOnDismissPendingIntent(pendingIntentService)
.build()
@@ -370,6 +884,81 @@ class SafetySourceIssueTest {
}
@Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getDeduplicationId_withDefaultBuilder_returnsNull() {
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ .build()
+
+ assertThat(safetySourceIssue.deduplicationId).isNull()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getDeduplicationId_whenSetExplicitly_returnsDeduplicationId() {
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ .setDeduplicationId("deduplication_id")
+ .build()
+
+ assertThat(safetySourceIssue.deduplicationId).isEqualTo("deduplication_id")
+ }
+
+ @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")
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ .build()
+
+ assertFailsWith(UnsupportedOperationException::class) { 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")
+ val safetySourceIssueBuilder =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+
+ assertFailsWith(UnsupportedOperationException::class) {
+ safetySourceIssueBuilder.setDeduplicationId("id")
+ }
+ }
+
+ @Test
fun getIssueTypeId_returnsIssueTypeId() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -377,7 +966,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action1)
.build()
@@ -385,6 +975,290 @@ class SafetySourceIssueTest {
}
@Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getCustomNotification_withDefaultBuilder_returnsNull() {
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ .build()
+
+ assertThat(safetySourceIssue.customNotification).isNull()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getCustomNotification_whenSetExplicitly_returnsCustomNotification() {
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ .setCustomNotification(
+ Notification.Builder("Notification title", "Notification text")
+ .addAction(action2)
+ .build()
+ )
+ .build()
+
+ assertThat(safetySourceIssue.customNotification)
+ .isEqualTo(
+ Notification.Builder("Notification title", "Notification text")
+ .addAction(action2)
+ .build()
+ )
+ }
+
+ @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")
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ .build()
+
+ assertFailsWith(UnsupportedOperationException::class) {
+ 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")
+ val safetySourceIssueBuilder =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+
+ assertFailsWith(UnsupportedOperationException::class) {
+ safetySourceIssueBuilder.setCustomNotification(null)
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getNotificationBehavior_withDefaultBuilder_returnsUnspecified() {
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ .build()
+
+ assertThat(safetySourceIssue.notificationBehavior)
+ .isEqualTo(SafetySourceIssue.NOTIFICATION_BEHAVIOR_UNSPECIFIED)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getNotificationBehavior_whenSetExplicitly_returnsSpecifiedBehavior() {
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_NEVER)
+ .build()
+
+ assertThat(safetySourceIssue.notificationBehavior)
+ .isEqualTo(SafetySourceIssue.NOTIFICATION_BEHAVIOR_NEVER)
+ }
+
+ @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")
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ .build()
+
+ assertFailsWith(UnsupportedOperationException::class) {
+ safetySourceIssue.notificationBehavior
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun setNotificationBehavior_withInvalidNotificationBehavior_throwsIllegalArgumentException() {
+ val builder =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+
+ val exception =
+ assertFailsWith(IllegalArgumentException::class) { builder.setNotificationBehavior(-1) }
+
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo("Unexpected NotificationBehavior for SafetySourceIssue: -1")
+ }
+
+ @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")
+ val safetySourceIssueBuilder =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+
+ assertFailsWith(UnsupportedOperationException::class) {
+ safetySourceIssueBuilder.setNotificationBehavior(0)
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getIssueActionability_withDefaultBuilder_returnsManual() {
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ .build()
+
+ assertThat(safetySourceIssue.issueActionability)
+ .isEqualTo(SafetySourceIssue.ISSUE_ACTIONABILITY_MANUAL)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getIssueActionability_whenSetExplicitly_returnsValueSet() {
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC)
+ .build()
+
+ assertThat(safetySourceIssue.issueActionability)
+ .isEqualTo(SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC)
+ }
+
+ @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")
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ .build()
+
+ assertFailsWith(UnsupportedOperationException::class) {
+ safetySourceIssue.issueActionability
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun setIssueActionability_withInvalidIssueActionability_throwsIllegalArgumentException() {
+ val builder =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+
+ val exception =
+ assertFailsWith(IllegalArgumentException::class) { builder.setIssueActionability(-1) }
+
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo("Unexpected IssueActionability for SafetySourceIssue: -1")
+ }
+
+ @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")
+ val safetySourceIssueBuilder =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+
+ assertFailsWith(UnsupportedOperationException::class) {
+ safetySourceIssueBuilder.setIssueActionability(0)
+ }
+ }
+
+ @Test
fun build_withNullId_throwsNullPointerException() {
assertFailsWith(NullPointerException::class) {
SafetySourceIssue.Builder(
@@ -392,7 +1266,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
}
}
@@ -404,7 +1279,8 @@ class SafetySourceIssueTest {
Generic.asNull(),
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
}
}
@@ -416,7 +1292,8 @@ class SafetySourceIssueTest {
"Issue title",
Generic.asNull(),
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
}
}
@@ -429,7 +1306,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_UNSPECIFIED,
- "issue_type_id")
+ "issue_type_id"
+ )
}
assertThat(exception)
.hasMessageThat()
@@ -441,7 +1319,12 @@ class SafetySourceIssueTest {
val exception =
assertFailsWith(IllegalArgumentException::class) {
SafetySourceIssue.Builder(
- "Issue id", "Issue title", "Issue summary", -1, "issue_type_id")
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ -1,
+ "issue_type_id"
+ )
}
assertThat(exception)
.hasMessageThat()
@@ -456,7 +1339,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- Generic.asNull())
+ Generic.asNull()
+ )
}
}
@@ -468,15 +1352,42 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
+
val exception =
assertFailsWith(IllegalArgumentException::class) { builder.setIssueCategory(-1) }
+
assertThat(exception)
.hasMessageThat()
.isEqualTo("Unexpected IssueCategory for SafetySourceIssue: -1")
}
@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",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+
+ val exception =
+ assertFailsWith(IllegalArgumentException::class) { builder.setIssueCategory(600) }
+
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo("Unexpected IssueCategory for SafetySourceIssue: 600")
+ }
+
+ @Test
fun build_withInvalidOnDismissPendingIntent_throwsIllegalArgumentException() {
val builder =
SafetySourceIssue.Builder(
@@ -484,7 +1395,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
val exception =
assertFailsWith(IllegalArgumentException::class) {
builder.setOnDismissPendingIntent(
@@ -492,7 +1404,9 @@ class SafetySourceIssueTest {
context,
/* requestCode = */ 0,
Intent("PendingIntent activity"),
- FLAG_IMMUTABLE))
+ FLAG_IMMUTABLE
+ )
+ )
}
assertThat(exception)
.hasMessageThat()
@@ -500,6 +1414,26 @@ class SafetySourceIssueTest {
}
@Test
+ fun build_withDuplicateActionIds_throwsIllegalArgumentException() {
+ val safetySourceIssueBuilder =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .addAction(action1)
+ .addAction(action1)
+
+ val exception =
+ assertFailsWith(IllegalArgumentException::class) { safetySourceIssueBuilder.build() }
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo("Safety source issue cannot have duplicate action ids")
+ }
+
+ @Test
fun build_withNoActions_throwsIllegalArgumentException() {
val safetySourceIssueBuilder =
SafetySourceIssue.Builder(
@@ -507,13 +1441,21 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
val exception =
assertFailsWith(IllegalArgumentException::class) { safetySourceIssueBuilder.build() }
+
assertThat(exception)
.hasMessageThat()
- .isEqualTo("Safety source issue must contain at least 1 action")
+ .isEqualTo(
+ if (SdkLevel.isAtLeastU()) {
+ "Actionable safety source issue must contain at least 1 action"
+ } else {
+ "Safety source issue must contain at least 1 action"
+ }
+ )
}
@Test
@@ -524,7 +1466,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action1)
.addAction(action2)
.addAction(action3)
@@ -537,6 +1480,60 @@ class SafetySourceIssueTest {
}
@Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun build_withNoActionsAndManualActionabilityOnU_throwsIllegalArgumentException() {
+ val safetySourceIssueBuilder =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+
+ val exception =
+ assertFailsWith(IllegalArgumentException::class) { safetySourceIssueBuilder.build() }
+
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo("Actionable safety source issue must contain at least 1 action")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun build_withNoActionsAndTipActionabilityOnU_success() {
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_TIP)
+ .build()
+
+ assertThat(safetySourceIssue.actions).isEmpty()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun build_withNoActionsAndAutomaticActionabilityOnU_success() {
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC)
+ .build()
+
+ assertThat(safetySourceIssue.actions).isEmpty()
+ }
+
+ @Test
fun describeContents_returns0() {
val safetySourceIssue =
SafetySourceIssue.Builder(
@@ -544,7 +1541,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.setSubtitle("Issue subtitle")
.setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
.addAction(action1)
@@ -563,7 +1561,8 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.setSubtitle("Issue subtitle")
.setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
.addAction(action1)
@@ -575,15 +1574,387 @@ class SafetySourceIssueTest {
}
@Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun parcelRoundTrip_recreatesEqual_atLeastAndroidU() {
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setSubtitle("Issue subtitle")
+ .setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
+ .addAction(
+ Action.Builder(action1)
+ .setConfirmationDialogDetails(
+ ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+ )
+ .build()
+ )
+ .addAction(action2)
+ .setOnDismissPendingIntent(pendingIntentService)
+ .build()
+
+ assertThat(safetySourceIssue).recreatesEqual(SafetySourceIssue.CREATOR)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun parcelRoundTrip_recreatesEqual_atLeastUpsideDownCake() {
+ val safetySourceIssue =
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setSubtitle("Issue subtitle")
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DATA)
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_TIP)
+ .addAction(action1)
+ .addAction(action2)
+ .setOnDismissPendingIntent(pendingIntentService)
+ .setCustomNotification(
+ Notification.Builder("Notification title", "Notification text")
+ .addAction(action2)
+ .build()
+ )
+ .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_DELAYED)
+ .setAttributionTitle("attribution title")
+ .setDeduplicationId("deduplication_id")
+ .build()
+
+ assertThat(safetySourceIssue).recreatesEqual(SafetySourceIssue.CREATOR)
+ }
+
+ @Test
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
+ newTiramisuEqualsHashCodeToStringTester().test()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun equalsHashCodeToString_usingEqualsHashCodeToStringTester_atLeastUpsideDownCake() {
+ newUpsideDownCakeEqualsHashCodeToStringTester().test()
+ }
+
+ /**
+ * Creates a new [EqualsHashCodeToStringTester] instance with all the equality groups in the
+ * [newTiramisuEqualsHashCodeToStringTester] plus new equality groups covering all the new
+ * fields added in U.
+ */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ private fun newUpsideDownCakeEqualsHashCodeToStringTester() =
+ newTiramisuEqualsHashCodeToStringTester(
+ createCopyFromBuilder = { SafetySourceIssue.Builder(it).build() }
+ )
+ .addEqualityGroup(
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setSubtitle("Issue subtitle")
+ .setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
+ .addAction(action1)
+ .addAction(action2)
+ .setOnDismissPendingIntent(pendingIntentService)
+ .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_DELAYED)
+ .setCustomNotification(
+ Notification.Builder("Notification title", "Notification text")
+ .addAction(action2)
+ .build()
+ )
+ .build()
+ )
+ .addEqualityGroup(
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setSubtitle("Issue subtitle")
+ .setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
+ .addAction(action1)
+ .addAction(action2)
+ .setOnDismissPendingIntent(pendingIntentService)
+ .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_IMMEDIATELY)
+ .setCustomNotification(
+ Notification.Builder("Other title", "Other text").addAction(action2).build()
+ )
+ .build()
+ )
+ .addEqualityGroup(
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setSubtitle("Issue subtitle")
+ .setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
+ .addAction(action1)
+ .addAction(action2)
+ .setOnDismissPendingIntent(pendingIntentService)
+ .setAttributionTitle("attribution title")
+ .build(),
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setSubtitle("Issue subtitle")
+ .setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
+ .addAction(action1)
+ .addAction(action2)
+ .setOnDismissPendingIntent(pendingIntentService)
+ .setAttributionTitle("attribution title")
+ .build()
+ )
+ .addEqualityGroup(
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_CRITICAL_WARNING,
+ "issue_type_id"
+ )
+ .setAttributionTitle("Other issue attribution title")
+ .addAction(action1)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setSubtitle("Issue subtitle")
+ .setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
+ .addAction(action1)
+ .addAction(action2)
+ .setOnDismissPendingIntent(pendingIntentService)
+ .setAttributionTitle("attribution title")
+ .setDeduplicationId("deduplication_id")
+ .build(),
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setSubtitle("Issue subtitle")
+ .setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
+ .addAction(action1)
+ .addAction(action2)
+ .setOnDismissPendingIntent(pendingIntentService)
+ .setAttributionTitle("attribution title")
+ .setDeduplicationId("deduplication_id")
+ .build()
+ )
+ .addEqualityGroup(
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setSubtitle("Issue subtitle")
+ .setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
+ .addAction(action1)
+ .addAction(action2)
+ .setOnDismissPendingIntent(pendingIntentService)
+ .setAttributionTitle("attribution title")
+ .setDeduplicationId("other_deduplication_id")
+ .build()
+ )
+ .addEqualityGroup(
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setSubtitle("Other issue subtitle")
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DATA)
+ .addAction(action1)
+ .build()
+ )
.addEqualityGroup(
SafetySourceIssue.Builder(
"Issue id",
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
+ .setSubtitle("Other issue subtitle")
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_PASSWORDS)
+ .addAction(action1)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setSubtitle("Other issue subtitle")
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_PERSONAL_SAFETY)
+ .addAction(action1)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_MANUAL)
+ .addAction(action1)
+ .setAttributionTitle("Attribution title")
+ .setDeduplicationId("dedup_id")
+ .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_NEVER)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_TIP)
+ .addAction(action1)
+ .build(),
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_TIP)
+ .addAction(action1)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC)
+ .addAction(action1)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_DELAYED)
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setSubtitle("Issue subtitle")
+ .setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
+ .addAction(
+ Action.Builder(action1)
+ .setConfirmationDialogDetails(
+ ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+ )
+ .build()
+ )
+ .addAction(action2)
+ .setOnDismissPendingIntent(pendingIntentService)
+ .build()
+ )
+ .addEqualityGroup(
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
+ .setSubtitle("Issue subtitle")
+ .setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
+ .addAction(action1)
+ .addAction(
+ Action.Builder(action2)
+ .setConfirmationDialogDetails(
+ ConfirmationDialogDetails("Title", "Text", "Accept", "Deny")
+ )
+ .build()
+ )
+ .setOnDismissPendingIntent(pendingIntentService)
+ .build()
+ )
+
+ /**
+ * Creates a new [EqualsHashCodeToStringTester] instance which covers all the fields in the T
+ * API and is safe to use on any T+ API level.
+ */
+ private fun newTiramisuEqualsHashCodeToStringTester(
+ createCopyFromBuilder: ((SafetySourceIssue) -> SafetySourceIssue)? = null
+ ) =
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetySourceIssue.CREATOR,
+ createCopy = createCopyFromBuilder
+ )
+ .addEqualityGroup(
+ SafetySourceIssue.Builder(
+ "Issue id",
+ "Issue title",
+ "Issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ "issue_type_id"
+ )
.setSubtitle("Issue subtitle")
.setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
.addAction(action1)
@@ -595,130 +1966,206 @@ class SafetySourceIssueTest {
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.setSubtitle("Issue subtitle")
.setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
.addAction(action1)
.addAction(action2)
.setOnDismissPendingIntent(pendingIntentService)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySourceIssue.Builder(
"Issue id",
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action1)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySourceIssue.Builder(
"Other issue id",
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action1)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySourceIssue.Builder(
"Issue id",
"Other issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action1)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySourceIssue.Builder(
"Issue id",
"Issue title",
"Different issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action1)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySourceIssue.Builder(
"Issue id",
"Issue title",
"Issue summary",
SEVERITY_LEVEL_CRITICAL_WARNING,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action1)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySourceIssue.Builder(
"Issue id",
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "other_issue_type_id")
+ "other_issue_type_id"
+ )
.addAction(action1)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySourceIssue.Builder(
"Issue id",
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.addAction(action2)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySourceIssue.Builder(
"Issue id",
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.setSubtitle("Other issue subtitle")
.setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
.addAction(action1)
.addAction(action2)
.setOnDismissPendingIntent(pendingIntentService)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySourceIssue.Builder(
"Issue id",
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.setSubtitle("Other issue subtitle")
.setIssueCategory(ISSUE_CATEGORY_DEVICE)
.addAction(action1)
.addAction(action2)
.setOnDismissPendingIntent(pendingIntentService)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySourceIssue.Builder(
"Issue id",
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.setSubtitle("Other issue subtitle")
.setIssueCategory(ISSUE_CATEGORY_DEVICE)
.addAction(action2)
.addAction(action1)
.setOnDismissPendingIntent(pendingIntentService)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySourceIssue.Builder(
"Issue id",
"Issue title",
"Issue summary",
SEVERITY_LEVEL_INFORMATION,
- "issue_type_id")
+ "issue_type_id"
+ )
.setSubtitle("Other issue subtitle")
.setIssueCategory(ISSUE_CATEGORY_DEVICE)
.addAction(action2)
.addAction(action1)
.setOnDismissPendingIntent(
PendingIntent.getService(
- context, 0, Intent("Other PendingIntent service"), FLAG_IMMUTABLE))
- .build())
- .test()
- }
+ context,
+ 0,
+ Intent("Other PendingIntent service"),
+ FLAG_IMMUTABLE
+ )
+ )
+ .build()
+ )
+
+ private fun actionNewTiramisuEqualsHashCodeToStringTester(
+ createCopyFromBuilder: ((Action) -> Action)? = null
+ ) =
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = Action.CREATOR,
+ createCopy = createCopyFromBuilder
+ )
+ .addEqualityGroup(
+ Action.Builder("action_id", "Action label", pendingIntent1).build(),
+ Action.Builder("action_id", "Action label", pendingIntent1).build(),
+ Action.Builder("action_id", "Action label", pendingIntent1)
+ .setWillResolve(false)
+ .build()
+ )
+ .addEqualityGroup(
+ Action.Builder("action_id", "Action label", pendingIntent1)
+ .setSuccessMessage("Action successfully completed")
+ .build()
+ )
+ .addEqualityGroup(
+ Action.Builder("action_id", "Other action label", pendingIntent1).build()
+ )
+ .addEqualityGroup(
+ Action.Builder("other_action_id", "Action label", pendingIntent1).build()
+ )
+ .addEqualityGroup(
+ Action.Builder("action_id", "Action label", pendingIntentService)
+ .setWillResolve(true)
+ .build()
+ )
+ .addEqualityGroup(
+ Action.Builder(
+ "action_id",
+ "Action label",
+ PendingIntent.getActivity(
+ context,
+ 0,
+ Intent("Other action PendingIntent"),
+ FLAG_IMMUTABLE
+ )
+ )
+ .build()
+ )
+ .addEqualityGroup(
+ Action.Builder("action_id", "Action label", pendingIntent1)
+ .setSuccessMessage("Other action successfully completed")
+ .build()
+ )
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceStatusTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceStatusTest.kt
index f082aa5ab..5aeea21f1 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.VERSION_CODES.TIRAMISU
+import android.os.Build
import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING
import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_INFORMATION
import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED
@@ -28,12 +28,12 @@ import android.safetycenter.SafetySourceStatus
import android.safetycenter.SafetySourceStatus.IconAction
import android.safetycenter.SafetySourceStatus.IconAction.ICON_TYPE_GEAR
import android.safetycenter.SafetySourceStatus.IconAction.ICON_TYPE_INFO
-import android.safetycenter.cts.testing.EqualsHashCodeToStringTester
import android.safetycenter.cts.testing.Generic
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
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.assertFailsWith
import org.junit.Test
@@ -41,7 +41,6 @@ import org.junit.runner.RunWith
/** CTS tests for [SafetySourceStatus]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class SafetySourceStatusTest {
private val context: Context = getApplicationContext()
@@ -96,10 +95,11 @@ class SafetySourceStatusTest {
@Test
fun iconAction_equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
+ EqualsHashCodeToStringTester.ofParcelable(parcelableCreator = IconAction.CREATOR)
.addEqualityGroup(
IconAction(ICON_TYPE_GEAR, pendingIntent1),
- IconAction(ICON_TYPE_GEAR, pendingIntent1))
+ IconAction(ICON_TYPE_GEAR, pendingIntent1)
+ )
.addEqualityGroup(IconAction(ICON_TYPE_INFO, pendingIntent1))
.addEqualityGroup(IconAction(ICON_TYPE_GEAR, pendingIntent2))
.test()
@@ -193,7 +193,10 @@ class SafetySourceStatusTest {
fun build_withNullTitle_throwsNullPointerException() {
assertFailsWith(NullPointerException::class) {
SafetySourceStatus.Builder(
- Generic.asNull(), "Status summary", SEVERITY_LEVEL_INFORMATION)
+ Generic.asNull(),
+ "Status summary",
+ SEVERITY_LEVEL_INFORMATION
+ )
}
}
@@ -226,7 +229,9 @@ class SafetySourceStatusTest {
context,
/* requestCode = */ 0,
Intent("PendingIntent service"),
- FLAG_IMMUTABLE))
+ FLAG_IMMUTABLE
+ )
+ )
}
assertThat(exception)
.hasMessageThat()
@@ -243,7 +248,8 @@ class SafetySourceStatusTest {
.hasMessageThat()
.isEqualTo(
"Safety source status must have a severity level of SEVERITY_LEVEL_UNSPECIFIED" +
- " when disabled")
+ " when disabled"
+ )
}
@Test
@@ -275,51 +281,102 @@ class SafetySourceStatusTest {
@Test
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
+ newTiramisuEqualsHashCodeToStringTester().test()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun equalsHashCodeToString_usingEqualsHashCodeToStringTester_atLeastAndroidU() {
+ newTiramisuEqualsHashCodeToStringTester(
+ createCopyFromBuilder = { SafetySourceStatus.Builder(it).build() }
+ )
+ .test()
+ }
+
+ private fun newTiramisuEqualsHashCodeToStringTester(
+ createCopyFromBuilder: ((SafetySourceStatus) -> SafetySourceStatus)? = null
+ ) =
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetySourceStatus.CREATOR,
+ createCopy = createCopyFromBuilder
+ )
.addEqualityGroup(
SafetySourceStatus.Builder(
- "Status title", "Status summary", SEVERITY_LEVEL_INFORMATION)
+ "Status title",
+ "Status summary",
+ SEVERITY_LEVEL_INFORMATION
+ )
.setPendingIntent(pendingIntent1)
.setIconAction(iconAction1)
.setEnabled(true)
.build(),
SafetySourceStatus.Builder(
- "Status title", "Status summary", SEVERITY_LEVEL_INFORMATION)
+ "Status title",
+ "Status summary",
+ SEVERITY_LEVEL_INFORMATION
+ )
.setPendingIntent(pendingIntent1)
.setIconAction(iconAction1)
.setEnabled(true)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySourceStatus.Builder(
- "Status title", "Status summary", SEVERITY_LEVEL_INFORMATION)
- .build())
+ "Status title",
+ "Status summary",
+ SEVERITY_LEVEL_INFORMATION
+ )
+ .build()
+ )
.addEqualityGroup(
SafetySourceStatus.Builder(
- "Other status title", "Status summary", SEVERITY_LEVEL_INFORMATION)
- .build())
+ "Other status title",
+ "Status summary",
+ SEVERITY_LEVEL_INFORMATION
+ )
+ .build()
+ )
.addEqualityGroup(
SafetySourceStatus.Builder(
- "Status title", "Other status summary", SEVERITY_LEVEL_INFORMATION)
- .build())
+ "Status title",
+ "Other status summary",
+ SEVERITY_LEVEL_INFORMATION
+ )
+ .build()
+ )
.addEqualityGroup(
SafetySourceStatus.Builder(
- "Status title", "Status summary", SEVERITY_LEVEL_CRITICAL_WARNING)
- .build())
+ "Status title",
+ "Status summary",
+ SEVERITY_LEVEL_CRITICAL_WARNING
+ )
+ .build()
+ )
.addEqualityGroup(
SafetySourceStatus.Builder(
- "Status title", "Status summary", SEVERITY_LEVEL_CRITICAL_WARNING)
+ "Status title",
+ "Status summary",
+ SEVERITY_LEVEL_CRITICAL_WARNING
+ )
.setPendingIntent(pendingIntent2)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySourceStatus.Builder(
- "Status title", "Status summary", SEVERITY_LEVEL_CRITICAL_WARNING)
+ "Status title",
+ "Status summary",
+ SEVERITY_LEVEL_CRITICAL_WARNING
+ )
.setIconAction(iconAction2)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySourceStatus.Builder(
- "Status title", "Status summary", SEVERITY_LEVEL_UNSPECIFIED)
+ "Status title",
+ "Status summary",
+ SEVERITY_LEVEL_UNSPECIFIED
+ )
.setEnabled(false)
- .build())
- .test()
- }
+ .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 f8131409b..7dff9dd54 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetyCenterConfigTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetyCenterConfigTest.kt
@@ -16,25 +16,57 @@
package android.safetycenter.cts.config
-import android.os.Build.VERSION_CODES.TIRAMISU
+import android.os.Build
import android.safetycenter.config.SafetyCenterConfig
-import android.safetycenter.cts.testing.EqualsHashCodeToStringTester
import androidx.test.ext.junit.runners.AndroidJUnit4
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.assertFailsWith
import org.junit.Test
import org.junit.runner.RunWith
/** CTS tests for [SafetyCenterConfig]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class SafetyCenterConfigTest {
@Test
- fun getSafetySources_returnsSafetySources() {
+ fun getSafetySourcesGroups_returnsSafetySourcesGroups() {
assertThat(BASE.safetySourcesGroups)
- .containsExactly(SafetySourcesGroupTest.RIGID, SafetySourcesGroupTest.HIDDEN)
+ .containsExactly(
+ SafetySourcesGroupTest.STATELESS_INFERRED,
+ SafetySourcesGroupTest.HIDDEN_INFERRED
+ )
+ .inOrder()
+ }
+
+ @Test
+ fun getSafetySourcesGroups_mutationsAreNotAllowed() {
+ val sourcesGroups = BASE.safetySourcesGroups
+
+ assertFailsWith(UnsupportedOperationException::class) {
+ sourcesGroups.add(SafetySourcesGroupTest.STATEFUL_INFERRED_WITH_SUMMARY)
+ }
+ }
+
+ @Test
+ fun builder_addSafetySourcesGroup_doesNotMutatePreviouslyBuiltInstance() {
+ val safetyCenterConfigBuilder =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(SafetySourcesGroupTest.STATELESS_INFERRED)
+ .addSafetySourcesGroup(SafetySourcesGroupTest.HIDDEN_INFERRED)
+ val sourceGroups = safetyCenterConfigBuilder.build().safetySourcesGroups
+
+ safetyCenterConfigBuilder.addSafetySourcesGroup(
+ SafetySourcesGroupTest.STATEFUL_INFERRED_WITH_SUMMARY
+ )
+
+ assertThat(sourceGroups)
+ .containsExactly(
+ SafetySourcesGroupTest.STATELESS_INFERRED,
+ SafetySourcesGroupTest.HIDDEN_INFERRED
+ )
.inOrder()
}
@@ -50,26 +82,44 @@ class SafetyCenterConfigTest {
@Test
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
+ newTiramisuEqualsHashCodeToStringTester().test()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun equalsHashCodeToString_usingEqualsHashCodeToStringTester_atLeastAndroidU() {
+ newTiramisuEqualsHashCodeToStringTester(
+ createCopyFromBuilder = { SafetyCenterConfig.Builder(it).build() }
+ )
+ .test()
+ }
+
+ private fun newTiramisuEqualsHashCodeToStringTester(
+ createCopyFromBuilder: ((SafetyCenterConfig) -> SafetyCenterConfig)? = null
+ ) =
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetyCenterConfig.CREATOR,
+ createCopy = createCopyFromBuilder
+ )
.addEqualityGroup(
BASE,
SafetyCenterConfig.Builder()
- .addSafetySourcesGroup(SafetySourcesGroupTest.RIGID)
- .addSafetySourcesGroup(SafetySourcesGroupTest.HIDDEN)
- .build())
+ .addSafetySourcesGroup(SafetySourcesGroupTest.STATELESS_INFERRED)
+ .addSafetySourcesGroup(SafetySourcesGroupTest.HIDDEN_INFERRED)
+ .build()
+ )
.addEqualityGroup(
SafetyCenterConfig.Builder()
- .addSafetySourcesGroup(SafetySourcesGroupTest.HIDDEN)
- .addSafetySourcesGroup(SafetySourcesGroupTest.RIGID)
- .build())
- .test()
- }
+ .addSafetySourcesGroup(SafetySourcesGroupTest.HIDDEN_INFERRED)
+ .addSafetySourcesGroup(SafetySourcesGroupTest.STATELESS_INFERRED)
+ .build()
+ )
companion object {
private val BASE =
SafetyCenterConfig.Builder()
- .addSafetySourcesGroup(SafetySourcesGroupTest.RIGID)
- .addSafetySourcesGroup(SafetySourcesGroupTest.HIDDEN)
+ .addSafetySourcesGroup(SafetySourcesGroupTest.STATELESS_INFERRED)
+ .addSafetySourcesGroup(SafetySourcesGroupTest.HIDDEN_INFERRED)
.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 b47b220b5..055e82ad3 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt
@@ -17,12 +17,13 @@
package android.safetycenter.cts.config
import android.content.res.Resources
-import android.os.Build.VERSION_CODES.TIRAMISU
+import android.os.Build
import android.safetycenter.config.SafetySource
-import android.safetycenter.cts.testing.EqualsHashCodeToStringTester
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.ext.truth.os.ParcelableSubject.assertThat
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 org.junit.Assert.assertThrows
import org.junit.Test
@@ -30,13 +31,12 @@ import org.junit.runner.RunWith
/** CTS tests for [SafetySource]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class SafetySourceTest {
@Test
fun getType_returnsType() {
assertThat(DYNAMIC_BAREBONE.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- assertThat(DYNAMIC_ALL_OPTIONAL.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
+ assertThat(dynamicAllOptional().type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
assertThat(DYNAMIC_HIDDEN.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.type)
.isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
@@ -44,40 +44,54 @@ class SafetySourceTest {
assertThat(STATIC_BAREBONE.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_STATIC)
assertThat(STATIC_ALL_OPTIONAL.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_STATIC)
assertThat(ISSUE_ONLY_BAREBONE.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY)
- assertThat(ISSUE_ONLY_ALL_OPTIONAL.type)
+ assertThat(issueOnlyAllOptional().type)
.isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY)
}
@Test
fun getId_returnsId() {
assertThat(DYNAMIC_BAREBONE.id).isEqualTo(DYNAMIC_BAREBONE_ID)
- assertThat(DYNAMIC_ALL_OPTIONAL.id).isEqualTo(DYNAMIC_ALL_OPTIONAL_ID)
+ assertThat(dynamicAllOptional().id).isEqualTo(DYNAMIC_ALL_OPTIONAL_ID)
assertThat(DYNAMIC_HIDDEN.id).isEqualTo(DYNAMIC_HIDDEN_ID)
assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.id).isEqualTo(DYNAMIC_HIDDEN_WITH_SEARCH_ID)
assertThat(DYNAMIC_DISABLED.id).isEqualTo(DYNAMIC_DISABLED_ID)
assertThat(STATIC_BAREBONE.id).isEqualTo(STATIC_BAREBONE_ID)
assertThat(STATIC_ALL_OPTIONAL.id).isEqualTo(STATIC_ALL_OPTIONAL_ID)
assertThat(ISSUE_ONLY_BAREBONE.id).isEqualTo(ISSUE_ONLY_BAREBONE_ID)
- assertThat(ISSUE_ONLY_ALL_OPTIONAL.id).isEqualTo(ISSUE_ONLY_ALL_OPTIONAL_ID)
+ assertThat(issueOnlyAllOptional().id).isEqualTo(ISSUE_ONLY_ALL_OPTIONAL_ID)
}
@Test
fun getPackageName_returnsPackageNameOrThrows() {
assertThat(DYNAMIC_BAREBONE.packageName).isEqualTo(PACKAGE_NAME)
- assertThat(DYNAMIC_ALL_OPTIONAL.packageName).isEqualTo(PACKAGE_NAME)
+ assertThat(dynamicAllOptional().packageName).isEqualTo(PACKAGE_NAME)
assertThat(DYNAMIC_HIDDEN.packageName).isEqualTo(PACKAGE_NAME)
assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.packageName).isEqualTo(PACKAGE_NAME)
assertThat(DYNAMIC_DISABLED.packageName).isEqualTo(PACKAGE_NAME)
assertThrows(UnsupportedOperationException::class.java) { STATIC_BAREBONE.packageName }
assertThrows(UnsupportedOperationException::class.java) { STATIC_ALL_OPTIONAL.packageName }
assertThat(ISSUE_ONLY_BAREBONE.packageName).isEqualTo(PACKAGE_NAME)
- assertThat(ISSUE_ONLY_ALL_OPTIONAL.packageName).isEqualTo(PACKAGE_NAME)
+ assertThat(issueOnlyAllOptional().packageName).isEqualTo(PACKAGE_NAME)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getOptionalPackageName_returnsPackageNameOrNull() {
+ assertThat(DYNAMIC_BAREBONE.optionalPackageName).isEqualTo(PACKAGE_NAME)
+ assertThat(dynamicAllOptional().optionalPackageName).isEqualTo(PACKAGE_NAME)
+ assertThat(DYNAMIC_HIDDEN.optionalPackageName).isEqualTo(PACKAGE_NAME)
+ assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.optionalPackageName).isEqualTo(PACKAGE_NAME)
+ assertThat(DYNAMIC_DISABLED.optionalPackageName).isEqualTo(PACKAGE_NAME)
+ assertThat(STATIC_BAREBONE.optionalPackageName).isNull()
+ assertThat(STATIC_ALL_OPTIONAL.optionalPackageName).isEqualTo(PACKAGE_NAME)
+ assertThat(ISSUE_ONLY_BAREBONE.optionalPackageName).isEqualTo(PACKAGE_NAME)
+ assertThat(issueOnlyAllOptional().optionalPackageName).isEqualTo(PACKAGE_NAME)
}
@Test
fun getTitleResId_returnsTitleResIdOrThrows() {
assertThat(DYNAMIC_BAREBONE.titleResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(DYNAMIC_ALL_OPTIONAL.titleResId).isEqualTo(REFERENCE_RES_ID)
+ assertThat(dynamicAllOptional().titleResId).isEqualTo(REFERENCE_RES_ID)
assertThat(DYNAMIC_DISABLED.titleResId).isEqualTo(REFERENCE_RES_ID)
assertThat(DYNAMIC_HIDDEN.titleResId).isEqualTo(Resources.ID_NULL)
assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.titleResId).isEqualTo(REFERENCE_RES_ID)
@@ -85,7 +99,7 @@ class SafetySourceTest {
assertThat(STATIC_ALL_OPTIONAL.titleResId).isEqualTo(REFERENCE_RES_ID)
assertThrows(UnsupportedOperationException::class.java) { ISSUE_ONLY_BAREBONE.titleResId }
assertThrows(UnsupportedOperationException::class.java) {
- ISSUE_ONLY_ALL_OPTIONAL.titleResId
+ issueOnlyAllOptional().titleResId
}
}
@@ -94,7 +108,7 @@ class SafetySourceTest {
assertThrows(UnsupportedOperationException::class.java) {
DYNAMIC_BAREBONE.titleForWorkResId
}
- assertThat(DYNAMIC_ALL_OPTIONAL.titleForWorkResId).isEqualTo(REFERENCE_RES_ID)
+ assertThat(dynamicAllOptional().titleForWorkResId).isEqualTo(REFERENCE_RES_ID)
assertThrows(UnsupportedOperationException::class.java) {
DYNAMIC_DISABLED.titleForWorkResId
}
@@ -108,14 +122,14 @@ class SafetySourceTest {
ISSUE_ONLY_BAREBONE.titleForWorkResId
}
assertThrows(UnsupportedOperationException::class.java) {
- ISSUE_ONLY_ALL_OPTIONAL.titleForWorkResId
+ issueOnlyAllOptional().titleForWorkResId
}
}
@Test
fun getSummaryResId_returnsSummaryResIdOrThrows() {
assertThat(DYNAMIC_BAREBONE.summaryResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(DYNAMIC_ALL_OPTIONAL.summaryResId).isEqualTo(REFERENCE_RES_ID)
+ assertThat(dynamicAllOptional().summaryResId).isEqualTo(REFERENCE_RES_ID)
assertThat(DYNAMIC_DISABLED.summaryResId).isEqualTo(REFERENCE_RES_ID)
assertThat(DYNAMIC_HIDDEN.summaryResId).isEqualTo(Resources.ID_NULL)
assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.summaryResId).isEqualTo(REFERENCE_RES_ID)
@@ -123,14 +137,14 @@ class SafetySourceTest {
assertThat(STATIC_ALL_OPTIONAL.summaryResId).isEqualTo(REFERENCE_RES_ID)
assertThrows(UnsupportedOperationException::class.java) { ISSUE_ONLY_BAREBONE.summaryResId }
assertThrows(UnsupportedOperationException::class.java) {
- ISSUE_ONLY_ALL_OPTIONAL.summaryResId
+ issueOnlyAllOptional().summaryResId
}
}
@Test
fun getIntentAction_returnsIntentActionOrThrows() {
assertThat(DYNAMIC_BAREBONE.intentAction).isEqualTo(INTENT_ACTION)
- assertThat(DYNAMIC_ALL_OPTIONAL.intentAction).isEqualTo(INTENT_ACTION)
+ assertThat(dynamicAllOptional().intentAction).isEqualTo(INTENT_ACTION)
assertThat(DYNAMIC_DISABLED.intentAction).isNull()
assertThat(DYNAMIC_HIDDEN.intentAction).isNull()
assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.intentAction).isEqualTo(INTENT_ACTION)
@@ -138,28 +152,28 @@ class SafetySourceTest {
assertThat(STATIC_ALL_OPTIONAL.intentAction).isEqualTo(INTENT_ACTION)
assertThrows(UnsupportedOperationException::class.java) { ISSUE_ONLY_BAREBONE.intentAction }
assertThrows(UnsupportedOperationException::class.java) {
- ISSUE_ONLY_ALL_OPTIONAL.intentAction
+ issueOnlyAllOptional().intentAction
}
}
@Test
fun getProfile_returnsProfile() {
assertThat(DYNAMIC_BAREBONE.profile).isEqualTo(SafetySource.PROFILE_PRIMARY)
- assertThat(DYNAMIC_ALL_OPTIONAL.profile).isEqualTo(SafetySource.PROFILE_ALL)
+ assertThat(dynamicAllOptional().profile).isEqualTo(SafetySource.PROFILE_ALL)
assertThat(DYNAMIC_DISABLED.profile).isEqualTo(SafetySource.PROFILE_PRIMARY)
assertThat(DYNAMIC_HIDDEN.profile).isEqualTo(SafetySource.PROFILE_ALL)
assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.profile).isEqualTo(SafetySource.PROFILE_ALL)
assertThat(STATIC_BAREBONE.profile).isEqualTo(SafetySource.PROFILE_PRIMARY)
assertThat(STATIC_ALL_OPTIONAL.profile).isEqualTo(SafetySource.PROFILE_ALL)
assertThat(ISSUE_ONLY_BAREBONE.profile).isEqualTo(SafetySource.PROFILE_PRIMARY)
- assertThat(ISSUE_ONLY_ALL_OPTIONAL.profile).isEqualTo(SafetySource.PROFILE_ALL)
+ assertThat(issueOnlyAllOptional().profile).isEqualTo(SafetySource.PROFILE_ALL)
}
@Test
fun getInitialDisplayState_returnsInitialDisplayStateOrThrows() {
assertThat(DYNAMIC_BAREBONE.initialDisplayState)
.isEqualTo(SafetySource.INITIAL_DISPLAY_STATE_ENABLED)
- assertThat(DYNAMIC_ALL_OPTIONAL.initialDisplayState)
+ assertThat(dynamicAllOptional().initialDisplayState)
.isEqualTo(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
assertThat(DYNAMIC_DISABLED.initialDisplayState)
.isEqualTo(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
@@ -177,14 +191,14 @@ class SafetySourceTest {
ISSUE_ONLY_BAREBONE.initialDisplayState
}
assertThrows(UnsupportedOperationException::class.java) {
- ISSUE_ONLY_ALL_OPTIONAL.initialDisplayState
+ issueOnlyAllOptional().initialDisplayState
}
}
@Test
fun getMaxSeverityLevel_returnsMaxSeverityLevelOrThrows() {
assertThat(DYNAMIC_BAREBONE.maxSeverityLevel).isEqualTo(Integer.MAX_VALUE)
- assertThat(DYNAMIC_ALL_OPTIONAL.maxSeverityLevel).isEqualTo(MAX_SEVERITY_LEVEL)
+ assertThat(dynamicAllOptional().maxSeverityLevel).isEqualTo(MAX_SEVERITY_LEVEL)
assertThat(DYNAMIC_DISABLED.maxSeverityLevel).isEqualTo(Integer.MAX_VALUE)
assertThat(DYNAMIC_HIDDEN.maxSeverityLevel).isEqualTo(Integer.MAX_VALUE)
assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.maxSeverityLevel).isEqualTo(Integer.MAX_VALUE)
@@ -193,13 +207,13 @@ class SafetySourceTest {
STATIC_ALL_OPTIONAL.maxSeverityLevel
}
assertThat(ISSUE_ONLY_BAREBONE.maxSeverityLevel).isEqualTo(Integer.MAX_VALUE)
- assertThat(ISSUE_ONLY_ALL_OPTIONAL.maxSeverityLevel).isEqualTo(MAX_SEVERITY_LEVEL)
+ assertThat(issueOnlyAllOptional().maxSeverityLevel).isEqualTo(MAX_SEVERITY_LEVEL)
}
@Test
fun getSearchTermsResId_returnsSearchTermsResIdOrThrows() {
assertThat(DYNAMIC_BAREBONE.searchTermsResId).isEqualTo(Resources.ID_NULL)
- assertThat(DYNAMIC_ALL_OPTIONAL.searchTermsResId).isEqualTo(REFERENCE_RES_ID)
+ assertThat(dynamicAllOptional().searchTermsResId).isEqualTo(REFERENCE_RES_ID)
assertThat(DYNAMIC_DISABLED.searchTermsResId).isEqualTo(Resources.ID_NULL)
assertThat(DYNAMIC_HIDDEN.searchTermsResId).isEqualTo(Resources.ID_NULL)
assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.searchTermsResId).isEqualTo(REFERENCE_RES_ID)
@@ -209,14 +223,14 @@ class SafetySourceTest {
ISSUE_ONLY_BAREBONE.searchTermsResId
}
assertThrows(UnsupportedOperationException::class.java) {
- ISSUE_ONLY_ALL_OPTIONAL.searchTermsResId
+ issueOnlyAllOptional().searchTermsResId
}
}
@Test
fun isLoggingAllowed_returnsLoggingAllowedOrThrows() {
assertThat(DYNAMIC_BAREBONE.isLoggingAllowed).isEqualTo(true)
- assertThat(DYNAMIC_ALL_OPTIONAL.isLoggingAllowed).isEqualTo(false)
+ assertThat(dynamicAllOptional().isLoggingAllowed).isEqualTo(false)
assertThat(DYNAMIC_DISABLED.isLoggingAllowed).isEqualTo(true)
assertThat(DYNAMIC_HIDDEN.isLoggingAllowed).isEqualTo(true)
assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.isLoggingAllowed).isEqualTo(true)
@@ -225,13 +239,13 @@ class SafetySourceTest {
STATIC_ALL_OPTIONAL.isLoggingAllowed
}
assertThat(ISSUE_ONLY_BAREBONE.isLoggingAllowed).isEqualTo(true)
- assertThat(ISSUE_ONLY_ALL_OPTIONAL.isLoggingAllowed).isEqualTo(false)
+ assertThat(issueOnlyAllOptional().isLoggingAllowed).isEqualTo(false)
}
@Test
fun isRefreshOnPageOpenAllowed_returnsRefreshOnPageOpenAllowedOrThrows() {
assertThat(DYNAMIC_BAREBONE.isRefreshOnPageOpenAllowed).isEqualTo(false)
- assertThat(DYNAMIC_ALL_OPTIONAL.isRefreshOnPageOpenAllowed).isEqualTo(true)
+ assertThat(dynamicAllOptional().isRefreshOnPageOpenAllowed).isEqualTo(true)
assertThat(DYNAMIC_DISABLED.isRefreshOnPageOpenAllowed).isEqualTo(false)
assertThat(DYNAMIC_HIDDEN.isRefreshOnPageOpenAllowed).isEqualTo(false)
assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.isRefreshOnPageOpenAllowed).isEqualTo(false)
@@ -242,41 +256,91 @@ class SafetySourceTest {
STATIC_ALL_OPTIONAL.isRefreshOnPageOpenAllowed
}
assertThat(ISSUE_ONLY_BAREBONE.isRefreshOnPageOpenAllowed).isEqualTo(false)
- assertThat(ISSUE_ONLY_ALL_OPTIONAL.isRefreshOnPageOpenAllowed).isEqualTo(true)
+ assertThat(issueOnlyAllOptional().isRefreshOnPageOpenAllowed).isEqualTo(true)
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @Test
+ fun areNotificationsAllowed_returnsNotificationsAllowed() {
+ assertThat(DYNAMIC_BAREBONE.areNotificationsAllowed()).isFalse()
+ assertThat(dynamicAllOptional().areNotificationsAllowed()).isTrue()
+ assertThat(DYNAMIC_DISABLED.areNotificationsAllowed()).isFalse()
+ assertThat(DYNAMIC_HIDDEN.areNotificationsAllowed()).isFalse()
+ assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.areNotificationsAllowed()).isFalse()
+ assertThat(STATIC_BAREBONE.areNotificationsAllowed()).isFalse()
+ assertThat(STATIC_ALL_OPTIONAL.areNotificationsAllowed()).isFalse()
+ assertThat(ISSUE_ONLY_BAREBONE.areNotificationsAllowed()).isFalse()
+ assertThat(issueOnlyAllOptional().areNotificationsAllowed()).isTrue()
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @Test
+ fun getDeduplicationGroupsList_returnsDeduplicationGroups() {
+ assertThat(DYNAMIC_BAREBONE.deduplicationGroup).isNull()
+ assertThat(dynamicAllOptional().deduplicationGroup).isEqualTo(DEDUPLICATION_GROUP)
+ assertThat(DYNAMIC_DISABLED.deduplicationGroup).isNull()
+ assertThat(DYNAMIC_HIDDEN.deduplicationGroup).isNull()
+ assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.deduplicationGroup).isNull()
+ assertThat(STATIC_BAREBONE.deduplicationGroup).isNull()
+ assertThat(STATIC_ALL_OPTIONAL.deduplicationGroup).isNull()
+ assertThat(ISSUE_ONLY_BAREBONE.deduplicationGroup).isNull()
+ assertThat(issueOnlyAllOptional().deduplicationGroup).isEqualTo(DEDUPLICATION_GROUP)
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @Test
+ fun getPackageCertificateHashes_returnsPackageCerts() {
+ assertThat(DYNAMIC_BAREBONE.packageCertificateHashes).isEmpty()
+ assertThat(dynamicAllOptional().packageCertificateHashes).containsExactly(HASH1)
+ assertThat(DYNAMIC_DISABLED.packageCertificateHashes).isEmpty()
+ assertThat(DYNAMIC_HIDDEN.packageCertificateHashes).isEmpty()
+ assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.packageCertificateHashes).isEmpty()
+ assertThat(STATIC_BAREBONE.packageCertificateHashes).isEmpty()
+ assertThat(STATIC_ALL_OPTIONAL.packageCertificateHashes).isEmpty()
+ assertThat(ISSUE_ONLY_BAREBONE.packageCertificateHashes).isEmpty()
+ assertThat(issueOnlyAllOptional().packageCertificateHashes).containsExactly(HASH1, HASH2)
}
@Test
fun describeContents_returns0() {
assertThat(DYNAMIC_BAREBONE.describeContents()).isEqualTo(0)
- assertThat(DYNAMIC_ALL_OPTIONAL.describeContents()).isEqualTo(0)
+ assertThat(dynamicAllOptional().describeContents()).isEqualTo(0)
assertThat(DYNAMIC_DISABLED.describeContents()).isEqualTo(0)
assertThat(DYNAMIC_HIDDEN.describeContents()).isEqualTo(0)
assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.describeContents()).isEqualTo(0)
assertThat(STATIC_BAREBONE.describeContents()).isEqualTo(0)
assertThat(STATIC_ALL_OPTIONAL.describeContents()).isEqualTo(0)
assertThat(ISSUE_ONLY_BAREBONE.describeContents()).isEqualTo(0)
- assertThat(ISSUE_ONLY_ALL_OPTIONAL.describeContents()).isEqualTo(0)
+ assertThat(issueOnlyAllOptional().describeContents()).isEqualTo(0)
}
@Test
fun parcelRoundTrip_recreatesEqual() {
assertThat(DYNAMIC_BAREBONE).recreatesEqual(SafetySource.CREATOR)
- assertThat(DYNAMIC_ALL_OPTIONAL).recreatesEqual(SafetySource.CREATOR)
+ assertThat(dynamicAllOptional()).recreatesEqual(SafetySource.CREATOR)
assertThat(DYNAMIC_DISABLED).recreatesEqual(SafetySource.CREATOR)
assertThat(DYNAMIC_HIDDEN).recreatesEqual(SafetySource.CREATOR)
assertThat(DYNAMIC_HIDDEN_WITH_SEARCH).recreatesEqual(SafetySource.CREATOR)
assertThat(STATIC_BAREBONE).recreatesEqual(SafetySource.CREATOR)
assertThat(STATIC_ALL_OPTIONAL).recreatesEqual(SafetySource.CREATOR)
assertThat(ISSUE_ONLY_BAREBONE).recreatesEqual(SafetySource.CREATOR)
- assertThat(ISSUE_ONLY_ALL_OPTIONAL).recreatesEqual(SafetySource.CREATOR)
+ assertThat(issueOnlyAllOptional()).recreatesEqual(SafetySource.CREATOR)
}
@Test
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetySource.CREATOR,
+ createCopy =
+ if (SdkLevel.isAtLeastU()) {
+ { SafetySource.Builder(it).build() }
+ } else {
+ null
+ }
+ )
.addEqualityGroup(DYNAMIC_BAREBONE)
.addEqualityGroup(
- DYNAMIC_ALL_OPTIONAL,
+ dynamicAllOptional(),
SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
.setId(DYNAMIC_ALL_OPTIONAL_ID)
.setPackageName(PACKAGE_NAME)
@@ -290,14 +354,22 @@ class SafetySourceTest {
.setSearchTermsResId(REFERENCE_RES_ID)
.setLoggingAllowed(false)
.setRefreshOnPageOpenAllowed(true)
- .build())
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup(DEDUPLICATION_GROUP)
+ addPackageCertificateHash(HASH1)
+ }
+ }
+ .build()
+ )
.addEqualityGroup(DYNAMIC_HIDDEN)
.addEqualityGroup(DYNAMIC_HIDDEN_WITH_SEARCH)
.addEqualityGroup(DYNAMIC_DISABLED)
.addEqualityGroup(STATIC_BAREBONE)
.addEqualityGroup(STATIC_ALL_OPTIONAL)
.addEqualityGroup(ISSUE_ONLY_BAREBONE)
- .addEqualityGroup(ISSUE_ONLY_ALL_OPTIONAL)
+ .addEqualityGroup(issueOnlyAllOptional())
.addEqualityGroup(
SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
.setId("other")
@@ -312,7 +384,15 @@ class SafetySourceTest {
.setSearchTermsResId(REFERENCE_RES_ID)
.setLoggingAllowed(false)
.setRefreshOnPageOpenAllowed(true)
- .build())
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup(DEDUPLICATION_GROUP)
+ addPackageCertificateHash(HASH1)
+ }
+ }
+ .build()
+ )
.addEqualityGroup(
SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
.setId(DYNAMIC_ALL_OPTIONAL_ID)
@@ -327,7 +407,15 @@ class SafetySourceTest {
.setSearchTermsResId(REFERENCE_RES_ID)
.setLoggingAllowed(false)
.setRefreshOnPageOpenAllowed(true)
- .build())
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup(DEDUPLICATION_GROUP)
+ addPackageCertificateHash(HASH1)
+ }
+ }
+ .build()
+ )
.addEqualityGroup(
SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
.setId(DYNAMIC_ALL_OPTIONAL_ID)
@@ -342,7 +430,15 @@ class SafetySourceTest {
.setSearchTermsResId(REFERENCE_RES_ID)
.setLoggingAllowed(false)
.setRefreshOnPageOpenAllowed(true)
- .build())
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup(DEDUPLICATION_GROUP)
+ addPackageCertificateHash(HASH1)
+ }
+ }
+ .build()
+ )
.addEqualityGroup(
SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
.setId(DYNAMIC_ALL_OPTIONAL_ID)
@@ -357,7 +453,15 @@ class SafetySourceTest {
.setSearchTermsResId(REFERENCE_RES_ID)
.setLoggingAllowed(false)
.setRefreshOnPageOpenAllowed(true)
- .build())
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup(DEDUPLICATION_GROUP)
+ addPackageCertificateHash(HASH1)
+ }
+ }
+ .build()
+ )
.addEqualityGroup(
SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
.setId(DYNAMIC_ALL_OPTIONAL_ID)
@@ -372,7 +476,15 @@ class SafetySourceTest {
.setSearchTermsResId(REFERENCE_RES_ID)
.setLoggingAllowed(false)
.setRefreshOnPageOpenAllowed(true)
- .build())
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup(DEDUPLICATION_GROUP)
+ addPackageCertificateHash(HASH1)
+ }
+ }
+ .build()
+ )
.addEqualityGroup(
SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
.setId(DYNAMIC_ALL_OPTIONAL_ID)
@@ -387,14 +499,23 @@ class SafetySourceTest {
.setSearchTermsResId(REFERENCE_RES_ID)
.setLoggingAllowed(false)
.setRefreshOnPageOpenAllowed(true)
- .build())
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup(DEDUPLICATION_GROUP)
+ addPackageCertificateHash(HASH1)
+ }
+ }
+ .build()
+ )
.addEqualityGroup(
SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
.setId(DYNAMIC_HIDDEN_ID)
.setPackageName(PACKAGE_NAME)
.setProfile(SafetySource.PROFILE_PRIMARY)
.setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_HIDDEN)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
.setId(DYNAMIC_ALL_OPTIONAL_ID)
@@ -409,7 +530,15 @@ class SafetySourceTest {
.setSearchTermsResId(REFERENCE_RES_ID)
.setLoggingAllowed(false)
.setRefreshOnPageOpenAllowed(true)
- .build())
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup(DEDUPLICATION_GROUP)
+ addPackageCertificateHash(HASH1)
+ }
+ }
+ .build()
+ )
.addEqualityGroup(
SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
.setId(DYNAMIC_ALL_OPTIONAL_ID)
@@ -424,7 +553,15 @@ class SafetySourceTest {
.setSearchTermsResId(REFERENCE_RES_ID)
.setLoggingAllowed(false)
.setRefreshOnPageOpenAllowed(true)
- .build())
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup(DEDUPLICATION_GROUP)
+ addPackageCertificateHash(HASH1)
+ }
+ }
+ .build()
+ )
.addEqualityGroup(
SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
.setId(DYNAMIC_ALL_OPTIONAL_ID)
@@ -439,7 +576,15 @@ class SafetySourceTest {
.setSearchTermsResId(-1)
.setLoggingAllowed(false)
.setRefreshOnPageOpenAllowed(true)
- .build())
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup(DEDUPLICATION_GROUP)
+ addPackageCertificateHash(HASH1)
+ }
+ }
+ .build()
+ )
.addEqualityGroup(
SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
.setId(DYNAMIC_ALL_OPTIONAL_ID)
@@ -454,7 +599,15 @@ class SafetySourceTest {
.setSearchTermsResId(REFERENCE_RES_ID)
.setLoggingAllowed(true)
.setRefreshOnPageOpenAllowed(true)
- .build())
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup(DEDUPLICATION_GROUP)
+ addPackageCertificateHash(HASH1)
+ }
+ }
+ .build()
+ )
.addEqualityGroup(
SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
.setId(DYNAMIC_ALL_OPTIONAL_ID)
@@ -469,7 +622,117 @@ class SafetySourceTest {
.setSearchTermsResId(REFERENCE_RES_ID)
.setLoggingAllowed(false)
.setRefreshOnPageOpenAllowed(false)
- .build())
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup(DEDUPLICATION_GROUP)
+ addPackageCertificateHash(HASH1)
+ }
+ }
+ .build()
+ )
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ addEqualityGroup(
+ SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
+ .setId(DYNAMIC_ALL_OPTIONAL_ID)
+ .setPackageName(PACKAGE_NAME)
+ .setTitleResId(REFERENCE_RES_ID)
+ .setTitleForWorkResId(REFERENCE_RES_ID)
+ .setSummaryResId(REFERENCE_RES_ID)
+ .setIntentAction(INTENT_ACTION)
+ .setProfile(SafetySource.PROFILE_ALL)
+ .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
+ .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
+ .setSearchTermsResId(REFERENCE_RES_ID)
+ .setLoggingAllowed(false)
+ .setRefreshOnPageOpenAllowed(true)
+ .setNotificationsAllowed(false)
+ .setDeduplicationGroup(DEDUPLICATION_GROUP)
+ .addPackageCertificateHash(HASH1)
+ .build()
+ )
+ addEqualityGroup(
+ SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
+ .setId(DYNAMIC_ALL_OPTIONAL_ID)
+ .setPackageName(PACKAGE_NAME)
+ .setTitleResId(REFERENCE_RES_ID)
+ .setTitleForWorkResId(REFERENCE_RES_ID)
+ .setSummaryResId(REFERENCE_RES_ID)
+ .setIntentAction(INTENT_ACTION)
+ .setProfile(SafetySource.PROFILE_ALL)
+ .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
+ .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
+ .setSearchTermsResId(REFERENCE_RES_ID)
+ .setLoggingAllowed(false)
+ .setRefreshOnPageOpenAllowed(true)
+ .setNotificationsAllowed(true)
+ .setDeduplicationGroup("other_deduplication_group")
+ .addPackageCertificateHash(HASH1)
+ .build()
+ )
+ // With no package cert hashes provided
+ addEqualityGroup(
+ SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
+ .setId(DYNAMIC_ALL_OPTIONAL_ID)
+ .setPackageName(PACKAGE_NAME)
+ .setTitleResId(REFERENCE_RES_ID)
+ .setTitleForWorkResId(REFERENCE_RES_ID)
+ .setSummaryResId(REFERENCE_RES_ID)
+ .setIntentAction(INTENT_ACTION)
+ .setProfile(SafetySource.PROFILE_ALL)
+ .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
+ .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
+ .setSearchTermsResId(REFERENCE_RES_ID)
+ .setLoggingAllowed(false)
+ .setRefreshOnPageOpenAllowed(true)
+ .setNotificationsAllowed(true)
+ .setDeduplicationGroup(DEDUPLICATION_GROUP)
+ .build()
+ )
+ // With longer package cert hash list
+ addEqualityGroup(
+ SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
+ .setId(DYNAMIC_ALL_OPTIONAL_ID)
+ .setPackageName(PACKAGE_NAME)
+ .setTitleResId(REFERENCE_RES_ID)
+ .setTitleForWorkResId(REFERENCE_RES_ID)
+ .setSummaryResId(REFERENCE_RES_ID)
+ .setIntentAction(INTENT_ACTION)
+ .setProfile(SafetySource.PROFILE_ALL)
+ .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
+ .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
+ .setSearchTermsResId(REFERENCE_RES_ID)
+ .setLoggingAllowed(false)
+ .setRefreshOnPageOpenAllowed(true)
+ .setNotificationsAllowed(true)
+ .setDeduplicationGroup(DEDUPLICATION_GROUP)
+ .addPackageCertificateHash(HASH1)
+ .addPackageCertificateHash(HASH2)
+ .build()
+ )
+ // With package cert hash list with different value
+ addEqualityGroup(
+ SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
+ .setId(DYNAMIC_ALL_OPTIONAL_ID)
+ .setPackageName(PACKAGE_NAME)
+ .setTitleResId(REFERENCE_RES_ID)
+ .setTitleForWorkResId(REFERENCE_RES_ID)
+ .setSummaryResId(REFERENCE_RES_ID)
+ .setIntentAction(INTENT_ACTION)
+ .setProfile(SafetySource.PROFILE_ALL)
+ .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
+ .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
+ .setSearchTermsResId(REFERENCE_RES_ID)
+ .setLoggingAllowed(false)
+ .setRefreshOnPageOpenAllowed(true)
+ .setNotificationsAllowed(true)
+ .setDeduplicationGroup(DEDUPLICATION_GROUP)
+ .addPackageCertificateHash(HASH2)
+ .build()
+ )
+ }
+ }
.test()
}
@@ -488,6 +751,9 @@ class SafetySourceTest {
private const val STATIC_ALL_OPTIONAL_ID = "static_all_optional"
private const val ISSUE_ONLY_BAREBONE_ID = "issue_only_barebone"
private const val ISSUE_ONLY_ALL_OPTIONAL_ID = "issue_only_all_optional"
+ private const val DEDUPLICATION_GROUP = "deduplication_group"
+ private const val HASH1 = "feed1"
+ private const val HASH2 = "feed2"
internal val DYNAMIC_BAREBONE =
SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
@@ -499,7 +765,7 @@ class SafetySourceTest {
.setProfile(SafetySource.PROFILE_PRIMARY)
.build()
- private val DYNAMIC_ALL_OPTIONAL =
+ private fun dynamicAllOptional(): SafetySource =
SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
.setId(DYNAMIC_ALL_OPTIONAL_ID)
.setPackageName(PACKAGE_NAME)
@@ -513,6 +779,13 @@ class SafetySourceTest {
.setSearchTermsResId(REFERENCE_RES_ID)
.setLoggingAllowed(false)
.setRefreshOnPageOpenAllowed(true)
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup(DEDUPLICATION_GROUP)
+ addPackageCertificateHash(HASH1)
+ }
+ }
.build()
private val DYNAMIC_DISABLED =
@@ -557,6 +830,7 @@ class SafetySourceTest {
private val STATIC_ALL_OPTIONAL =
SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_STATIC)
.setId(STATIC_ALL_OPTIONAL_ID)
+ .apply { if (SdkLevel.isAtLeastU()) setPackageName(PACKAGE_NAME) }
.setTitleResId(REFERENCE_RES_ID)
.setTitleForWorkResId(REFERENCE_RES_ID)
.setSummaryResId(REFERENCE_RES_ID)
@@ -572,7 +846,7 @@ class SafetySourceTest {
.setProfile(SafetySource.PROFILE_PRIMARY)
.build()
- private val ISSUE_ONLY_ALL_OPTIONAL =
+ private fun issueOnlyAllOptional(): SafetySource =
SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY)
.setId(ISSUE_ONLY_ALL_OPTIONAL_ID)
.setPackageName(PACKAGE_NAME)
@@ -580,6 +854,14 @@ class SafetySourceTest {
.setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
.setLoggingAllowed(false)
.setRefreshOnPageOpenAllowed(true)
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup(DEDUPLICATION_GROUP)
+ addPackageCertificateHash(HASH1)
+ addPackageCertificateHash(HASH2)
+ }
+ }
.build()
}
}
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 0ecaadff9..015d18842 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourcesGroupTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourcesGroupTest.kt
@@ -17,128 +17,344 @@
package android.safetycenter.cts.config
import android.content.res.Resources
-import android.os.Build.VERSION_CODES.TIRAMISU
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.safetycenter.config.SafetySourcesGroup
-import android.safetycenter.cts.testing.EqualsHashCodeToStringTester
+import androidx.annotation.RequiresApi
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.ext.truth.os.ParcelableSubject.assertThat
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.assertFailsWith
import org.junit.Test
import org.junit.runner.RunWith
/** CTS tests for [SafetySourcesGroup]. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class SafetySourcesGroupTest {
@Test
fun getType_returnsType() {
- assertThat(COLLAPSIBLE_WITH_SUMMARY.type)
- .isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_COLLAPSIBLE)
- assertThat(COLLAPSIBLE_WITH_ICON.type)
- .isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_COLLAPSIBLE)
- assertThat(COLLAPSIBLE_WITH_BOTH.type)
- .isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_COLLAPSIBLE)
- assertThat(RIGID.type).isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_RIGID)
- assertThat(HIDDEN.type).isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_HIDDEN)
+ assertThat(STATEFUL_INFERRED_WITH_SUMMARY.type)
+ .isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATEFUL)
+ assertThat(STATEFUL_INFERRED_WITH_ICON.type)
+ .isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATEFUL)
+ assertThat(STATEFUL_INFERRED_WITH_BOTH.type)
+ .isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATEFUL)
+ assertThat(STATELESS_INFERRED.type)
+ .isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATELESS)
+ assertThat(HIDDEN_INFERRED.type)
+ .isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_HIDDEN)
+ if (SdkLevel.isAtLeastU()) {
+ assertThat(STATEFUL_BAREBONE.type)
+ .isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATEFUL)
+ assertThat(STATEFUL_ALL_OPTIONAL.type)
+ .isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATEFUL)
+ assertThat(STATELESS_BAREBONE.type)
+ .isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATELESS)
+ assertThat(STATELESS_ALL_OPTIONAL.type)
+ .isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATELESS)
+ assertThat(HIDDEN_BAREBONE.type)
+ .isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_HIDDEN)
+ assertThat(HIDDEN_ALL_OPTIONAL.type)
+ .isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_HIDDEN)
+ }
}
@Test
fun getId_returnsId() {
- assertThat(COLLAPSIBLE_WITH_SUMMARY.id).isEqualTo(COLLAPSIBLE_WITH_SUMMARY_ID)
- assertThat(COLLAPSIBLE_WITH_ICON.id).isEqualTo(COLLAPSIBLE_WITH_ICON_ID)
- assertThat(COLLAPSIBLE_WITH_BOTH.id).isEqualTo(COLLAPSIBLE_WITH_BOTH_ID)
- assertThat(RIGID.id).isEqualTo(RIGID_ID)
- assertThat(HIDDEN.id).isEqualTo(HIDDEN_ID)
+ assertThat(STATEFUL_INFERRED_WITH_SUMMARY.id).isEqualTo(STATEFUL_INFERRED_WITH_SUMMARY_ID)
+ assertThat(STATEFUL_INFERRED_WITH_ICON.id).isEqualTo(STATEFUL_INFERRED_WITH_ICON_ID)
+ assertThat(STATEFUL_INFERRED_WITH_BOTH.id).isEqualTo(STATEFUL_INFERRED_WITH_BOTH_ID)
+ assertThat(STATELESS_INFERRED.id).isEqualTo(STATELESS_INFERRED_ID)
+ assertThat(HIDDEN_INFERRED.id).isEqualTo(HIDDEN_INFERRED_ID)
+ if (SdkLevel.isAtLeastU()) {
+ assertThat(STATEFUL_BAREBONE.id).isEqualTo(STATEFUL_BAREBONE_ID)
+ assertThat(STATEFUL_ALL_OPTIONAL.id).isEqualTo(STATEFUL_ALL_OPTIONAL_ID)
+ assertThat(STATELESS_BAREBONE.id).isEqualTo(STATELESS_BAREBONE_ID)
+ assertThat(STATELESS_ALL_OPTIONAL.id).isEqualTo(STATELESS_ALL_OPTIONAL_ID)
+ assertThat(HIDDEN_BAREBONE.id).isEqualTo(HIDDEN_BAREBONE_ID)
+ assertThat(HIDDEN_ALL_OPTIONAL.id).isEqualTo(HIDDEN_ALL_OPTIONAL_ID)
+ }
}
@Test
fun getTitleResId_returnsTitleResId() {
- assertThat(COLLAPSIBLE_WITH_SUMMARY.titleResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(COLLAPSIBLE_WITH_ICON.titleResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(COLLAPSIBLE_WITH_BOTH.titleResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(RIGID.titleResId).isEqualTo(REFERENCE_RES_ID)
+ assertThat(STATEFUL_INFERRED_WITH_SUMMARY.titleResId).isEqualTo(REFERENCE_RES_ID)
+ assertThat(STATEFUL_INFERRED_WITH_ICON.titleResId).isEqualTo(REFERENCE_RES_ID)
+ assertThat(STATEFUL_INFERRED_WITH_BOTH.titleResId).isEqualTo(REFERENCE_RES_ID)
+ assertThat(STATELESS_INFERRED.titleResId).isEqualTo(REFERENCE_RES_ID)
// This is not an enforced invariant, titleResId should just be ignored for hidden groups
- assertThat(HIDDEN.titleResId).isEqualTo(Resources.ID_NULL)
+ assertThat(HIDDEN_INFERRED.titleResId).isEqualTo(Resources.ID_NULL)
+ if (SdkLevel.isAtLeastU()) {
+ assertThat(STATEFUL_BAREBONE.titleResId).isEqualTo(REFERENCE_RES_ID)
+ assertThat(STATEFUL_ALL_OPTIONAL.titleResId).isEqualTo(REFERENCE_RES_ID)
+ assertThat(STATELESS_BAREBONE.titleResId).isEqualTo(REFERENCE_RES_ID)
+ assertThat(STATELESS_ALL_OPTIONAL.titleResId).isEqualTo(REFERENCE_RES_ID)
+ assertThat(HIDDEN_BAREBONE.titleResId).isEqualTo(Resources.ID_NULL)
+ assertThat(HIDDEN_ALL_OPTIONAL.titleResId).isEqualTo(REFERENCE_RES_ID)
+ }
}
@Test
fun getSummaryResId_returnsSummaryResId() {
- assertThat(COLLAPSIBLE_WITH_SUMMARY.summaryResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(COLLAPSIBLE_WITH_ICON.summaryResId).isEqualTo(Resources.ID_NULL)
- assertThat(COLLAPSIBLE_WITH_BOTH.summaryResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(RIGID.summaryResId).isEqualTo(Resources.ID_NULL)
+ assertThat(STATEFUL_INFERRED_WITH_SUMMARY.summaryResId).isEqualTo(REFERENCE_RES_ID)
+ assertThat(STATEFUL_INFERRED_WITH_ICON.summaryResId).isEqualTo(Resources.ID_NULL)
+ assertThat(STATEFUL_INFERRED_WITH_BOTH.summaryResId).isEqualTo(REFERENCE_RES_ID)
+ assertThat(STATELESS_INFERRED.summaryResId).isEqualTo(Resources.ID_NULL)
// This is not an enforced invariant, summaryResId should just be ignored for hidden groups
- assertThat(HIDDEN.summaryResId).isEqualTo(Resources.ID_NULL)
+ assertThat(HIDDEN_INFERRED.summaryResId).isEqualTo(Resources.ID_NULL)
+ if (SdkLevel.isAtLeastU()) {
+ assertThat(STATEFUL_BAREBONE.titleResId).isEqualTo(REFERENCE_RES_ID)
+ assertThat(STATEFUL_ALL_OPTIONAL.titleResId).isEqualTo(REFERENCE_RES_ID)
+ assertThat(STATELESS_BAREBONE.titleResId).isEqualTo(REFERENCE_RES_ID)
+ assertThat(STATELESS_ALL_OPTIONAL.titleResId).isEqualTo(REFERENCE_RES_ID)
+ assertThat(HIDDEN_BAREBONE.titleResId).isEqualTo(Resources.ID_NULL)
+ assertThat(HIDDEN_ALL_OPTIONAL.titleResId).isEqualTo(REFERENCE_RES_ID)
+ }
}
@Test
fun getStatelessIconType_returnsStatelessIconType() {
- assertThat(COLLAPSIBLE_WITH_SUMMARY.statelessIconType)
+ assertThat(STATEFUL_INFERRED_WITH_SUMMARY.statelessIconType)
.isEqualTo(SafetySourcesGroup.STATELESS_ICON_TYPE_NONE)
- assertThat(COLLAPSIBLE_WITH_ICON.statelessIconType)
+ assertThat(STATEFUL_INFERRED_WITH_ICON.statelessIconType)
.isEqualTo(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
- assertThat(COLLAPSIBLE_WITH_BOTH.statelessIconType)
+ assertThat(STATEFUL_INFERRED_WITH_BOTH.statelessIconType)
.isEqualTo(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
- assertThat(RIGID.statelessIconType).isEqualTo(SafetySourcesGroup.STATELESS_ICON_TYPE_NONE)
+ assertThat(STATELESS_INFERRED.statelessIconType)
+ .isEqualTo(SafetySourcesGroup.STATELESS_ICON_TYPE_NONE)
// This is not an enforced invariant
// statelessIconType should just be ignored for hidden groups
- assertThat(HIDDEN.statelessIconType).isEqualTo(SafetySourcesGroup.STATELESS_ICON_TYPE_NONE)
+ assertThat(HIDDEN_INFERRED.statelessIconType)
+ .isEqualTo(SafetySourcesGroup.STATELESS_ICON_TYPE_NONE)
+ if (SdkLevel.isAtLeastU()) {
+ assertThat(STATEFUL_BAREBONE.statelessIconType)
+ .isEqualTo(SafetySourcesGroup.STATELESS_ICON_TYPE_NONE)
+ assertThat(STATEFUL_ALL_OPTIONAL.statelessIconType)
+ .isEqualTo(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
+ assertThat(STATELESS_BAREBONE.statelessIconType)
+ .isEqualTo(SafetySourcesGroup.STATELESS_ICON_TYPE_NONE)
+ assertThat(STATELESS_ALL_OPTIONAL.statelessIconType)
+ .isEqualTo(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
+ assertThat(HIDDEN_BAREBONE.statelessIconType)
+ .isEqualTo(SafetySourcesGroup.STATELESS_ICON_TYPE_NONE)
+ assertThat(HIDDEN_ALL_OPTIONAL.statelessIconType)
+ .isEqualTo(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
+ }
}
@Test
fun getSafetySources_returnsSafetySources() {
- assertThat(COLLAPSIBLE_WITH_SUMMARY.safetySources)
+ assertThat(STATEFUL_INFERRED_WITH_SUMMARY.safetySources)
.containsExactly(SafetySourceTest.DYNAMIC_BAREBONE)
- assertThat(COLLAPSIBLE_WITH_ICON.safetySources)
+ assertThat(STATEFUL_INFERRED_WITH_ICON.safetySources)
.containsExactly(SafetySourceTest.STATIC_BAREBONE)
- assertThat(COLLAPSIBLE_WITH_BOTH.safetySources)
+ assertThat(STATEFUL_INFERRED_WITH_BOTH.safetySources)
.containsExactly(
SafetySourceTest.DYNAMIC_BAREBONE,
SafetySourceTest.STATIC_BAREBONE,
- SafetySourceTest.ISSUE_ONLY_BAREBONE)
+ SafetySourceTest.ISSUE_ONLY_BAREBONE
+ )
.inOrder()
- assertThat(RIGID.safetySources).containsExactly(SafetySourceTest.STATIC_BAREBONE)
- assertThat(HIDDEN.safetySources).containsExactly(SafetySourceTest.ISSUE_ONLY_BAREBONE)
+ assertThat(STATELESS_INFERRED.safetySources)
+ .containsExactly(SafetySourceTest.STATIC_BAREBONE)
+ assertThat(HIDDEN_INFERRED.safetySources)
+ .containsExactly(SafetySourceTest.ISSUE_ONLY_BAREBONE)
+ if (SdkLevel.isAtLeastU()) {
+ assertThat(STATEFUL_BAREBONE.safetySources)
+ .containsExactly(SafetySourceTest.DYNAMIC_BAREBONE)
+ assertThat(STATEFUL_ALL_OPTIONAL.safetySources)
+ .containsExactly(
+ SafetySourceTest.DYNAMIC_BAREBONE,
+ SafetySourceTest.STATIC_BAREBONE,
+ SafetySourceTest.ISSUE_ONLY_BAREBONE
+ )
+ assertThat(STATELESS_BAREBONE.safetySources)
+ .containsExactly(SafetySourceTest.STATIC_BAREBONE)
+ assertThat(STATELESS_ALL_OPTIONAL.safetySources)
+ .containsExactly(
+ SafetySourceTest.DYNAMIC_BAREBONE,
+ SafetySourceTest.STATIC_BAREBONE,
+ SafetySourceTest.ISSUE_ONLY_BAREBONE
+ )
+ assertThat(HIDDEN_BAREBONE.safetySources)
+ .containsExactly(SafetySourceTest.ISSUE_ONLY_BAREBONE)
+ assertThat(HIDDEN_ALL_OPTIONAL.safetySources)
+ .containsExactly(SafetySourceTest.ISSUE_ONLY_BAREBONE)
+ }
+ }
+
+ @Test
+ fun getSafetySources_mutationsAreNotAllowed() {
+ val sources = STATEFUL_INFERRED_WITH_SUMMARY.safetySources
+
+ assertFailsWith(UnsupportedOperationException::class) {
+ sources.add(SafetySourceTest.DYNAMIC_BAREBONE)
+ }
+ }
+
+ @Test
+ fun builder_addSafetySource_doesNotMutatePreviouslyBuiltInstance() {
+ val safetySourcesGroupBuilder =
+ SafetySourcesGroup.Builder()
+ .setId(STATEFUL_INFERRED_WITH_SUMMARY_ID)
+ .setTitleResId(REFERENCE_RES_ID)
+ .setSummaryResId(REFERENCE_RES_ID)
+ .addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
+ val sources = safetySourcesGroupBuilder.build().safetySources
+
+ safetySourcesGroupBuilder.addSafetySource(SafetySourceTest.STATIC_BAREBONE)
+
+ assertThat(sources).containsExactly(SafetySourceTest.DYNAMIC_BAREBONE)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun build_hiddenGroupWithDynamicSource_throwsIllegalStateException() {
+ val builder =
+ SafetySourcesGroup.Builder()
+ .setType(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_HIDDEN)
+ .setId(HIDDEN_BAREBONE_ID)
+ .addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
+
+ val exception = assertFailsWith(IllegalStateException::class) { builder.build() }
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo(
+ "Safety sources groups of type hidden can only contain sources of type issue-only"
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun build_hiddenGroupWithStaticSource_throwsIllegalStateException() {
+ val builder =
+ SafetySourcesGroup.Builder()
+ .setType(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_HIDDEN)
+ .setId(HIDDEN_BAREBONE_ID)
+ .addSafetySource(SafetySourceTest.STATIC_BAREBONE)
+
+ val exception = assertFailsWith(IllegalStateException::class) { builder.build() }
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo(
+ "Safety sources groups of type hidden can only contain sources of type issue-only"
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun build_statefulGroupWithIssueOnlySource_throwsIllegalStateException() {
+ val builder =
+ SafetySourcesGroup.Builder()
+ .setType(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATEFUL)
+ .setId(STATEFUL_BAREBONE_ID)
+ .setTitleResId(REFERENCE_RES_ID)
+ .addSafetySource(SafetySourceTest.ISSUE_ONLY_BAREBONE)
+
+ val exception = assertFailsWith(IllegalStateException::class) { builder.build() }
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo(
+ "Safety sources groups containing only sources of type issue-only must be of " +
+ "type hidden"
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun build_statelessGroupWithIssueOnlySource_throwsIllegalStateException() {
+ val builder =
+ SafetySourcesGroup.Builder()
+ .setType(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATELESS)
+ .setId(STATELESS_BAREBONE_ID)
+ .setTitleResId(REFERENCE_RES_ID)
+ .addSafetySource(SafetySourceTest.ISSUE_ONLY_BAREBONE)
+
+ val exception = assertFailsWith(IllegalStateException::class) { builder.build() }
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo(
+ "Safety sources groups containing only sources of type issue-only must be of " +
+ "type hidden"
+ )
}
@Test
fun describeContents_returns0() {
- assertThat(COLLAPSIBLE_WITH_SUMMARY.describeContents()).isEqualTo(0)
- assertThat(COLLAPSIBLE_WITH_ICON.describeContents()).isEqualTo(0)
- assertThat(COLLAPSIBLE_WITH_BOTH.describeContents()).isEqualTo(0)
- assertThat(RIGID.describeContents()).isEqualTo(0)
- assertThat(HIDDEN.describeContents()).isEqualTo(0)
+ assertThat(STATEFUL_INFERRED_WITH_SUMMARY.describeContents()).isEqualTo(0)
+ assertThat(STATEFUL_INFERRED_WITH_ICON.describeContents()).isEqualTo(0)
+ assertThat(STATEFUL_INFERRED_WITH_BOTH.describeContents()).isEqualTo(0)
+ assertThat(STATELESS_INFERRED.describeContents()).isEqualTo(0)
+ assertThat(HIDDEN_INFERRED.describeContents()).isEqualTo(0)
+ if (SdkLevel.isAtLeastU()) {
+ assertThat(STATEFUL_BAREBONE.describeContents()).isEqualTo(0)
+ assertThat(STATEFUL_ALL_OPTIONAL.describeContents()).isEqualTo(0)
+ assertThat(STATELESS_BAREBONE.describeContents()).isEqualTo(0)
+ assertThat(STATELESS_ALL_OPTIONAL.describeContents()).isEqualTo(0)
+ assertThat(HIDDEN_BAREBONE.describeContents()).isEqualTo(0)
+ assertThat(HIDDEN_ALL_OPTIONAL.describeContents()).isEqualTo(0)
+ }
}
@Test
fun parcelRoundTrip_recreatesEqual() {
- assertThat(COLLAPSIBLE_WITH_SUMMARY).recreatesEqual(SafetySourcesGroup.CREATOR)
- assertThat(COLLAPSIBLE_WITH_ICON).recreatesEqual(SafetySourcesGroup.CREATOR)
- assertThat(COLLAPSIBLE_WITH_BOTH).recreatesEqual(SafetySourcesGroup.CREATOR)
- assertThat(RIGID).recreatesEqual(SafetySourcesGroup.CREATOR)
- assertThat(HIDDEN).recreatesEqual(SafetySourcesGroup.CREATOR)
+ assertThat(STATEFUL_INFERRED_WITH_SUMMARY).recreatesEqual(SafetySourcesGroup.CREATOR)
+ assertThat(STATEFUL_INFERRED_WITH_ICON).recreatesEqual(SafetySourcesGroup.CREATOR)
+ assertThat(STATEFUL_INFERRED_WITH_BOTH).recreatesEqual(SafetySourcesGroup.CREATOR)
+ assertThat(STATELESS_INFERRED).recreatesEqual(SafetySourcesGroup.CREATOR)
+ assertThat(HIDDEN_INFERRED).recreatesEqual(SafetySourcesGroup.CREATOR)
+ if (SdkLevel.isAtLeastU()) {
+ assertThat(STATEFUL_BAREBONE).recreatesEqual(SafetySourcesGroup.CREATOR)
+ assertThat(STATEFUL_ALL_OPTIONAL).recreatesEqual(SafetySourcesGroup.CREATOR)
+ assertThat(STATELESS_BAREBONE).recreatesEqual(SafetySourcesGroup.CREATOR)
+ assertThat(STATELESS_ALL_OPTIONAL).recreatesEqual(SafetySourcesGroup.CREATOR)
+ assertThat(HIDDEN_BAREBONE).recreatesEqual(SafetySourcesGroup.CREATOR)
+ assertThat(HIDDEN_ALL_OPTIONAL).recreatesEqual(SafetySourcesGroup.CREATOR)
+ }
}
@Test
fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() {
- EqualsHashCodeToStringTester()
- .addEqualityGroup(COLLAPSIBLE_WITH_SUMMARY)
- .addEqualityGroup(COLLAPSIBLE_WITH_ICON)
+ EqualsHashCodeToStringTester.ofParcelable(
+ parcelableCreator = SafetySourcesGroup.CREATOR,
+ createCopy =
+ if (SdkLevel.isAtLeastU()) {
+ { SafetySourcesGroup.Builder(it).build() }
+ } else {
+ null
+ }
+ )
+ .addEqualityGroup(STATEFUL_INFERRED_WITH_SUMMARY)
+ .addEqualityGroup(STATEFUL_INFERRED_WITH_ICON)
.addEqualityGroup(
- COLLAPSIBLE_WITH_BOTH,
- SafetySourcesGroup.Builder()
- .setId(COLLAPSIBLE_WITH_BOTH_ID)
- .setTitleResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
- .addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
- .addSafetySource(SafetySourceTest.STATIC_BAREBONE)
- .addSafetySource(SafetySourceTest.ISSUE_ONLY_BAREBONE)
- .build())
- .addEqualityGroup(RIGID)
- .addEqualityGroup(HIDDEN)
+ *mutableListOf(
+ STATEFUL_INFERRED_WITH_BOTH,
+ SafetySourcesGroup.Builder()
+ .setId(STATEFUL_INFERRED_WITH_BOTH_ID)
+ .setTitleResId(REFERENCE_RES_ID)
+ .setSummaryResId(REFERENCE_RES_ID)
+ .setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
+ .addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
+ .addSafetySource(SafetySourceTest.STATIC_BAREBONE)
+ .addSafetySource(SafetySourceTest.ISSUE_ONLY_BAREBONE)
+ .build()
+ )
+ .apply { if (SdkLevel.isAtLeastU()) add(STATEFUL_ALL_OPTIONAL) }
+ .toTypedArray()
+ )
+ .addEqualityGroup(
+ *mutableListOf(STATELESS_INFERRED)
+ .apply { if (SdkLevel.isAtLeastU()) add(STATELESS_BAREBONE) }
+ .toTypedArray()
+ )
+ .addEqualityGroup(
+ *mutableListOf(HIDDEN_INFERRED)
+ .apply { if (SdkLevel.isAtLeastU()) add(HIDDEN_BAREBONE) }
+ .toTypedArray()
+ )
.addEqualityGroup(
SafetySourcesGroup.Builder()
.setId("other")
@@ -146,70 +362,89 @@ class SafetySourcesGroupTest {
.setSummaryResId(REFERENCE_RES_ID)
.setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
.addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySourcesGroup.Builder()
- .setId(COLLAPSIBLE_WITH_BOTH_ID)
+ .setId(STATEFUL_INFERRED_WITH_BOTH_ID)
.setTitleResId(-1)
.setSummaryResId(REFERENCE_RES_ID)
.setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
.addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySourcesGroup.Builder()
- .setId(COLLAPSIBLE_WITH_BOTH_ID)
+ .setId(STATEFUL_INFERRED_WITH_BOTH_ID)
.setTitleResId(REFERENCE_RES_ID)
.setSummaryResId(-1)
.setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
.addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySourcesGroup.Builder()
- .setId(COLLAPSIBLE_WITH_BOTH_ID)
+ .setId(STATEFUL_INFERRED_WITH_BOTH_ID)
.setTitleResId(REFERENCE_RES_ID)
.setSummaryResId(REFERENCE_RES_ID)
.setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_NONE)
.addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
- .build())
+ .build()
+ )
.addEqualityGroup(
SafetySourcesGroup.Builder()
- .setId(COLLAPSIBLE_WITH_BOTH_ID)
+ .setId(STATEFUL_INFERRED_WITH_BOTH_ID)
.setTitleResId(REFERENCE_RES_ID)
.setSummaryResId(REFERENCE_RES_ID)
.setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
.addSafetySource(SafetySourceTest.STATIC_BAREBONE)
- .build())
+ .build()
+ )
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ addEqualityGroup(STATEFUL_BAREBONE)
+ addEqualityGroup(STATELESS_ALL_OPTIONAL)
+ addEqualityGroup(HIDDEN_ALL_OPTIONAL)
+ }
+ }
.test()
}
companion object {
private const val REFERENCE_RES_ID = 9999
- private const val COLLAPSIBLE_WITH_SUMMARY_ID = "collapsible_with_summary"
- private const val COLLAPSIBLE_WITH_ICON_ID = "collapsible_with_icon"
- private const val COLLAPSIBLE_WITH_BOTH_ID = "collapsible_with_both"
- private const val RIGID_ID = "rigid"
- private const val HIDDEN_ID = "hidden"
+ private const val STATEFUL_BAREBONE_ID = "stateful_barebone"
+ private const val STATEFUL_ALL_OPTIONAL_ID = "stateful_all_optional"
+ private const val STATELESS_BAREBONE_ID = "stateless_barebone"
+ private const val STATELESS_ALL_OPTIONAL_ID = "stateless_all_optional"
+ private const val HIDDEN_BAREBONE_ID = "hidden_barebone"
+ private const val HIDDEN_ALL_OPTIONAL_ID = "hidden_all_optional"
+ private const val STATEFUL_INFERRED_WITH_SUMMARY_ID = "stateful_inferred_with_summary"
+ private const val STATEFUL_INFERRED_WITH_ICON_ID = "stateful_inferred_with_icon"
+ private const val STATEFUL_INFERRED_WITH_BOTH_ID = STATEFUL_ALL_OPTIONAL_ID
+ private const val STATELESS_INFERRED_ID = STATELESS_BAREBONE_ID
+ private const val HIDDEN_INFERRED_ID = HIDDEN_BAREBONE_ID
- private val COLLAPSIBLE_WITH_SUMMARY =
+ // TODO(b/230078826): Consider extracting shared constants to a separate file.
+ internal val STATEFUL_INFERRED_WITH_SUMMARY =
SafetySourcesGroup.Builder()
- .setId(COLLAPSIBLE_WITH_SUMMARY_ID)
+ .setId(STATEFUL_INFERRED_WITH_SUMMARY_ID)
.setTitleResId(REFERENCE_RES_ID)
.setSummaryResId(REFERENCE_RES_ID)
.addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
.build()
- private val COLLAPSIBLE_WITH_ICON =
+ private val STATEFUL_INFERRED_WITH_ICON =
SafetySourcesGroup.Builder()
- .setId(COLLAPSIBLE_WITH_ICON_ID)
+ .setId(STATEFUL_INFERRED_WITH_ICON_ID)
.setTitleResId(REFERENCE_RES_ID)
.setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
.addSafetySource(SafetySourceTest.STATIC_BAREBONE)
.build()
- private val COLLAPSIBLE_WITH_BOTH =
+ private val STATEFUL_INFERRED_WITH_BOTH =
SafetySourcesGroup.Builder()
- .setId(COLLAPSIBLE_WITH_BOTH_ID)
+ .setId(STATEFUL_INFERRED_WITH_BOTH_ID)
.setTitleResId(REFERENCE_RES_ID)
.setSummaryResId(REFERENCE_RES_ID)
.setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
@@ -218,17 +453,86 @@ class SafetySourcesGroupTest {
.addSafetySource(SafetySourceTest.ISSUE_ONLY_BAREBONE)
.build()
- internal val RIGID =
+ private val STATEFUL_BAREBONE: SafetySourcesGroup
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ get() =
+ SafetySourcesGroup.Builder()
+ .setType(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATEFUL)
+ .setId(STATEFUL_BAREBONE_ID)
+ .setTitleResId(REFERENCE_RES_ID)
+ .addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
+ .build()
+
+ private val STATEFUL_ALL_OPTIONAL: SafetySourcesGroup
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ get() =
+ SafetySourcesGroup.Builder()
+ .setType(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATEFUL)
+ .setId(STATEFUL_ALL_OPTIONAL_ID)
+ .setTitleResId(REFERENCE_RES_ID)
+ .setSummaryResId(REFERENCE_RES_ID)
+ .setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
+ .addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
+ .addSafetySource(SafetySourceTest.STATIC_BAREBONE)
+ .addSafetySource(SafetySourceTest.ISSUE_ONLY_BAREBONE)
+ .build()
+
+ internal val STATELESS_INFERRED =
SafetySourcesGroup.Builder()
- .setId(RIGID_ID)
+ .setId(STATELESS_INFERRED_ID)
.setTitleResId(REFERENCE_RES_ID)
.addSafetySource(SafetySourceTest.STATIC_BAREBONE)
.build()
- internal val HIDDEN =
+ private val STATELESS_BAREBONE: SafetySourcesGroup
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ get() =
+ SafetySourcesGroup.Builder()
+ .setType(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATELESS)
+ .setId(STATELESS_BAREBONE_ID)
+ .setTitleResId(REFERENCE_RES_ID)
+ .addSafetySource(SafetySourceTest.STATIC_BAREBONE)
+ .build()
+
+ private val STATELESS_ALL_OPTIONAL: SafetySourcesGroup
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ get() =
+ SafetySourcesGroup.Builder()
+ .setType(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATELESS)
+ .setId(STATELESS_ALL_OPTIONAL_ID)
+ .setTitleResId(REFERENCE_RES_ID)
+ .setSummaryResId(REFERENCE_RES_ID)
+ .setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
+ .addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
+ .addSafetySource(SafetySourceTest.STATIC_BAREBONE)
+ .addSafetySource(SafetySourceTest.ISSUE_ONLY_BAREBONE)
+ .build()
+
+ internal val HIDDEN_INFERRED =
SafetySourcesGroup.Builder()
- .setId(HIDDEN_ID)
+ .setId(HIDDEN_INFERRED_ID)
.addSafetySource(SafetySourceTest.ISSUE_ONLY_BAREBONE)
.build()
+
+ private val HIDDEN_BAREBONE: SafetySourcesGroup
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ get() =
+ SafetySourcesGroup.Builder()
+ .setType(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_HIDDEN)
+ .setId(HIDDEN_BAREBONE_ID)
+ .addSafetySource(SafetySourceTest.ISSUE_ONLY_BAREBONE)
+ .build()
+
+ private val HIDDEN_ALL_OPTIONAL: SafetySourcesGroup
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ get() =
+ SafetySourcesGroup.Builder()
+ .setType(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_HIDDEN)
+ .setId(HIDDEN_ALL_OPTIONAL_ID)
+ .setTitleResId(REFERENCE_RES_ID)
+ .setSummaryResId(REFERENCE_RES_ID)
+ .setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
+ .addSafetySource(SafetySourceTest.ISSUE_ONLY_BAREBONE)
+ .build()
}
}
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 f79d9d649..32959629c 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/config/XmlConfigTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/config/XmlConfigTest.kt
@@ -19,39 +19,61 @@ package android.safetycenter.cts.config
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager.ResolveInfoFlags
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.safetycenter.config.SafetySource
-import android.safetycenter.cts.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
+import android.safetycenter.SafetyCenterManager
+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 androidx.test.filters.SdkSuppress
import com.android.safetycenter.config.SafetyCenterConfigParser
import com.android.safetycenter.resources.SafetyCenterResourcesContext
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.getSafetyCenterConfigWithPermission
+import com.android.safetycenter.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
+import com.android.safetycenter.testing.SafetyCenterTestHelper
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.Test
import org.junit.runner.RunWith
+/** CTS tests for the Safety Center XML config file. */
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class XmlConfigTest {
private val context: Context = getApplicationContext()
- private val safetyCenterContext = SafetyCenterResourcesContext(context)
+ private val safetyCenterContext = SafetyCenterResourcesContext.forTests(context)
+ private val safetyCenterTestHelper = SafetyCenterTestHelper(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(context.deviceSupportsSafetyCenter())
+ assumeTrue(shouldRunTests)
+ }
+
+ @Before
+ fun enableSafetyCenterBeforeTest() {
+ if (!shouldRunTests) {
+ return
+ }
+ safetyCenterTestHelper.setup()
+ }
+
+ @After
+ fun clearDataAfterTest() {
+ if (!shouldRunTests) {
+ return
+ }
+ safetyCenterTestHelper.reset()
}
@Test
fun safetyCenterConfigResource_validConfig() {
- // Assert that the parser validates the Safety Center config without throwing any exception
- assertThat(
- SafetyCenterConfigParser.parseXmlResource(
- safetyCenterContext.safetyCenterConfig!!, safetyCenterContext.resources!!))
- .isNotNull()
+ val parsedSafetyCenterConfig = parseXmlConfig()
+ val safetyCenterConfig = safetyCenterManager.getSafetyCenterConfigWithPermission()
+
+ assertThat(parsedSafetyCenterConfig).isEqualTo(safetyCenterConfig)
}
@Test
@@ -78,18 +100,22 @@ class XmlConfigTest {
}
private fun isIntentInConfig(intentAction: String): Boolean {
- val safetyCenterConfig =
- SafetyCenterConfigParser.parseXmlResource(
- safetyCenterContext.safetyCenterConfig!!, safetyCenterContext.resources!!)
- return safetyCenterConfig.safetySourcesGroups.any { safetySourceGroup ->
- safetySourceGroup.safetySources
- .filter { it.type != SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY }
- .any { it.intentAction == intentAction }
- }
+ val safetyCenterConfig = parseXmlConfig()
+ return safetyCenterConfig.safetySourcesGroups
+ .flatMap { it.safetySources }
+ .filter { it.type != SAFETY_SOURCE_TYPE_ISSUE_ONLY }
+ .any { it.intentAction == intentAction }
}
+ private fun parseXmlConfig() =
+ SafetyCenterConfigParser.parseXmlResource(
+ safetyCenterContext.safetyCenterConfig!!,
+ safetyCenterContext.resources!!
+ )
+
companion object {
- private const val ADVANCED_PRIVACY_INTENT_STRING = "android.settings.PRIVACY_ADVANCED_SETTINGS"
+ private const val ADVANCED_PRIVACY_INTENT_STRING =
+ "android.settings.PRIVACY_ADVANCED_SETTINGS"
private const val PRIVACY_CONTROLS_INTENT_STRING = "android.settings.PRIVACY_CONTROLS"
}
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/testing/Coroutines.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/testing/Coroutines.kt
deleted file mode 100644
index 2604f128e..000000000
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/testing/Coroutines.kt
+++ /dev/null
@@ -1,37 +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 android.safetycenter.cts.testing
-
-import java.time.Duration
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.withTimeout
-
-/** A class that facilitates interacting with coroutines. */
-object Coroutines {
-
- /** Behaves in the same way as [runBlocking], but with a timeout. */
- fun <T> runBlockingWithTimeout(timeout: Duration = TIMEOUT_LONG, block: suspend () -> T) =
- runBlocking {
- withTimeout(timeout.toMillis()) { block() }
- }
-
- /** A long timeout, to be used for actions that are expected to complete. */
- val TIMEOUT_LONG: Duration = Duration.ofSeconds(5)
-
- /** A short timeout, to be used for actions that are expected not to complete. */
- val TIMEOUT_SHORT: Duration = Duration.ofSeconds(1)
-}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/testing/EqualsHashCodeToStringTester.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/testing/EqualsHashCodeToStringTester.kt
deleted file mode 100644
index 0b32f2a13..000000000
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/testing/EqualsHashCodeToStringTester.kt
+++ /dev/null
@@ -1,94 +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 android.safetycenter.cts.testing
-
-import com.google.common.base.Equivalence
-import com.google.common.testing.EqualsTester
-import com.google.common.testing.EquivalenceTester
-
-/**
- * A class similar to [EqualsTester] that also checks that the [Object.hashCode] and
- * [Object.toString] implementations are consistent with equality groups.
- *
- * Note: this class assumes that [Object.hashCode] does not create a collision for equality groups,
- * however this can be disabled by setting [hashCodeCanCollide] to `true`.
- */
-class EqualsHashCodeToStringTester(private val hashCodeCanCollide: Boolean = false) {
- private val equalsTester = EqualsTester()
- private val toStringTester = EquivalenceTester.of(TO_STRING_EQUIVALENCE)
- private val hashCodeTester = EquivalenceTester.of(HASH_CODE_EQUIVALENCE)
-
- fun addEqualityGroup(vararg groups: Any): EqualsHashCodeToStringTester {
- equalsTester.addEqualityGroup(*groups)
- toStringTester.addEquivalenceGroupAsArray(groups)
- if (!hashCodeCanCollide) {
- hashCodeTester.addEquivalenceGroupAsArray(groups)
- }
- return this
- }
-
- private fun EquivalenceTester<Any>.addEquivalenceGroupAsArray(input: Array<out Any>) {
- when (val size = input.size) {
- 0 -> return
- 1 -> addEquivalenceGroup(input[0])
- else -> addEquivalenceGroup(input[0], *input.copyOfRange(1, size))
- }
- }
-
- fun test() {
- equalsTester.testEquals()
- toStringTester.test()
- if (!hashCodeCanCollide) {
- hashCodeTester.test()
- }
- }
-
- companion object {
-
- /**
- * An [Equivalence] that considers two instances of a class equivalent iff [Object.toString]
- * return the same value.
- */
- private val TO_STRING_EQUIVALENCE =
- object : Equivalence<Any>() {
-
- override fun doEquivalent(a: Any, b: Any): Boolean {
- return a.toString() == b.toString()
- }
-
- override fun doHash(o: Any): Int {
- return o.toString().hashCode()
- }
- }
-
- /**
- * An [Equivalence] that considers two instances of a class equivalent iff [Object.hashCode]
- * return the same value.
- */
- private val HASH_CODE_EQUIVALENCE =
- object : Equivalence<Any>() {
-
- override fun doEquivalent(a: Any, b: Any): Boolean {
- return a.hashCode() == b.hashCode()
- }
-
- override fun doHash(o: Any): Int {
- return o.hashCode()
- }
- }
- }
-}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/testing/FakeExecutor.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/testing/FakeExecutor.kt
index a642c88ca..d7943c271 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/testing/FakeExecutor.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/testing/FakeExecutor.kt
@@ -16,8 +16,8 @@
package android.safetycenter.cts.testing
-import android.safetycenter.cts.testing.Coroutines.TIMEOUT_LONG
-import android.safetycenter.cts.testing.Coroutines.runBlockingWithTimeout
+import com.android.safetycenter.testing.Coroutines.TIMEOUT_LONG
+import com.android.safetycenter.testing.Coroutines.runBlockingWithTimeout
import java.time.Duration
import java.util.concurrent.Executor
import kotlinx.coroutines.TimeoutCancellationException
@@ -47,5 +47,6 @@ class FakeExecutor : Executor {
*
* Note: the returned task is not run when returned. Use [Runnable.run] to actually run it.
*/
- fun getNextTask(timeout: Duration = TIMEOUT_LONG) = runBlockingWithTimeout { tasks.receive() }
+ fun getNextTask(timeout: Duration = TIMEOUT_LONG) =
+ runBlockingWithTimeout(timeout) { tasks.receive() }
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetyCenterFlags.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetyCenterFlags.kt
deleted file mode 100644
index 431788c59..000000000
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetyCenterFlags.kt
+++ /dev/null
@@ -1,52 +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 android.safetycenter.cts.testing
-
-import android.Manifest.permission.WRITE_DEVICE_CONFIG
-import android.content.Context
-import android.content.res.Resources
-import android.provider.DeviceConfig
-import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
-
-/** A class that facilitates working with Safety Center flags. */
-object SafetyCenterFlags {
-
- /** Name of the flag that determines whether SafetyCenter is enabled. */
- private const val PROPERTY_SAFETY_CENTER_ENABLED = "safety_center_is_enabled"
-
- /** Returns whether the device supports Safety Center. */
- fun Context.deviceSupportsSafetyCenter() =
- resources.getBoolean(
- Resources.getSystem().getIdentifier("config_enableSafetyCenter", "bool", "android"))
-
- /** Sets the Safety Center device config flag to the given boolean [value]. */
- fun setSafetyCenterEnabled(value: Boolean) {
- callWithShellPermissionIdentity(
- {
- val valueWasSet =
- DeviceConfig.setProperty(
- DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_SAFETY_CENTER_ENABLED,
- /* value = */ value.toString(),
- /* makeDefault = */ false)
- if (!valueWasSet) {
- throw IllegalStateException("Could not set Safety Center flag value to: $value")
- }
- },
- WRITE_DEVICE_CONFIG)
- }
-}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetySourceBroadcastReceiver.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetySourceBroadcastReceiver.kt
deleted file mode 100644
index d6eb00bd8..000000000
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetySourceBroadcastReceiver.kt
+++ /dev/null
@@ -1,88 +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 android.safetycenter.cts.testing
-
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import android.safetycenter.SafetyCenterManager
-import android.safetycenter.SafetyCenterManager.ACTION_REFRESH_SAFETY_SOURCES
-import android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA
-import android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_GET_DATA
-import android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE
-import android.safetycenter.SafetyEvent
-import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED
-import android.safetycenter.SafetySourceData
-import android.safetycenter.cts.testing.Coroutines.TIMEOUT_LONG
-import android.safetycenter.cts.testing.Coroutines.runBlockingWithTimeout
-import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.setSafetySourceDataWithPermission
-import java.time.Duration
-import kotlinx.coroutines.channels.Channel
-import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
-
-/** Broadcast receiver to be used for testing broadcasts sent to safety source apps. */
-class SafetySourceBroadcastReceiver : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent?) {
- if (intent == null) {
- throw IllegalArgumentException("Received null intent")
- }
-
- if (intent.action != ACTION_REFRESH_SAFETY_SOURCES) {
- throw IllegalArgumentException("Received intent with action: ${intent.action}")
- }
-
- val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
-
- when (intent.getIntExtra(EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE, -1)) {
- EXTRA_REFRESH_REQUEST_TYPE_GET_DATA ->
- safetyCenterManager.setSafetySourceDataWithPermission(
- safetySourceId!!, safetySourceDataOnPageOpen!!, EVENT_REFRESH_REQUESTED)
- EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA ->
- safetyCenterManager.setSafetySourceDataWithPermission(
- safetySourceId!!, safetySourceDataOnRescanClick!!, EVENT_REFRESH_REQUESTED)
- }
-
- runBlockingWithTimeout { updateChannel.send(Unit) }
- }
-
- companion object {
- private val EVENT_REFRESH_REQUESTED =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
- .setRefreshBroadcastId("refresh_id")
- .build()
-
- @Volatile private var updateChannel = Channel<Unit>(UNLIMITED)
-
- @Volatile var safetySourceId: String? = null
-
- @Volatile var safetySourceDataOnPageOpen: SafetySourceData? = null
-
- @Volatile var safetySourceDataOnRescanClick: SafetySourceData? = null
-
- fun reset() {
- safetySourceId = null
- safetySourceDataOnRescanClick = null
- safetySourceDataOnPageOpen = null
- updateChannel.cancel()
- updateChannel = Channel()
- }
-
- fun waitTillOnReceiveComplete(timeout: Duration = TIMEOUT_LONG) {
- runBlockingWithTimeout(timeout) { updateChannel.receive() }
- }
- }
-}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/ui/SafetyCenterActivityTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/ui/SafetyCenterActivityTest.kt
new file mode 100644
index 000000000..8fb56b09e
--- /dev/null
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/ui/SafetyCenterActivityTest.kt
@@ -0,0 +1,90 @@
+/*
+ * 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.safetycenter.cts.ui
+
+import android.content.Context
+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.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.SettingsPackage.getSettingsPackageName
+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
+
+/** CTS tests for the Safety Center Activity. */
+@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()
+ }
+
+ @After
+ fun clearDataAfterTest() {
+ if (!shouldRunTests) {
+ return
+ }
+ safetyCenterTestHelper.reset()
+ getUiDevice().resetRotation()
+ }
+
+ @Test
+ fun launchActivity_withFlagEnabled_showsSecurityAndPrivacyTitle() {
+ context.launchSafetyCenterActivity { waitPageTitleDisplayed("Security & privacy") }
+ }
+
+ @Test
+ fun launchActivity_withFlagDisabled_opensSettings() {
+ safetyCenterTestHelper.setEnabled(false)
+
+ context.launchSafetyCenterActivity {
+ waitDisplayed(By.pkg(context.getSettingsPackageName()))
+ }
+ }
+}
diff --git a/tests/functional/safetycenter/OWNERS b/tests/functional/safetycenter/OWNERS
new file mode 100644
index 000000000..5d8b8161b
--- /dev/null
+++ b/tests/functional/safetycenter/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1026964
+
+include /SafetyCenter/OWNERS
diff --git a/tests/functional/safetycenter/multiusers/Android.bp b/tests/functional/safetycenter/multiusers/Android.bp
new file mode 100644
index 000000000..c1c7a95e7
--- /dev/null
+++ b/tests/functional/safetycenter/multiusers/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: "SafetyCenterFunctionalMultiUsersTestCases",
+ 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",
+ "kotlin-test",
+ "safety-center-test-util-lib",
+ "Harrier",
+ "Nene",
+ "TestApp",
+ ],
+ test_suites: [
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/functional/safetycenter/multiusers/AndroidManifest.xml b/tests/functional/safetycenter/multiusers/AndroidManifest.xml
new file mode 100644
index 000000000..225542afd
--- /dev/null
+++ b/tests/functional/safetycenter/multiusers/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.safetycenter.functional.multiusers">
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:label="Functional multi users tests for SafetyCenter"
+ android:targetPackage="android.safetycenter.functional.multiusers"/>
+
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+</manifest>
diff --git a/tests/functional/safetycenter/multiusers/AndroidTest.xml b/tests/functional/safetycenter/multiusers/AndroidTest.xml
new file mode 100644
index 000000000..c1e19d2e4
--- /dev/null
+++ b/tests/functional/safetycenter/multiusers/AndroidTest.xml
@@ -0,0 +1,56 @@
+<?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 functional multi users SafetyCenter test cases">
+
+ <object
+ class="com.android.tradefed.testtype.suite.module.Sdk33ModuleController"
+ 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="no_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="SafetyCenterFunctionalMultiUsersTestCases.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" />
+ <!-- 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" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="android.safetycenter.functional.multiusers"/>
+ <option name="exclude-annotation" value="org.junit.Ignore"/>
+ <option name="runtime-hint" value="5m"/>
+ </test>
+</configuration>
diff --git a/tests/functional/safetycenter/multiusers/TEST_MAPPING b/tests/functional/safetycenter/multiusers/TEST_MAPPING
new file mode 100644
index 000000000..aedf92b86
--- /dev/null
+++ b/tests/functional/safetycenter/multiusers/TEST_MAPPING
@@ -0,0 +1,30 @@
+{
+ "presubmit": [
+ {
+ "name": "SafetyCenterFunctionalMultiUsersTestCases",
+ "options": [
+ {
+ "exclude-annotation": "com.android.bedstead.harrier.annotations.Postsubmit"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
+ "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
new file mode 100644
index 000000000..07ae129ec
--- /dev/null
+++ b/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt
@@ -0,0 +1,1310 @@
+/*
+ * 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.safetycenter.functional.multiusers
+
+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.ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING
+import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN
+import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED
+import android.safetycenter.SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION
+import android.safetycenter.SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY
+import android.safetycenter.SafetyCenterEntryGroup
+import android.safetycenter.SafetyCenterEntryOrGroup
+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 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.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.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.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
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.DYNAMIC_HIDDEN_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.DYNAMIC_IN_STATELESS_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.ISSUE_ONLY_ALL_OPTIONAL_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.ISSUE_ONLY_ALL_PROFILE_SOURCE_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.ISSUE_ONLY_BAREBONE_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.ISSUE_ONLY_GROUP_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.ISSUE_ONLY_IN_STATELESS_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.MIXED_STATELESS_GROUP_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_ALL_PROFILE_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_GROUP_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.STATIC_ALL_OPTIONAL_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.STATIC_BAREBONE_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.STATIC_GROUP_ID
+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.SafetySourceTestData
+import com.android.safetycenter.testing.SafetySourceTestData.Companion.EVENT_SOURCE_STATE_CHANGED
+import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity
+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).
+ */
+@RunWith(BedsteadJUnit4::class)
+class SafetyCenterMultiUsersTest {
+
+ companion object {
+ @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 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 dynamicBareboneDefault =
+ safetyCenterTestData.safetyCenterEntryDefault(DYNAMIC_BAREBONE_ID)
+
+ private val dynamicBareboneUpdated =
+ safetyCenterTestData.safetyCenterEntryCritical(DYNAMIC_BAREBONE_ID)
+
+ private val dynamicDisabledDefault =
+ safetyCenterTestData
+ .safetyCenterEntryDefaultBuilder(DYNAMIC_DISABLED_ID)
+ .setPendingIntent(null)
+ .setEnabled(false)
+ .build()
+
+ private val dynamicDisabledUpdated =
+ safetyCenterTestData.safetyCenterEntryRecommendation(DYNAMIC_DISABLED_ID)
+
+ private val dynamicDisabledForWorkDefaultBuilder
+ get() =
+ safetyCenterTestData
+ .safetyCenterEntryDefaultBuilder(
+ DYNAMIC_DISABLED_ID,
+ userId = deviceState.workProfile().id(),
+ title = "Paste"
+ )
+ .setPendingIntent(null)
+ .setEnabled(false)
+
+ private val dynamicDisabledForWorkDefault
+ get() = dynamicDisabledForWorkDefaultBuilder.build()
+
+ private val dynamicDisabledForWorkPaused
+ get() =
+ dynamicDisabledForWorkDefaultBuilder
+ // TODO(b/233188021): This needs to use the Enterprise API to override the "work"
+ // keyword.
+ .setSummary(safetyCenterResourcesContext.getStringByName("work_profile_paused"))
+ .build()
+
+ private val dynamicDisabledForWorkUpdated
+ get() = safetyCenterEntryOkForWork(DYNAMIC_DISABLED_ID, deviceState.workProfile().id())
+
+ private val dynamicHiddenUpdated =
+ safetyCenterTestData.safetyCenterEntryUnspecified(DYNAMIC_HIDDEN_ID, pendingIntent = null)
+
+ private val dynamicHiddenForWorkUpdated
+ get() = safetyCenterEntryOkForWork(DYNAMIC_HIDDEN_ID, deviceState.workProfile().id())
+
+ private val staticGroupBuilder =
+ SafetyCenterEntryGroup.Builder(STATIC_GROUP_ID, "OK")
+ .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
+ .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY)
+ .setSummary("OK")
+
+ private val staticBarebone =
+ safetyCenterTestData
+ .safetyCenterEntryDefaultStaticBuilder(STATIC_BAREBONE_ID)
+ .setSummary(null)
+ .build()
+
+ private val staticAllOptional =
+ safetyCenterTestData.safetyCenterEntryDefaultStaticBuilder(STATIC_ALL_OPTIONAL_ID).build()
+
+ private val staticAllOptionalForWorkBuilder
+ get() =
+ safetyCenterTestData
+ .safetyCenterEntryDefaultStaticBuilder(
+ STATIC_ALL_OPTIONAL_ID,
+ userId = deviceState.workProfile().id(),
+ title = "Paste"
+ )
+ .setPendingIntent(
+ createTestActivityRedirectPendingIntentForUser(
+ deviceState.workProfile().userHandle()
+ )
+ )
+
+ private val staticAllOptionalForWork
+ get() = staticAllOptionalForWorkBuilder.build()
+
+ 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"))
+ .setEnabled(false)
+ .build()
+
+ private val staticEntry =
+ SafetyCenterStaticEntry.Builder("OK")
+ .setSummary("OK")
+ .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
+ .build()
+
+ private val staticEntryUpdated =
+ SafetyCenterStaticEntry.Builder("Unspecified title")
+ .setSummary("Unspecified summary")
+ .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
+ .build()
+
+ private val staticEntryForWorkBuilder
+ get() =
+ SafetyCenterStaticEntry.Builder("Paste")
+ .setSummary("OK")
+ .setPendingIntent(
+ createTestActivityRedirectPendingIntentForUser(
+ deviceState.workProfile().userHandle()
+ )
+ )
+
+ private val staticEntryForWork
+ get() = staticEntryForWorkBuilder.build()
+
+ private val staticEntryForWorkPaused
+ get() =
+ staticEntryForWorkBuilder
+ // TODO(b/233188021): This needs to use the Enterprise API to override the "work"
+ // keyword.
+ .setSummary(safetyCenterResourcesContext.getStringByName("work_profile_paused"))
+ .build()
+
+ private val staticEntryForWorkUpdated =
+ SafetyCenterStaticEntry.Builder("Unspecified title for Work")
+ .setSummary("Unspecified summary")
+ .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
+ .build()
+
+ private val safetyCenterDataForAdditionalUser
+ get() =
+ SafetyCenterData(
+ safetyCenterTestData.safetyCenterStatusUnknown,
+ emptyList(),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData.safetyCenterEntryDefault(
+ SINGLE_SOURCE_ALL_PROFILE_ID,
+ deviceState.additionalUser().id(),
+ pendingIntent =
+ createTestActivityRedirectPendingIntentForUser(
+ deviceState.additionalUser().userHandle()
+ )
+ )
+ )
+ ),
+ emptyList()
+ )
+
+ @Before
+ fun assumeDeviceSupportsSafetyCenterToRunTests() {
+ assumeTrue(shouldRunTests)
+ }
+
+ @Before
+ fun enableSafetyCenterBeforeTest() {
+ if (!shouldRunTests) {
+ return
+ }
+ safetyCenterTestHelper.setup()
+ }
+
+ @After
+ fun clearDataAfterTest() {
+ if (!shouldRunTests) {
+ return
+ }
+ safetyCenterTestHelper.reset()
+ resetQuietMode()
+ }
+
+ @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() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.workPolicyInfoConfig)
+
+ findWorkPolicyInfo()
+ }
+
+ @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() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.workPolicyInfoConfig)
+
+ findWorkPolicyInfo()
+ }
+
+ @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() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.workPolicyInfoConfig)
+
+ findWorkPolicyInfo()
+ setQuietMode(true)
+ 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)
+ val dataForWork = safetySourceTestData.informationWithIssueForWork
+ val managedSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.workProfile().userHandle())
+ managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID,
+ dataForWork
+ )
+
+ setQuietMode(true)
+ val apiSafetySourceDataForWork =
+ managedSafetyCenterManager.getSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID
+ )
+
+ assertThat(apiSafetySourceDataForWork).isEqualTo(dataForWork)
+ }
+
+ @Test
+ @EnsureHasAdditionalUser(installInstrumentedApp = TRUE)
+ @Postsubmit(reason = "Test takes too much time to setup")
+ fun getSafetySourceData_afterAdditionalUserRemoved_returnsNull() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
+ val additionalUserSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.additionalUser().userHandle())
+ val dataForAdditionalUser = safetySourceTestData.information
+ additionalUserSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID,
+ dataForAdditionalUser
+ )
+ checkState(
+ additionalUserSafetyCenterManager.getSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID
+ ) == dataForAdditionalUser
+ )
+
+ deviceState.additionalUser().remove()
+
+ assertThat(
+ additionalUserSafetyCenterManager
+ .getSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID
+ )
+ )
+ .isNull()
+ }
+
+ @Test
+ @Postsubmit(reason = "Test takes too much time to setup")
+ @EnsureHasWorkProfile(installInstrumentedApp = TRUE)
+ fun getSafetySourceData_withoutInteractAcrossUserPermission_shouldThrowError() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
+
+ val managedSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.workProfile().userHandle())
+ assertFailsWith(SecurityException::class) {
+ managedSafetyCenterManager.getSafetySourceData(SINGLE_SOURCE_ALL_PROFILE_ID)
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "Test takes too much time to setup")
+ @EnsureHasWorkProfile(installInstrumentedApp = TRUE)
+ fun getSafetySourceData_withoutAppInstalledForWorkProfile_shouldReturnNull() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
+ val managedSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.workProfile().userHandle())
+ val dataForWork = safetySourceTestData.informationWithIssueForWork
+ managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID,
+ dataForWork
+ )
+ TestApis.packages().find(context.packageName).uninstall(deviceState.workProfile())
+
+ val safetySourceData =
+ managedSafetyCenterManager.getSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID
+ )
+
+ assertThat(safetySourceData).isNull()
+ }
+
+ @Test
+ @Postsubmit(reason = "Test takes too much time to setup")
+ @EnsureHasWorkProfile(installInstrumentedApp = TRUE)
+ fun getSafetySourceData_withRemovedProfile_shouldReturnNull() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
+ val managedSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.workProfile().userHandle())
+ val dataForWork = safetySourceTestData.informationWithIssueForWork
+ managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID,
+ dataForWork
+ )
+ deviceState.workProfile().remove()
+
+ val safetySourceData =
+ managedSafetyCenterManager.getSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID
+ )
+
+ assertThat(safetySourceData).isNull()
+ }
+
+ @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 =
+ getSafetyCenterManagerForUser(deviceState.workProfile().userHandle())
+ val dataForWork = safetySourceTestData.informationWithIssueForWork
+ managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID,
+ dataForWork
+ )
+ setQuietMode(true)
+
+ val safetySourceData =
+ managedSafetyCenterManager.getSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID
+ )
+
+ assertThat(safetySourceData).isEqualTo(dataForWork)
+ }
+
+ @Test
+ @Postsubmit(reason = "Test takes too much time to setup")
+ @EnsureHasNoWorkProfile
+ fun getSafetyCenterData_withComplexConfigWithoutWorkProfile_returnsPrimaryDataFromConfig() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexAllProfileConfig)
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ 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"
+ )
+ )
+ .setEntries(listOf(dynamicBareboneDefault, dynamicDisabledDefault))
+ .setSeverityUnspecifiedIconType(
+ SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION
+ )
+ .build()
+ ),
+ SafetyCenterEntryOrGroup(
+ staticGroupBuilder
+ .setEntries(listOf(staticBarebone, staticAllOptional))
+ .build()
+ )
+ ),
+ listOf(SafetyCenterStaticEntryGroup("OK", listOf(staticEntry, staticEntry)))
+ )
+ 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)
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ 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"
+ )
+ )
+ .setEntries(
+ listOf(
+ dynamicBareboneDefault,
+ dynamicDisabledDefault,
+ dynamicDisabledForWorkDefault
+ )
+ )
+ .setSeverityUnspecifiedIconType(
+ SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION
+ )
+ .build()
+ ),
+ SafetyCenterEntryOrGroup(
+ staticGroupBuilder
+ .setEntries(
+ listOf(staticBarebone, staticAllOptional, staticAllOptionalForWork)
+ )
+ .build()
+ )
+ ),
+ listOf(
+ SafetyCenterStaticEntryGroup(
+ "OK",
+ listOf(staticEntry, staticEntryForWork, staticEntry, staticEntryForWork)
+ )
+ )
+ )
+ assertThat(apiSafetyCenterData.withoutExtras()).isEqualTo(safetyCenterDataFromComplexConfig)
+ }
+
+ @Test
+ @Postsubmit(reason = "Test takes too much time to setup")
+ @EnsureHasWorkProfile(installInstrumentedApp = TRUE)
+ fun getSafetyCenterData_withComplexConfigWithPrimaryDataProvided_returnsPrimaryDataProvided() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexAllProfileConfig)
+ updatePrimaryProfileSources()
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ val safetyCenterDataFromComplexConfig =
+ SafetyCenterData(
+ safetyCenterTestData.safetyCenterStatusCritical(6),
+ primaryProfileOnlyIssues,
+ listOf(
+ SafetyCenterEntryOrGroup(
+ SafetyCenterEntryGroup.Builder(DYNAMIC_GROUP_ID, "OK")
+ .setSeverityLevel(ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .setSummary("Critical summary")
+ .setEntries(
+ listOf(
+ dynamicBareboneUpdated,
+ dynamicDisabledUpdated,
+ dynamicDisabledForWorkDefault,
+ dynamicHiddenUpdated
+ )
+ )
+ .setSeverityUnspecifiedIconType(
+ SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION
+ )
+ .build()
+ ),
+ SafetyCenterEntryOrGroup(
+ staticGroupBuilder
+ .setEntries(
+ listOf(staticBarebone, staticAllOptional, staticAllOptionalForWork)
+ )
+ .build()
+ )
+ ),
+ listOf(
+ SafetyCenterStaticEntryGroup(
+ "OK",
+ listOf(
+ staticEntryUpdated,
+ staticEntryForWork,
+ staticEntry,
+ staticEntryForWork
+ )
+ )
+ )
+ )
+ assertThat(apiSafetyCenterData.withoutExtras()).isEqualTo(safetyCenterDataFromComplexConfig)
+ }
+
+ @Test
+ @Postsubmit(reason = "Test takes too much time to setup")
+ @EnsureHasWorkProfile(installInstrumentedApp = TRUE)
+ fun getSafetyCenterData_withComplexConfigWithAllDataProvided_returnsAllDataProvided() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexAllProfileConfig)
+ updatePrimaryProfileSources()
+ updateWorkProfileSources()
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ val managedUserId = deviceState.workProfile().id()
+ val safetyCenterDataFromComplexConfig =
+ SafetyCenterData(
+ safetyCenterTestData.safetyCenterStatusCritical(11),
+ 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
+ ),
+ safetyCenterTestData.safetyCenterIssueInformation(
+ DYNAMIC_DISABLED_ID,
+ managedUserId,
+ groupId = DYNAMIC_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueInformation(
+ DYNAMIC_HIDDEN_ID,
+ managedUserId,
+ groupId = DYNAMIC_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueInformation(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ managedUserId,
+ attributionTitle = null,
+ groupId = ISSUE_ONLY_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueInformation(
+ DYNAMIC_IN_STATELESS_ID,
+ managedUserId,
+ groupId = MIXED_STATELESS_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueInformation(
+ ISSUE_ONLY_IN_STATELESS_ID,
+ managedUserId,
+ groupId = MIXED_STATELESS_GROUP_ID
+ )
+ ),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ SafetyCenterEntryGroup.Builder(DYNAMIC_GROUP_ID, "OK")
+ .setSeverityLevel(ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .setSummary("Critical summary")
+ .setEntries(
+ listOf(
+ dynamicBareboneUpdated,
+ dynamicDisabledUpdated,
+ dynamicDisabledForWorkUpdated,
+ dynamicHiddenUpdated,
+ dynamicHiddenForWorkUpdated
+ )
+ )
+ .setSeverityUnspecifiedIconType(
+ SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION
+ )
+ .build()
+ ),
+ SafetyCenterEntryOrGroup(
+ staticGroupBuilder
+ .setEntries(
+ listOf(staticBarebone, staticAllOptional, staticAllOptionalForWork)
+ )
+ .build()
+ )
+ ),
+ listOf(
+ SafetyCenterStaticEntryGroup(
+ "OK",
+ listOf(
+ staticEntryUpdated,
+ staticEntryForWorkUpdated,
+ staticEntry,
+ staticEntryForWork
+ )
+ )
+ )
+ )
+ assertThat(apiSafetyCenterData.withoutExtras()).isEqualTo(safetyCenterDataFromComplexConfig)
+ }
+
+ @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 =
+ SafetyCenterData(
+ safetyCenterTestData.safetyCenterStatusCritical(6),
+ primaryProfileOnlyIssues,
+ listOf(
+ SafetyCenterEntryOrGroup(
+ SafetyCenterEntryGroup.Builder(DYNAMIC_GROUP_ID, "OK")
+ .setSeverityLevel(ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .setSummary("Critical summary")
+ .setEntries(
+ listOf(
+ dynamicBareboneUpdated,
+ dynamicDisabledUpdated,
+ dynamicDisabledForWorkPaused,
+ dynamicHiddenUpdated
+ )
+ )
+ .setSeverityUnspecifiedIconType(
+ SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION
+ )
+ .build()
+ ),
+ SafetyCenterEntryOrGroup(
+ staticGroupBuilder
+ .setEntries(
+ listOf(
+ staticBarebone,
+ staticAllOptional,
+ staticAllOptionalForWorkPaused
+ )
+ )
+ .build()
+ )
+ ),
+ listOf(
+ SafetyCenterStaticEntryGroup(
+ "OK",
+ listOf(
+ staticEntryUpdated,
+ staticEntryForWorkPaused,
+ staticEntry,
+ staticEntryForWorkPaused
+ )
+ )
+ )
+ )
+ assertThat(apiSafetyCenterData.withoutExtras()).isEqualTo(safetyCenterDataFromComplexConfig)
+ }
+
+ @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
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ALL_PROFILE_ID, dataForPrimaryUser)
+ val dataForPrimaryUserWorkProfile = safetySourceTestData.informationWithIssueForWork
+ val managedSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.workProfile().userHandle())
+ managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID,
+ dataForPrimaryUserWorkProfile
+ )
+
+ val additionalUserSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.additionalUser().userHandle())
+ val apiSafetyCenterDataForAdditionalUser =
+ additionalUserSafetyCenterManager.getSafetyCenterDataWithInteractAcrossUsersPermission()
+
+ assertThat(apiSafetyCenterDataForAdditionalUser)
+ .isEqualTo(safetyCenterDataForAdditionalUser)
+ }
+
+ @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)
+ val managedSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.workProfile().userHandle())
+ val safetyCenterDataWithWorkProfile =
+ SafetyCenterData(
+ safetyCenterTestData.safetyCenterStatusUnknown,
+ emptyList(),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ SafetyCenterEntryGroup.Builder(SINGLE_SOURCE_GROUP_ID, "OK")
+ .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNKNOWN)
+ .setSummary(
+ safetyCenterResourcesContext.getStringByName(
+ "group_unknown_summary"
+ )
+ )
+ .setEntries(
+ listOf(
+ safetyCenterTestData.safetyCenterEntryDefault(
+ SINGLE_SOURCE_ALL_PROFILE_ID
+ ),
+ safetyCenterTestData.safetyCenterEntryDefault(
+ SINGLE_SOURCE_ALL_PROFILE_ID,
+ deviceState.workProfile().id(),
+ title = "Paste",
+ pendingIntent =
+ createTestActivityRedirectPendingIntentForUser(
+ deviceState.workProfile().userHandle()
+ )
+ )
+ )
+ )
+ .setSeverityUnspecifiedIconType(
+ SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION
+ )
+ .build()
+ )
+ ),
+ emptyList()
+ )
+ checkState(
+ safetyCenterManager.getSafetyCenterDataWithPermission() ==
+ safetyCenterDataWithWorkProfile
+ )
+ checkState(
+ managedSafetyCenterManager.getSafetyCenterDataWithInteractAcrossUsersPermission() ==
+ safetyCenterDataWithWorkProfile
+ )
+
+ deviceState.workProfile().remove()
+
+ val safetyCenterDataForPrimaryUser =
+ SafetyCenterData(
+ safetyCenterTestData.safetyCenterStatusUnknown,
+ emptyList(),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData.safetyCenterEntryDefault(SINGLE_SOURCE_ALL_PROFILE_ID)
+ )
+ ),
+ emptyList()
+ )
+ assertThat(safetyCenterManager.getSafetyCenterDataWithPermission())
+ .isEqualTo(safetyCenterDataForPrimaryUser)
+ assertThat(
+ managedSafetyCenterManager.getSafetyCenterDataWithInteractAcrossUsersPermission()
+ )
+ .isEqualTo(SafetyCenterTestData.DEFAULT)
+ }
+
+ @Test
+ @EnsureHasAdditionalUser(installInstrumentedApp = TRUE)
+ @Postsubmit(reason = "Test takes too much time to setup")
+ fun getSafetyCenterData_afterAdditionalUserRemoved_returnsDefaultData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
+ val additionalUserSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.additionalUser().userHandle())
+ checkState(
+ additionalUserSafetyCenterManager
+ .getSafetyCenterDataWithInteractAcrossUsersPermission() ==
+ safetyCenterDataForAdditionalUser
+ )
+
+ deviceState.additionalUser().remove()
+
+ assertThat(
+ additionalUserSafetyCenterManager
+ .getSafetyCenterDataWithInteractAcrossUsersPermission()
+ )
+ .isEqualTo(SafetyCenterTestData.DEFAULT)
+ }
+
+ @Test
+ @Postsubmit(reason = "Test takes too much time to setup")
+ @EnsureHasWorkProfile(installInstrumentedApp = TRUE)
+ fun setSafetySourceData_primaryProfileIssueOnlySource_shouldNotBeAbleToSetDataToWorkProfile() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
+ val managedSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.workProfile().userHandle())
+ val dataForWork =
+ SafetySourceTestData.issuesOnly(safetySourceTestData.criticalResolvingGeneralIssue)
+
+ assertFailsWith(IllegalArgumentException::class) {
+ managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ dataForWork
+ )
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "Test takes too much time to setup")
+ @EnsureHasWorkProfile(installInstrumentedApp = TRUE)
+ fun setSafetySourceData_withoutInteractAcrossUserPermission_shouldThrowError() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
+ val dataForWork = safetySourceTestData.informationWithIssueForWork
+ val managedSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.workProfile().userHandle())
+
+ assertFailsWith(SecurityException::class) {
+ managedSafetyCenterManager.setSafetySourceData(
+ SINGLE_SOURCE_ALL_PROFILE_ID,
+ dataForWork,
+ EVENT_SOURCE_STATE_CHANGED
+ )
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "Test takes too much time to setup")
+ @EnsureHasWorkProfile(installInstrumentedApp = TRUE)
+ fun setSafetySourceData_withoutAppInstalledForWorkProfile_shouldNoOp() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
+ val dataForWork = safetySourceTestData.informationWithIssueForWork
+ val managedSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.workProfile().userHandle())
+ TestApis.packages().find(context.packageName).uninstall(deviceState.workProfile())
+
+ managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID,
+ dataForWork
+ )
+
+ val safetySourceData =
+ managedSafetyCenterManager.getSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID
+ )
+ assertThat(safetySourceData).isNull()
+ }
+
+ @Test
+ @Postsubmit(reason = "Test takes too much time to setup")
+ @EnsureHasWorkProfile(installInstrumentedApp = TRUE)
+ fun setSafetySourceData_withRemovedProfile_shouldNoOp() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
+ val dataForWork = safetySourceTestData.informationWithIssueForWork
+ val managedSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.workProfile().userHandle())
+ deviceState.workProfile().remove()
+
+ managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID,
+ dataForWork
+ )
+
+ val safetySourceData =
+ managedSafetyCenterManager.getSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID
+ )
+ assertThat(safetySourceData).isNull()
+ }
+
+ @Test
+ @Postsubmit(reason = "Test takes too much time to setup")
+ @EnsureHasCloneProfile(installInstrumentedApp = TRUE)
+ fun setSafetySourceData_withUnsupportedProfile_shouldNoOp() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
+ val dataForClone = safetySourceTestData.informationWithIssueForWork
+ val clonedSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.cloneProfile().userHandle())
+
+ clonedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID,
+ dataForClone
+ )
+
+ val safetySourceData =
+ clonedSafetyCenterManager.getSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID
+ )
+ assertThat(safetySourceData).isNull()
+ }
+
+ @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
+ val managedSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.workProfile().userHandle())
+ setQuietMode(true)
+
+ managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID,
+ dataForWork
+ )
+
+ val safetySourceData =
+ managedSafetyCenterManager.getSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID
+ )
+ assertThat(safetySourceData).isEqualTo(dataForWork)
+ }
+
+ @Test
+ @Postsubmit(reason = "Test takes too much time to setup")
+ @EnsureHasWorkProfile(installInstrumentedApp = TRUE)
+ fun setSafetySourceData_issuesOnlySourceWithWorkProfile_shouldBeAbleToSetData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceAllProfileConfig)
+
+ val dataForPrimaryUser =
+ SafetySourceTestData.issuesOnly(safetySourceTestData.recommendationGeneralIssue)
+ safetyCenterTestHelper.setData(ISSUE_ONLY_ALL_PROFILE_SOURCE_ID, dataForPrimaryUser)
+ val managedSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.workProfile().userHandle())
+ val dataForWorkProfile =
+ SafetySourceTestData.issuesOnly(safetySourceTestData.criticalResolvingGeneralIssue)
+ managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ ISSUE_ONLY_ALL_PROFILE_SOURCE_ID,
+ dataForWorkProfile
+ )
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(ISSUE_ONLY_ALL_PROFILE_SOURCE_ID)
+ val apiSafetySourceDataForWork =
+ managedSafetyCenterManager.getSafetySourceDataWithInteractAcrossUsersPermission(
+ ISSUE_ONLY_ALL_PROFILE_SOURCE_ID
+ )
+ assertThat(apiSafetySourceData).isEqualTo(dataForPrimaryUser)
+ assertThat(apiSafetySourceDataForWork).isEqualTo(dataForWorkProfile)
+ }
+
+ @Test
+ @Postsubmit(reason = "Test takes too much time to setup")
+ @EnsureHasWorkProfile(installInstrumentedApp = TRUE)
+ fun setSafetySourceData_primaryProfileSource_shouldNotBeAbleToSetDataToWorkProfile() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val managedSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.workProfile().userHandle())
+ val dataForWork = safetySourceTestData.informationWithIssueForWork
+ assertFailsWith(IllegalArgumentException::class) {
+ managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ID,
+ dataForWork
+ )
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "Test takes too much time to setup")
+ @EnsureHasWorkProfile(installInstrumentedApp = TRUE)
+ fun setSafetySourceData_sourceWithWorkProfile_shouldBeAbleToSetData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceAllProfileConfig)
+
+ val dataForPrimaryUser = safetySourceTestData.information
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ALL_PROFILE_ID, dataForPrimaryUser)
+ val dataForWork = safetySourceTestData.informationWithIssueForWork
+ val managedSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.workProfile().userHandle())
+ managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID,
+ dataForWork
+ )
+
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ALL_PROFILE_ID)
+ val apiSafetySourceDataForWork =
+ managedSafetyCenterManager.getSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ALL_PROFILE_ID
+ )
+ assertThat(apiSafetySourceData).isEqualTo(dataForPrimaryUser)
+ assertThat(apiSafetySourceDataForWork).isEqualTo(dataForWork)
+ }
+
+ @Test
+ @Postsubmit(reason = "Test takes too much time to setup")
+ @EnsureHasAdditionalUser(installInstrumentedApp = TRUE)
+ fun setSafetySourceData_forStoppedUser_shouldSetData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ deviceState.additionalUser().stop()
+
+ val dataForPrimaryUser = safetySourceTestData.unspecified
+ val additionalUserSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.additionalUser().userHandle())
+ additionalUserSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ID,
+ dataForPrimaryUser
+ )
+
+ val apiSafetySourceData =
+ additionalUserSafetyCenterManager.getSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ID
+ )
+ assertThat(apiSafetySourceData).isEqualTo(dataForPrimaryUser)
+ }
+
+ @Test
+ @Postsubmit(reason = "Test takes too much time to setup")
+ @EnsureHasAdditionalUser(installInstrumentedApp = TRUE)
+ fun setSafetySourceData_forBothPrimaryAdditionalUser_shouldSetData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val dataForPrimaryUser = safetySourceTestData.information
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataForPrimaryUser)
+ val dataForAdditionalUser = safetySourceTestData.unspecified
+ val additionalUserSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.additionalUser().userHandle())
+ additionalUserSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ID,
+ dataForAdditionalUser
+ )
+
+ val apiSafetySourceDataForPrimaryUser =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ val apiSafetySourceDataForAdditionalUser =
+ additionalUserSafetyCenterManager.getSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ID
+ )
+ assertThat(apiSafetySourceDataForPrimaryUser).isEqualTo(dataForPrimaryUser)
+ assertThat(apiSafetySourceDataForAdditionalUser).isEqualTo(dataForAdditionalUser)
+ }
+
+ @Test
+ @Postsubmit(reason = "Test takes too much time to setup")
+ @EnsureHasAdditionalUser(installInstrumentedApp = TRUE)
+ fun setSafetySourceData_forAdditionalUser_shouldNotAffectDataForPrimaryUser() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val dataForAdditionalUser = safetySourceTestData.unspecified
+ val additionalUserSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.additionalUser().userHandle())
+ additionalUserSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ SINGLE_SOURCE_ID,
+ dataForAdditionalUser
+ )
+
+ val apiSafetySourceDataForPrimaryUser =
+ safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
+ assertThat(apiSafetySourceDataForPrimaryUser).isEqualTo(null)
+ }
+
+ 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")
+ }
+ }
+
+ private fun getSafetyCenterManagerForUser(userHandle: UserHandle): SafetyCenterManager {
+ val contextForUser = getContextForUser(userHandle)
+ return contextForUser.getSystemService(SafetyCenterManager::class.java)!!
+ }
+
+ private fun getContextForUser(userHandle: UserHandle): Context {
+ return callWithShellPermissionIdentity(INTERACT_ACROSS_USERS_FULL) {
+ context.createContextAsUser(userHandle, 0)
+ }
+ }
+
+ private fun createTestActivityRedirectPendingIntentForUser(user: UserHandle): PendingIntent {
+ return callWithShellPermissionIdentity(INTERACT_ACROSS_USERS) {
+ SafetySourceTestData.createRedirectPendingIntent(
+ getContextForUser(user),
+ Intent(ACTION_TEST_ACTIVITY)
+ )
+ }
+ }
+
+ private fun SafetyCenterManager.getSafetySourceDataWithInteractAcrossUsersPermission(
+ id: String
+ ): SafetySourceData? =
+ callWithShellPermissionIdentity(INTERACT_ACROSS_USERS_FULL) {
+ getSafetySourceDataWithPermission(id)
+ }
+
+ private fun SafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ id: String,
+ dataToSet: SafetySourceData,
+ safetyEvent: SafetyEvent = EVENT_SOURCE_STATE_CHANGED
+ ) =
+ callWithShellPermissionIdentity(INTERACT_ACROSS_USERS_FULL) {
+ setSafetySourceDataWithPermission(id, dataToSet, safetyEvent)
+ }
+
+ private fun SafetyCenterManager.getSafetyCenterDataWithInteractAcrossUsersPermission():
+ SafetyCenterData =
+ callWithShellPermissionIdentity(INTERACT_ACROSS_USERS_FULL) {
+ getSafetyCenterDataWithPermission()
+ }
+
+ private fun setQuietMode(value: Boolean) {
+ deviceState.workProfile().setQuietMode(value)
+ inQuietMode = value
+ }
+
+ private fun resetQuietMode() {
+ if (!inQuietMode) {
+ return
+ }
+ setQuietMode(false)
+ }
+
+ private fun safetyCenterEntryOkForWork(sourceId: String, managedUserId: Int) =
+ safetyCenterTestData
+ .safetyCenterEntryOkBuilder(sourceId, managedUserId, title = "Ok title for Work")
+ .build()
+
+ private fun updatePrimaryProfileSources() {
+ safetyCenterTestHelper.setData(
+ DYNAMIC_BAREBONE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ safetyCenterTestHelper.setData(
+ DYNAMIC_DISABLED_ID,
+ safetySourceTestData.recommendationWithGeneralIssue
+ )
+ safetyCenterTestHelper.setData(DYNAMIC_HIDDEN_ID, safetySourceTestData.unspecified)
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_BAREBONE_ID,
+ SafetySourceTestData.issuesOnly(safetySourceTestData.criticalResolvingGeneralIssue)
+ )
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ SafetySourceTestData.issuesOnly(safetySourceTestData.recommendationGeneralIssue)
+ )
+ safetyCenterTestHelper.setData(
+ DYNAMIC_IN_STATELESS_ID,
+ safetySourceTestData.unspecifiedWithIssue
+ )
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_IN_STATELESS_ID,
+ SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue)
+ )
+ }
+
+ private fun updateWorkProfileSources() {
+ val managedSafetyCenterManager =
+ getSafetyCenterManagerForUser(deviceState.workProfile().userHandle())
+ managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ DYNAMIC_DISABLED_ID,
+ safetySourceTestData.informationWithIssueForWork
+ )
+ managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ DYNAMIC_HIDDEN_ID,
+ safetySourceTestData.informationWithIssueForWork
+ )
+ managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue)
+ )
+ managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ DYNAMIC_IN_STATELESS_ID,
+ safetySourceTestData.unspecifiedWithIssueForWork
+ )
+ managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission(
+ ISSUE_ONLY_IN_STATELESS_ID,
+ SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue)
+ )
+ }
+}
diff --git a/tests/functional/safetycenter/safetycenteractivity/Android.bp b/tests/functional/safetycenter/safetycenteractivity/Android.bp
new file mode 100644
index 000000000..af0020e91
--- /dev/null
+++ b/tests/functional/safetycenter/safetycenteractivity/Android.bp
@@ -0,0 +1,43 @@
+//
+// 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: "SafetyCenterActivityFunctionalTestCases",
+ 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",
+ "compatibility-device-preconditions",
+ "kotlin-test",
+ "platform-test-rules",
+ "safety-center-test-util-lib",
+ "safety-center-pending-intents",
+ ],
+ test_suites: [
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/functional/safetycenter/safetycenteractivity/AndroidManifest.xml b/tests/functional/safetycenter/safetycenteractivity/AndroidManifest.xml
new file mode 100644
index 000000000..c08ae78b0
--- /dev/null
+++ b/tests/functional/safetycenter/safetycenteractivity/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?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.safetycenter.functional.ui.safetycenteractivity">
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:label="Functional tests for SafetyCenterActivity"
+ android:targetPackage="android.safetycenter.functional.ui.safetycenteractivity"/>
+
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+</manifest>
diff --git a/tests/functional/safetycenter/safetycenteractivity/AndroidTest.xml b/tests/functional/safetycenter/safetycenteractivity/AndroidTest.xml
new file mode 100644
index 000000000..5357ed4f7
--- /dev/null
+++ b/tests/functional/safetycenter/safetycenteractivity/AndroidTest.xml
@@ -0,0 +1,61 @@
+<?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 functional SafetyCenterActivity test cases">
+
+ <object
+ class="com.android.tradefed.testtype.suite.module.Sdk33ModuleController"
+ 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="SafetyCenterActivityFunctionalTestCases.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" />
+ <!-- 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" />
+ </target_preparer>
+
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/data/user/0/android.safetycenter.functional.ui.safetycenteractivity/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.ui.safetycenteractivity"/>
+ <option name="exclude-annotation" value="org.junit.Ignore"/>
+ <option name="runtime-hint" value="10m"/>
+ </test>
+</configuration>
diff --git a/tests/functional/safetycenter/safetycenteractivity/TEST_MAPPING b/tests/functional/safetycenter/safetycenteractivity/TEST_MAPPING
new file mode 100644
index 000000000..533b4d2a5
--- /dev/null
+++ b/tests/functional/safetycenter/safetycenteractivity/TEST_MAPPING
@@ -0,0 +1,17 @@
+{
+ "presubmit": [
+ {
+ "name": "SafetyCenterActivityFunctionalTestCases"
+ }
+ ],
+ "mainline-presubmit": [
+ {
+ "name": "SafetyCenterActivityFunctionalTestCases[com.google.android.permission.apex]",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.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
new file mode 100644
index 000000000..ce8a70fbe
--- /dev/null
+++ b/tests/functional/safetycenter/safetycenteractivity/src/android/safetycenter/functional/ui/SafetyCenterActivityTest.kt
@@ -0,0 +1,1496 @@
+/*
+ * 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.safetycenter.functional.ui
+
+import android.content.Context
+import android.os.Build.VERSION.CODENAME
+import android.os.Build.VERSION_CODES.TIRAMISU
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import android.os.Bundle
+import android.platform.test.rule.ScreenRecordRule
+import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_ID
+import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_ISSUE_ID
+import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING
+import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_INFORMATION
+import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION
+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
+import com.android.compatibility.common.util.UiAutomatorUtils2.getUiDevice
+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
+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.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.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.UiTestHelper.MORE_ISSUES_LABEL
+import com.android.safetycenter.testing.UiTestHelper.RESCAN_BUTTON_LABEL
+import com.android.safetycenter.testing.UiTestHelper.clickConfirmDismissal
+import com.android.safetycenter.testing.UiTestHelper.clickDismissIssueCard
+import com.android.safetycenter.testing.UiTestHelper.clickMoreIssuesCard
+import com.android.safetycenter.testing.UiTestHelper.resetRotation
+import com.android.safetycenter.testing.UiTestHelper.rotate
+import com.android.safetycenter.testing.UiTestHelper.setAnimationsEnabled
+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.waitCollapsedIssuesDisplayed
+import com.android.safetycenter.testing.UiTestHelper.waitDisplayed
+import com.android.safetycenter.testing.UiTestHelper.waitExpandedIssuesDisplayed
+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
+
+/** Functional tests for the Safety Center Activity. */
+@RunWith(AndroidJUnit4::class)
+class SafetyCenterActivityTest {
+
+ @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 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()
+ }
+
+ @After
+ fun clearDataAfterTest() {
+ if (!shouldRunTests) {
+ return
+ }
+ safetyCenterTestHelper.reset()
+ getUiDevice().resetRotation()
+ }
+
+ @Test
+ fun launchActivity_allowingSettingsTrampoline() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val dataToDisplay = safetySourceTestData.criticalWithResolvingGeneralIssue
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataToDisplay)
+
+ context.launchSafetyCenterActivity(preventTrampolineToSettings = false) {
+ waitSourceDataDisplayed(dataToDisplay)
+ }
+ }
+
+ @Test
+ fun launchActivity_displaysStaticSources() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.staticSourcesConfig)
+
+ context.launchSafetyCenterActivity {
+ waitAllTextDisplayed(
+ context.getString(safetyCenterTestConfigs.staticSourceGroup1.titleResId),
+ context.getString(safetyCenterTestConfigs.staticSource1.titleResId),
+ context.getString(safetyCenterTestConfigs.staticSource1.summaryResId),
+ context.getString(safetyCenterTestConfigs.staticSourceGroup2.titleResId),
+ context.getString(safetyCenterTestConfigs.staticSource2.titleResId),
+ context.getString(safetyCenterTestConfigs.staticSource2.summaryResId)
+ )
+ }
+ }
+
+ @Test
+ fun launchActivity_displaysSafetyData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val dataToDisplay = safetySourceTestData.criticalWithResolvingGeneralIssue
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataToDisplay)
+
+ context.launchSafetyCenterActivity { waitSourceDataDisplayed(dataToDisplay) }
+ }
+
+ @Test
+ fun launchActivity_displaysCollapsedGroupsOfMultipleSource() {
+ with(safetyCenterTestHelper) {
+ setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig)
+ setData(
+ SOURCE_ID_1,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_1_TITLE,
+ entrySummary = SAFETY_SOURCE_1_SUMMARY,
+ withIssue = false
+ )
+ )
+ setData(
+ SOURCE_ID_2,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_2_TITLE,
+ entrySummary = SAFETY_SOURCE_2_SUMMARY,
+ withIssue = false
+ )
+ )
+ setData(
+ SOURCE_ID_3,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_3_TITLE,
+ entrySummary = SAFETY_SOURCE_3_SUMMARY,
+ withIssue = false
+ )
+ )
+ setData(
+ SOURCE_ID_4,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_4_TITLE,
+ entrySummary = SAFETY_SOURCE_4_SUMMARY,
+ withIssue = false
+ )
+ )
+ setData(
+ SOURCE_ID_5,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_5_TITLE,
+ entrySummary = SAFETY_SOURCE_5_SUMMARY,
+ withIssue = false
+ )
+ )
+ }
+
+ context.launchSafetyCenterActivity {
+ waitAllTextDisplayed(
+ context.getString(safetyCenterTestConfigs.dynamicSourceGroup1.titleResId),
+ context.getString(safetyCenterTestConfigs.dynamicSourceGroup1.summaryResId),
+ context.getString(safetyCenterTestConfigs.dynamicSourceGroup3.titleResId),
+ context.getString(safetyCenterTestConfigs.dynamicSourceGroup3.summaryResId)
+ )
+ waitAllTextNotDisplayed(
+ SAFETY_SOURCE_1_TITLE,
+ SAFETY_SOURCE_1_SUMMARY,
+ SAFETY_SOURCE_2_TITLE,
+ SAFETY_SOURCE_2_SUMMARY,
+ SAFETY_SOURCE_4_TITLE,
+ SAFETY_SOURCE_4_SUMMARY,
+ SAFETY_SOURCE_5_TITLE,
+ SAFETY_SOURCE_5_SUMMARY
+ )
+ }
+ }
+
+ @Test
+ fun launchActivity_displaysPrioritizedGroupSummary() {
+ with(safetyCenterTestHelper) {
+ setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig)
+ setData(
+ SOURCE_ID_1,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_1_TITLE,
+ entrySummary = SAFETY_SOURCE_1_SUMMARY,
+ withIssue = false
+ )
+ )
+ setData(
+ SOURCE_ID_2,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_RECOMMENDATION,
+ entryTitle = SAFETY_SOURCE_2_TITLE,
+ entrySummary = SAFETY_SOURCE_2_SUMMARY,
+ withIssue = true
+ )
+ )
+ setData(
+ SOURCE_ID_3,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_3_TITLE,
+ entrySummary = SAFETY_SOURCE_3_SUMMARY,
+ withIssue = false
+ )
+ )
+ setData(
+ SOURCE_ID_4,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_RECOMMENDATION,
+ entryTitle = SAFETY_SOURCE_4_TITLE,
+ entrySummary = SAFETY_SOURCE_4_SUMMARY,
+ withIssue = true
+ )
+ )
+ setData(
+ SOURCE_ID_5,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_CRITICAL_WARNING,
+ entryTitle = SAFETY_SOURCE_5_TITLE,
+ entrySummary = SAFETY_SOURCE_5_SUMMARY,
+ withIssue = true
+ )
+ )
+ }
+
+ context.launchSafetyCenterActivity {
+ waitAllTextDisplayed(
+ context.getString(safetyCenterTestConfigs.dynamicSourceGroup1.titleResId),
+ SAFETY_SOURCE_2_SUMMARY,
+ context.getString(safetyCenterTestConfigs.dynamicSourceGroup3.titleResId),
+ SAFETY_SOURCE_5_SUMMARY
+ )
+ waitAllTextNotDisplayed(
+ SAFETY_SOURCE_1_TITLE,
+ SAFETY_SOURCE_2_TITLE,
+ SAFETY_SOURCE_1_SUMMARY,
+ SAFETY_SOURCE_4_TITLE,
+ SAFETY_SOURCE_5_TITLE,
+ SAFETY_SOURCE_4_SUMMARY
+ )
+ }
+ }
+
+ @Test
+ fun launchActivity_displaysGroupsOfSingleSourceAsEntity() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig)
+
+ context.launchSafetyCenterActivity {
+ waitAllTextDisplayed(
+ context.getString(safetyCenterTestConfigs.dynamicSource3.titleResId)
+ )
+ waitAllTextNotDisplayed(
+ context.getString(safetyCenterTestConfigs.dynamicSourceGroup2.titleResId)
+ )
+ }
+ }
+
+ @Test
+ fun updatingSafetySourceData_updatesDisplayedSafetyData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+
+ context.launchSafetyCenterActivity {
+ val dataToDisplay = safetySourceTestData.recommendationWithGeneralIssue
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataToDisplay)
+
+ waitSourceDataDisplayed(dataToDisplay)
+ }
+ }
+
+ @Test
+ fun updatingSafetySourceData_withoutSubtitle_newIssueWithSubtitle() {
+ val initialDataToDisplay = safetySourceTestData.informationWithIssue
+ val updatedDataToDisplay = safetySourceTestData.informationWithSubtitleIssue
+
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, initialDataToDisplay)
+
+ context.launchSafetyCenterActivity {
+ waitSourceIssueDisplayed(safetySourceTestData.informationIssue)
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, updatedDataToDisplay)
+
+ waitSourceIssueDisplayed(safetySourceTestData.informationIssueWithSubtitle)
+ }
+ }
+
+ @Test
+ fun updatingSafetySourceData_withSubtitle_newIssueWithoutSubtitle() {
+ val initialDataToDisplay = safetySourceTestData.informationWithSubtitleIssue
+ val updatedDataToDisplay = safetySourceTestData.informationWithIssue
+
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, initialDataToDisplay)
+
+ context.launchSafetyCenterActivity {
+ waitSourceIssueDisplayed(safetySourceTestData.informationIssueWithSubtitle)
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, updatedDataToDisplay)
+
+ waitAllTextNotDisplayed(safetySourceTestData.informationIssueWithSubtitle.subtitle)
+ waitSourceIssueDisplayed(safetySourceTestData.informationIssue)
+ }
+ }
+
+ @Test
+ fun entryListWithEntryGroup_informationState_hasContentDescription() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ safetyCenterTestHelper.setData(SOURCE_ID_1, safetySourceTestData.information)
+ safetyCenterTestHelper.setData(SOURCE_ID_2, safetySourceTestData.information)
+ safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.information)
+
+ context.launchSafetyCenterActivity {
+ // Verify content description for the collapsed entry group, and click on it to expand
+ waitDisplayed(By.desc("List. OK. OK")) { it.click() }
+
+ // Verify content descriptions for the expanded group header and entry list item
+ waitAllTextDisplayed("OK")
+ waitDisplayed(By.desc("List item. Ok title. Ok summary"))
+ }
+ }
+
+ @Test
+ fun entryListWithEntryGroup_recommendationState_hasActionsNeededContentDescription() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ safetySourceTestData.recommendationWithGeneralIssue
+ )
+ safetyCenterTestHelper.setData(SOURCE_ID_2, safetySourceTestData.information)
+ safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.information)
+
+ context.launchSafetyCenterActivity {
+ // Verify content description for the collapsed entry group, and click on it to expand.
+ waitDisplayed(By.desc("List. OK. Actions needed. Recommendation summary")) {
+ it.click()
+ }
+
+ // Verify content descriptions for the expanded group header and entry list items.
+ waitAllTextDisplayed("OK")
+ waitDisplayed(By.desc("List item. Recommendation title. Recommendation summary"))
+ waitDisplayed(By.desc("List item. Ok title. Ok summary"))
+ }
+ }
+
+ @Test
+ fun entryListWithEntryGroup_clickingAnUnclickableDisabledEntry_doesNothing() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesConfigWithSourceWithInvalidIntent
+ )
+ safetyCenterTestHelper.setData(SOURCE_ID_1, safetySourceTestData.unspecified)
+
+ context.launchSafetyCenterActivity {
+ waitDisplayed(By.text("OK")) { it.click() }
+ waitDisplayed(By.text("Unspecified title")) { it.click() }
+ // Confirm that clicking on the entry neither redirects to any other screen nor
+ // collapses the group.
+ waitAllTextDisplayed("Unspecified title")
+ }
+ }
+
+ @Test
+ fun entryListWithEntryGroup_unclickableDisabledEntry_hasContentDescription() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesConfigWithSourceWithInvalidIntent
+ )
+ safetyCenterTestHelper.setData(SOURCE_ID_1, safetySourceTestData.unspecified)
+
+ context.launchSafetyCenterActivity {
+ waitDisplayed(By.desc("List. OK. No info yet")) { it.click() }
+ // Make sure that the content description is correctly set for the unclickable disabled
+ // entries so that the talkback to works properly.
+ waitDisplayed(By.desc("List item. Unspecified title. Unspecified summary"))
+ }
+ }
+
+ @Test
+ @ScreenRecordRule.ScreenRecord
+ fun entryListWithEntryGroup_clickingAClickableDisabledEntry_redirectsToDifferentScreen() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ safetySourceTestData.unspecifiedDisabledWithTestActivityRedirect
+ )
+
+ context.launchSafetyCenterActivity {
+ waitDisplayed(By.text("OK")) { it.click() }
+ waitDisplayed(By.text("Clickable disabled title")) { it.click() }
+ waitButtonDisplayed("Exit test activity") { it.click() }
+ }
+ }
+
+ @Test
+ fun entryListWithEntryGroup_clickableDisabledEntry_hasContentDescription() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ safetySourceTestData.unspecifiedDisabledWithTestActivityRedirect
+ )
+
+ context.launchSafetyCenterActivity {
+ waitDisplayed(By.desc("List. OK. No info yet")) { it.click() }
+ // Make sure that the content description is correctly set for the clickable disabled
+ // entry so that the talkback to works properly.
+ waitDisplayed(
+ By.desc("List item. Clickable disabled title. Clickable disabled summary")
+ )
+ }
+ }
+
+ @Test
+ fun entryListWithSingleSource_informationState_hasContentDescription() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+
+ context.launchSafetyCenterActivity {
+ // Verify content description for the individual entry
+ waitDisplayed(By.desc("Ok title. Ok summary"))
+ }
+ }
+
+ @Test
+ fun entryListWithSingleSource_clickingTheDefaultEntry_redirectsToDifferentScreen() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ context.launchSafetyCenterActivity {
+ waitDisplayed(By.text("OK")) { it.click() }
+ waitButtonDisplayed("Exit test activity") { it.click() }
+ waitDisplayed(By.text("OK"))
+ }
+ }
+
+ @Test
+ @ScreenRecordRule.ScreenRecord
+ fun entryListWithSingleSource_clickingDefaultEntryImplicitIntent_redirectsToDifferentScreen() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.implicitIntentSingleSourceConfig)
+
+ context.launchSafetyCenterActivity {
+ waitDisplayed(By.text("OK")) { it.click() }
+ waitButtonDisplayed("Exit test activity") { it.click() }
+ }
+ }
+
+ @Test
+ fun entryListWithSingleSource_clickingTheUpdatedEntry_redirectsToDifferentScreen() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+
+ context.launchSafetyCenterActivity {
+ waitDisplayed(By.text("Ok title")) { it.click() }
+ waitButtonDisplayed("Exit test activity") { it.click() }
+ waitDisplayed(By.text("Ok title"))
+ }
+ }
+
+ @Test
+ fun entryListWithSingleSource_clickingTheIconActionButton_redirectsToDifferentScreen() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.informationWithIconAction
+ )
+
+ context.launchSafetyCenterActivity {
+ waitDisplayed(By.desc("Information")) { it.click() }
+ waitButtonDisplayed("Exit test activity") { it.click() }
+ waitDisplayed(By.text("Ok title"))
+ }
+ }
+
+ @Test
+ fun staticSource_clickingTheEntry_redirectsToDifferentScreen() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.staticSourcesConfig)
+
+ context.launchSafetyCenterActivity {
+ waitDisplayed(
+ By.text(context.getString(safetyCenterTestConfigs.staticSource1.titleResId))
+ ) {
+ it.click()
+ }
+ waitButtonDisplayed("Exit test activity") { it.click() }
+ waitAllTextDisplayed(
+ context.getString(safetyCenterTestConfigs.staticSource1.titleResId)
+ )
+ }
+ }
+
+ @Test
+ fun issueCard_noAttribution_hasProperContentDescriptions() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceNoGroupTitleConfig)
+
+ val issue = safetySourceTestData.recommendationGeneralIssue
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ SafetySourceTestData.issuesOnly(issue)
+ )
+
+ context.launchSafetyCenterActivity { waitDisplayed(By.desc("Alert. ${issue.title}")) }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun issueCard_withAttribution_hasProperContentDescriptions() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val data = safetySourceTestData.informationWithIssueWithAttributionTitle
+ val issue = data.issues[0]
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ context.launchSafetyCenterActivity {
+ waitDisplayed(By.desc("Alert. ${issue.attributionTitle}"))
+ }
+ }
+
+ @Test
+ fun issueCard_greenIssue_noDismissalConfirmationAndDismisses() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.informationWithIssue)
+
+ context.launchSafetyCenterActivity {
+ clickDismissIssueCard()
+
+ waitSourceIssueNotDisplayed(safetySourceTestData.informationIssue)
+ waitSourceDataDisplayed(safetySourceTestData.information)
+ waitButtonDisplayed(RESCAN_BUTTON_LABEL)
+ }
+ }
+
+ @Test
+ fun issueCard_confirmsDismissal_dismisses() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+
+ context.launchSafetyCenterActivity {
+ clickDismissIssueCard()
+ waitAllTextDisplayed("Dismiss this alert?")
+ clickConfirmDismissal()
+
+ waitSourceIssueNotDisplayed(safetySourceTestData.criticalResolvingGeneralIssue)
+ waitButtonDisplayed(RESCAN_BUTTON_LABEL)
+ }
+ }
+
+ @Test
+ fun issueCard_confirmsDismissal_afterRotation_dismisses() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+
+ context.launchSafetyCenterActivity {
+ clickDismissIssueCard()
+ waitAllTextDisplayed(
+ "Dismiss this alert?",
+ "Review your security and privacy settings any time to add more protection"
+ )
+
+ getUiDevice().rotate()
+
+ waitAllTextDisplayed(
+ "Dismiss this alert?",
+ "Review your security and privacy settings any time to add more protection"
+ )
+ clickConfirmDismissal()
+
+ waitSourceIssueNotDisplayed(safetySourceTestData.criticalResolvingGeneralIssue)
+ waitButtonDisplayed(RESCAN_BUTTON_LABEL)
+ }
+ }
+
+ @Test
+ fun issueCard_confirmsDismissal_cancels() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+
+ context.launchSafetyCenterActivity {
+ clickDismissIssueCard()
+ waitAllTextDisplayed("Dismiss this alert?")
+ waitButtonDisplayed("Cancel") { it.click() }
+
+ waitSourceIssueDisplayed(safetySourceTestData.criticalResolvingGeneralIssue)
+ }
+ }
+
+ @Test
+ fun issueCard_confirmsDismissal_afterRotation_cancels() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+
+ context.launchSafetyCenterActivity {
+ clickDismissIssueCard()
+ waitAllTextDisplayed("Dismiss this alert?")
+
+ getUiDevice().rotate()
+
+ waitAllTextDisplayed("Dismiss this alert?")
+ waitButtonDisplayed("Cancel") { it.click() }
+
+ waitSourceIssueDisplayed(safetySourceTestData.criticalResolvingGeneralIssue)
+ }
+ }
+
+ @Test
+ fun issueCard_resolveIssue_successConfirmationShown() {
+ SafetyCenterFlags.hideResolvedIssueUiTransitionDelay = TIMEOUT_LONG
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ // Set the initial data for the source
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingIssueWithSuccessMessage
+ )
+
+ // Clear the data when action is triggered to simulate resolution.
+ SafetySourceReceiver.setResponse(
+ Request.ResolveAction(SINGLE_SOURCE_ID),
+ Response.ClearData
+ )
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ val action = safetySourceTestData.criticalResolvingActionWithSuccessMessage
+ waitButtonDisplayed(action.label) {
+ // Re-enable animations for this test as this is needed to show the success message.
+ setAnimationsEnabled(true)
+ it.click()
+ }
+
+ // Success message should show up if issue marked as resolved
+ val successMessage = action.successMessage
+ waitAllTextDisplayed(successMessage)
+ }
+ }
+
+ @Test
+ fun issueCard_resolveIssue_issueDismisses() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ // Set the initial data for the source
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingIssueWithSuccessMessage
+ )
+
+ // Clear the data when action is triggered to simulate resolution.
+ SafetySourceReceiver.setResponse(
+ Request.ResolveAction(SINGLE_SOURCE_ID),
+ Response.ClearData
+ )
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ val action = safetySourceTestData.criticalResolvingActionWithSuccessMessage
+ waitButtonDisplayed(action.label) { it.click() }
+
+ // Wait for success message to go away, verify issue no longer displayed
+ val successMessage = action.successMessage
+ waitAllTextNotDisplayed(successMessage)
+ waitSourceIssueNotDisplayed(
+ safetySourceTestData.criticalResolvingIssueWithSuccessMessage
+ )
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun issueCard_resolveIssue_withDialogClickYes_resolves() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssueWithConfirmation
+ )
+
+ // Clear the data when action is triggered to simulate resolution.
+ SafetySourceReceiver.setResponse(
+ Request.ResolveAction(SINGLE_SOURCE_ID),
+ Response.ClearData
+ )
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ val action = safetySourceTestData.criticalResolvingActionWithConfirmation
+ waitButtonDisplayed(action.label) { it.click() }
+
+ waitAllTextDisplayed(SafetySourceTestData.CONFIRMATION_TITLE)
+ waitButtonDisplayed(SafetySourceTestData.CONFIRMATION_YES) { it.click() }
+
+ waitSourceIssueNotDisplayed(safetySourceTestData.criticalResolvingIssueWithConfirmation)
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun issueCard_resolveIssue_withDialog_rotates_clickYes_resolves() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssueWithConfirmation
+ )
+
+ // Clear the data when action is triggered to simulate resolution.
+ SafetySourceReceiver.setResponse(
+ Request.ResolveAction(SINGLE_SOURCE_ID),
+ Response.ClearData
+ )
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ val action = safetySourceTestData.criticalResolvingActionWithConfirmation
+ waitButtonDisplayed(action.label) { it.click() }
+
+ waitAllTextDisplayed(SafetySourceTestData.CONFIRMATION_TITLE)
+
+ getUiDevice().rotate()
+
+ waitAllTextDisplayed(SafetySourceTestData.CONFIRMATION_TITLE)
+ waitButtonDisplayed(SafetySourceTestData.CONFIRMATION_YES) { it.click() }
+
+ waitSourceIssueNotDisplayed(safetySourceTestData.criticalResolvingIssueWithConfirmation)
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun issueCard_resolveIssue_withDialogClicksNo_cancels() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssueWithConfirmation
+ )
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ val action = safetySourceTestData.criticalResolvingActionWithConfirmation
+ waitButtonDisplayed(action.label) { it.click() }
+
+ waitAllTextDisplayed(SafetySourceTestData.CONFIRMATION_TITLE)
+ waitButtonDisplayed(SafetySourceTestData.CONFIRMATION_NO) { it.click() }
+
+ waitSourceIssueDisplayed(safetySourceTestData.criticalResolvingIssueWithConfirmation)
+ }
+ }
+
+ @Test
+ fun issueCard_resolveIssue_noSuccessMessage_noResolutionUiShown_issueDismisses() {
+ SafetyCenterFlags.hideResolvedIssueUiTransitionDelay = TIMEOUT_LONG
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ // Set the initial data for the source
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+
+ // Clear the data when action is triggered to simulate resolution.
+ SafetySourceReceiver.setResponse(
+ Request.ResolveAction(SINGLE_SOURCE_ID),
+ Response.ClearData
+ )
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ val action = safetySourceTestData.criticalResolvingAction
+ waitButtonDisplayed(action.label) {
+ // Re-enable animations for this test as this is needed to show the success message.
+ setAnimationsEnabled(true)
+ it.click()
+ }
+
+ waitSourceIssueNotDisplayed(safetySourceTestData.criticalResolvingGeneralIssue)
+ }
+ }
+
+ @Test
+ fun issueCard_resolvingInflightIssueFailed_issueRemains() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ // Set the initial data for the source
+ val data = safetySourceTestData.criticalWithResolvingGeneralIssue
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ // Respond with an error when the action is triggered
+ SafetySourceReceiver.setResponse(Request.ResolveAction(SINGLE_SOURCE_ID), Response.Error)
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ val action = safetySourceTestData.criticalResolvingAction
+ waitButtonDisplayed(action.label) { it.click() }
+
+ waitSourceIssueDisplayed(safetySourceTestData.criticalResolvingGeneralIssue)
+ }
+ }
+
+ @Test
+ fun issueCard_resolvingInFlightIssueTimesOut_issueRemains() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ // Set the initial data for the source
+ val data = safetySourceTestData.criticalWithResolvingGeneralIssue
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ SafetyCenterFlags.resolveActionTimeout = TIMEOUT_SHORT
+
+ // Set no data at all on the receiver, will ignore incoming call.
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ val action = safetySourceTestData.criticalResolvingAction
+ waitButtonDisplayed(action.label) { it.click() }
+
+ waitSourceIssueDisplayed(safetySourceTestData.criticalResolvingGeneralIssue)
+ }
+ }
+
+ @Test
+ fun issueCard_clickingNonResolvingActionButton_redirectsToDifferentScreen() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val data = safetySourceTestData.criticalWithTestActivityRedirectIssue
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ context.launchSafetyCenterActivity {
+ val action = safetySourceTestData.testActivityRedirectAction
+ waitButtonDisplayed(action.label) { it.click() }
+ waitButtonDisplayed("Exit test activity") { it.click() }
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun issueCard_withAttributionTitleSetBySource_displaysAttributionTitle() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val data = safetySourceTestData.informationWithIssueWithAttributionTitle
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ context.launchSafetyCenterActivity { waitAllTextDisplayed("Attribution Title") }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun issueCard_attributionNotSetBySource_displaysGroupTitleAsAttribution() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val data = safetySourceTestData.recommendationWithGeneralIssue
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ context.launchSafetyCenterActivity { waitAllTextDisplayed("OK") }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun issueCard_attributionNotSetBySourceAndGroupTitleNull_doesNotDisplayAttributionTitle() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceNoGroupTitleConfig)
+
+ val data = SafetySourceTestData.issuesOnly(safetySourceTestData.recommendationGeneralIssue)
+ safetyCenterTestHelper.setData(ISSUE_ONLY_ALL_OPTIONAL_ID, data)
+
+ context.launchSafetyCenterActivity { waitAllTextNotDisplayed("Attribution Title", "OK") }
+ }
+
+ @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
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ context.launchSafetyCenterActivity { waitAllTextNotDisplayed("Attribution title", "OK") }
+ }
+
+ @Test
+ @ScreenRecordRule.ScreenRecord
+ fun launchActivity_fromQuickSettings_issuesExpanded() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ safetySourceTestData.recommendationWithGeneralIssue
+ )
+ safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue)
+
+ val bundle = Bundle()
+ bundle.putBoolean(EXPAND_ISSUE_GROUP_QS_FRAGMENT_KEY, true)
+ context.launchSafetyCenterActivity(bundle) {
+ waitExpandedIssuesDisplayed(
+ safetySourceTestData.criticalResolvingGeneralIssue,
+ safetySourceTestData.recommendationGeneralIssue,
+ safetySourceTestData.informationIssue
+ )
+ }
+ }
+
+ @Test
+ fun launchActivity_fromNotification_targetIssueAlreadyFirstIssue() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ safetySourceTestData.recommendationWithGeneralIssue
+ )
+ safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue)
+
+ val bundle = Bundle()
+ bundle.putString(EXTRA_SAFETY_SOURCE_ID, SOURCE_ID_1)
+ bundle.putString(EXTRA_SAFETY_SOURCE_ISSUE_ID, CRITICAL_ISSUE_ID)
+ context.launchSafetyCenterActivity(bundle) {
+ waitCollapsedIssuesDisplayed(
+ safetySourceTestData.criticalResolvingGeneralIssue,
+ safetySourceTestData.recommendationGeneralIssue,
+ safetySourceTestData.informationIssue
+ )
+ }
+ }
+
+ @Test
+ fun launchActivity_fromNotification_targetIssueSamePriorityAsFirstIssue_reorderedFirstIssue() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ safetySourceTestData.criticalWithRedirectingIssue
+ )
+ safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue)
+
+ val bundle = Bundle()
+ bundle.putString(EXTRA_SAFETY_SOURCE_ID, SOURCE_ID_2)
+ bundle.putString(EXTRA_SAFETY_SOURCE_ISSUE_ID, CRITICAL_ISSUE_ID)
+ context.launchSafetyCenterActivity(bundle) {
+ waitCollapsedIssuesDisplayed(
+ safetySourceTestData.criticalRedirectingIssue,
+ safetySourceTestData.criticalResolvingGeneralIssue,
+ safetySourceTestData.informationIssue
+ )
+ }
+ }
+
+ @Test
+ fun launchActivity_fromNotification_targetLowerPriorityAsFirstIssue_reorderedSecondIssue() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ safetySourceTestData.recommendationWithGeneralIssue
+ )
+ safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue)
+
+ val bundle = Bundle()
+ bundle.putString(EXTRA_SAFETY_SOURCE_ID, SOURCE_ID_2)
+ bundle.putString(EXTRA_SAFETY_SOURCE_ISSUE_ID, RECOMMENDATION_ISSUE_ID)
+ context.launchSafetyCenterActivity(bundle) {
+ waitSourceIssueDisplayed(safetySourceTestData.criticalResolvingGeneralIssue)
+ waitSourceIssueDisplayed(safetySourceTestData.recommendationGeneralIssue)
+ waitAllTextDisplayed(MORE_ISSUES_LABEL)
+ waitSourceIssueNotDisplayed(safetySourceTestData.informationIssue)
+ }
+ }
+
+ @Test
+ fun launchActivity_fromNotification_targetIssueNotFound() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ safetySourceTestData.recommendationWithGeneralIssue
+ )
+ safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue)
+
+ val bundle = Bundle()
+ bundle.putString(EXTRA_SAFETY_SOURCE_ID, SOURCE_ID_2)
+ bundle.putString(EXTRA_SAFETY_SOURCE_ISSUE_ID, CRITICAL_ISSUE_ID)
+ context.launchSafetyCenterActivity(bundle) {
+ waitCollapsedIssuesDisplayed(
+ safetySourceTestData.criticalResolvingGeneralIssue,
+ safetySourceTestData.recommendationGeneralIssue,
+ safetySourceTestData.informationIssue
+ )
+ }
+ }
+
+ @Test
+ fun moreIssuesCard_underMaxShownIssues_noMoreIssuesCard() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+
+ context.launchSafetyCenterActivity {
+ waitSourceIssueDisplayed(safetySourceTestData.criticalResolvingGeneralIssue)
+ waitAllTextNotDisplayed(MORE_ISSUES_LABEL)
+ }
+ }
+
+ @Test
+ fun moreIssuesCard_moreIssuesCardShown_additionalIssueCardsCollapsed() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ safetySourceTestData.recommendationWithGeneralIssue
+ )
+ safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue)
+
+ context.launchSafetyCenterActivity {
+ waitCollapsedIssuesDisplayed(
+ safetySourceTestData.criticalResolvingGeneralIssue,
+ safetySourceTestData.recommendationGeneralIssue,
+ safetySourceTestData.informationIssue
+ )
+ }
+ }
+
+ @Test
+ fun moreIssuesCard_expandAdditionalIssueCards() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ safetySourceTestData.recommendationWithGeneralIssue
+ )
+ safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue)
+
+ context.launchSafetyCenterActivity {
+ waitSourceIssueDisplayed(safetySourceTestData.criticalResolvingGeneralIssue)
+
+ clickMoreIssuesCard()
+
+ waitExpandedIssuesDisplayed(
+ safetySourceTestData.criticalResolvingGeneralIssue,
+ safetySourceTestData.recommendationGeneralIssue,
+ safetySourceTestData.informationIssue
+ )
+ }
+ }
+
+ @Test
+ fun moreIssuesCard_rotation_cardsStillExpanded() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ safetySourceTestData.recommendationWithGeneralIssue
+ )
+ safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue)
+
+ context.launchSafetyCenterActivity {
+ clickMoreIssuesCard()
+
+ val uiDevice = getUiDevice()
+ uiDevice.waitForIdle()
+
+ // Verify cards initially expanded
+ waitExpandedIssuesDisplayed(
+ safetySourceTestData.criticalResolvingGeneralIssue,
+ safetySourceTestData.recommendationGeneralIssue,
+ safetySourceTestData.informationIssue
+ )
+
+ // Device rotation to trigger usage of savedinstancestate via config update
+ uiDevice.rotate()
+
+ // Verify cards remain expanded
+ waitExpandedIssuesDisplayed(
+ safetySourceTestData.criticalResolvingGeneralIssue,
+ safetySourceTestData.recommendationGeneralIssue,
+ safetySourceTestData.informationIssue
+ )
+ }
+ }
+
+ @Test
+ fun moreIssuesCard_twoIssuesAlreadyShown_expandAdditionalIssueCards() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ safetySourceTestData.recommendationWithGeneralIssue
+ )
+ safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue)
+
+ val bundle = Bundle()
+ bundle.putString(EXTRA_SAFETY_SOURCE_ID, SOURCE_ID_2)
+ bundle.putString(EXTRA_SAFETY_SOURCE_ISSUE_ID, RECOMMENDATION_ISSUE_ID)
+ context.launchSafetyCenterActivity(bundle) {
+ waitSourceIssueDisplayed(safetySourceTestData.criticalResolvingGeneralIssue)
+ waitSourceIssueDisplayed(safetySourceTestData.recommendationGeneralIssue)
+ waitAllTextDisplayed(MORE_ISSUES_LABEL)
+ waitSourceIssueNotDisplayed(safetySourceTestData.informationIssue)
+
+ clickMoreIssuesCard()
+
+ waitExpandedIssuesDisplayed(
+ safetySourceTestData.criticalResolvingGeneralIssue,
+ safetySourceTestData.recommendationGeneralIssue,
+ safetySourceTestData.informationIssue
+ )
+ }
+ }
+
+ @Test
+ fun collapsedEntryGroup_expandsWhenClicked() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig)
+ with(safetyCenterTestHelper) {
+ setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig)
+ setData(
+ SOURCE_ID_1,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_1_TITLE,
+ entrySummary = SAFETY_SOURCE_1_SUMMARY,
+ withIssue = false
+ )
+ )
+ setData(
+ SOURCE_ID_2,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_2_TITLE,
+ entrySummary = SAFETY_SOURCE_2_SUMMARY,
+ withIssue = false
+ )
+ )
+ setData(
+ SOURCE_ID_3,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_3_TITLE,
+ entrySummary = SAFETY_SOURCE_3_SUMMARY,
+ withIssue = false
+ )
+ )
+ setData(
+ SOURCE_ID_4,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_4_TITLE,
+ entrySummary = SAFETY_SOURCE_4_SUMMARY,
+ withIssue = false
+ )
+ )
+ setData(
+ SOURCE_ID_5,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_5_TITLE,
+ entrySummary = SAFETY_SOURCE_5_SUMMARY,
+ withIssue = false
+ )
+ )
+ }
+
+ context.launchSafetyCenterActivity {
+ waitDisplayed(
+ By.text(context.getString(safetyCenterTestConfigs.dynamicSourceGroup1.titleResId))
+ ) {
+ it.click()
+ }
+
+ waitAllTextNotDisplayed(
+ context.getString(safetyCenterTestConfigs.dynamicSourceGroup1.summaryResId)
+ )
+ waitAllTextDisplayed(
+ SAFETY_SOURCE_1_TITLE,
+ SAFETY_SOURCE_1_SUMMARY,
+ SAFETY_SOURCE_2_TITLE,
+ SAFETY_SOURCE_2_SUMMARY
+ )
+ }
+ }
+
+ @Test
+ fun expandedEntryGroup_collapsesWhenClicked() {
+ with(safetyCenterTestHelper) {
+ setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig)
+ setData(
+ SOURCE_ID_1,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_1_TITLE,
+ entrySummary = SAFETY_SOURCE_1_SUMMARY,
+ withIssue = false
+ )
+ )
+ setData(
+ SOURCE_ID_2,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_2_TITLE,
+ entrySummary = SAFETY_SOURCE_2_SUMMARY,
+ withIssue = false
+ )
+ )
+ setData(
+ SOURCE_ID_3,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_3_TITLE,
+ entrySummary = SAFETY_SOURCE_3_SUMMARY,
+ withIssue = false
+ )
+ )
+ setData(
+ SOURCE_ID_4,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_4_TITLE,
+ entrySummary = SAFETY_SOURCE_4_SUMMARY,
+ withIssue = false
+ )
+ )
+ setData(
+ SOURCE_ID_5,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_5_TITLE,
+ entrySummary = SAFETY_SOURCE_5_SUMMARY,
+ withIssue = false
+ )
+ )
+ }
+
+ context.launchSafetyCenterActivity {
+ waitDisplayed(
+ By.text(context.getString(safetyCenterTestConfigs.dynamicSourceGroup1.titleResId))
+ ) {
+ it.click()
+ }
+
+ waitDisplayed(
+ By.text(context.getString(safetyCenterTestConfigs.dynamicSourceGroup1.titleResId))
+ ) {
+ it.click()
+ }
+
+ waitAllTextDisplayed(
+ context.getString(safetyCenterTestConfigs.dynamicSourceGroup1.titleResId)
+ )
+ waitAllTextNotDisplayed(SAFETY_SOURCE_1_TITLE, SAFETY_SOURCE_2_TITLE)
+ }
+ }
+
+ @Test
+ fun expandedEntryGroup_rotation_remainsExpanded() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig)
+
+ context.launchSafetyCenterActivity {
+ waitDisplayed(
+ By.text(context.getString(safetyCenterTestConfigs.dynamicSourceGroup1.titleResId))
+ ) {
+ it.click()
+ }
+
+ getUiDevice().rotate()
+
+ waitAllTextNotDisplayed(
+ context.getString(safetyCenterTestConfigs.dynamicSourceGroup1.summaryResId)
+ )
+ waitAllTextDisplayed(
+ context.getString(safetyCenterTestConfigs.dynamicSource1.titleResId),
+ context.getString(safetyCenterTestConfigs.dynamicSource2.titleResId)
+ )
+ }
+ }
+
+ @Test
+ fun expandedEntryGroup_otherGroupRemainsCollapsed() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig)
+ with(safetyCenterTestHelper) {
+ setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig)
+ setData(
+ SOURCE_ID_1,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_1_TITLE,
+ entrySummary = SAFETY_SOURCE_1_SUMMARY,
+ withIssue = false
+ )
+ )
+ setData(
+ SOURCE_ID_2,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_2_TITLE,
+ entrySummary = SAFETY_SOURCE_2_SUMMARY,
+ withIssue = false
+ )
+ )
+ setData(
+ SOURCE_ID_3,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_3_TITLE,
+ entrySummary = SAFETY_SOURCE_3_SUMMARY,
+ withIssue = false
+ )
+ )
+ setData(
+ SOURCE_ID_4,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_4_TITLE,
+ entrySummary = SAFETY_SOURCE_4_SUMMARY,
+ withIssue = false
+ )
+ )
+ setData(
+ SOURCE_ID_5,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_5_TITLE,
+ entrySummary = SAFETY_SOURCE_5_SUMMARY,
+ withIssue = false
+ )
+ )
+ }
+
+ context.launchSafetyCenterActivity {
+ waitDisplayed(
+ By.text(context.getString(safetyCenterTestConfigs.dynamicSourceGroup1.titleResId))
+ ) {
+ it.click()
+ }
+
+ waitAllTextNotDisplayed(
+ context.getString(safetyCenterTestConfigs.dynamicSourceGroup1.summaryResId)
+ )
+ waitAllTextDisplayed(
+ context.getString(safetyCenterTestConfigs.dynamicSourceGroup3.summaryResId)
+ )
+ }
+ }
+
+ @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
+ with(safetyCenterTestHelper) {
+ setConfig(config)
+ setData(SOURCE_ID_1, sourceTestData)
+ setData(SOURCE_ID_2, sourceTestData)
+ setData(SOURCE_ID_3, sourceTestData)
+ setData(SOURCE_ID_4, sourceTestData)
+ setData(SOURCE_ID_5, sourceTestData)
+ }
+ val firstGroup = config.safetySourcesGroups.first()
+ val lastGroup = config.safetySourcesGroups.last()
+
+ context.launchSafetyCenterActivity {
+ waitAllTextDisplayed(
+ context.getString(lastGroup.titleResId),
+ context.getString(lastGroup.summaryResId)
+ )
+
+ waitDisplayed(By.text(context.getString(firstGroup.titleResId))) { it.click() }
+
+ waitAllTextDisplayed(
+ sourceTestData.status!!.title,
+ sourceTestData.status!!.summary,
+ context.getString(lastGroup.titleResId),
+ context.getString(lastGroup.summaryResId),
+ )
+ }
+ }
+
+ @Test
+ fun startStaticEntryActivity_noConfigToBeSettingsActivity_noExtraInBundle() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.implicitIntentSingleSourceConfig)
+
+ context.launchSafetyCenterActivity {
+ waitDisplayed(By.text("OK")) { it.click() }
+ waitDisplayed(By.text("is_from_settings_homepage false"))
+ waitButtonDisplayed("Exit test activity") { it.click() }
+ }
+ }
+
+ @Test
+ fun startStaticEntryActivity_withConfigToBeSettingsActivity_trueExtraInBundle() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleStaticSettingsSource)
+
+ context.launchSafetyCenterActivity {
+ waitDisplayed(By.text("OK")) { it.click() }
+ waitDisplayed(By.text("is_from_settings_homepage true"))
+ waitButtonDisplayed("Exit test activity") { it.click() }
+ }
+ }
+
+ 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"
+ }
+}
diff --git a/tests/functional/safetycenter/singleuser/Android.bp b/tests/functional/safetycenter/singleuser/Android.bp
new file mode 100644
index 000000000..995f3ca40
--- /dev/null
+++ b/tests/functional/safetycenter/singleuser/Android.bp
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "SafetyCenterFunctionalTestCases",
+ 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-internal-data",
+ "safety-center-pending-intents",
+ "safety-center-test-util-lib",
+ ],
+ test_suites: [
+ "general-tests",
+ "mts-permission",
+ ],
+}
diff --git a/tests/functional/safetycenter/singleuser/AndroidManifest.xml b/tests/functional/safetycenter/singleuser/AndroidManifest.xml
new file mode 100644
index 000000000..7ca38dede
--- /dev/null
+++ b/tests/functional/safetycenter/singleuser/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?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">
+ <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>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:label="Functional tests for SafetyCenter"
+ android:targetPackage="android.safetycenter.functional"/>
+
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+</manifest>
diff --git a/tests/functional/safetycenter/singleuser/AndroidTest.xml b/tests/functional/safetycenter/singleuser/AndroidTest.xml
new file mode 100644
index 000000000..d9d5b1361
--- /dev/null
+++ b/tests/functional/safetycenter/singleuser/AndroidTest.xml
@@ -0,0 +1,61 @@
+<?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 functional SafetyCenter test cases">
+
+ <object
+ class="com.android.tradefed.testtype.suite.module.Sdk33ModuleController"
+ 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="SafetyCenterFunctionalTestCases.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" />
+ <!-- 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" />
+ </target_preparer>
+
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/data/user/0/android.safetycenter.functional/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"/>
+ <option name="exclude-annotation" value="org.junit.Ignore"/>
+ <option name="runtime-hint" value="10m"/>
+ </test>
+</configuration>
diff --git a/tests/functional/safetycenter/singleuser/TEST_MAPPING b/tests/functional/safetycenter/singleuser/TEST_MAPPING
new file mode 100644
index 000000000..8285ecd5a
--- /dev/null
+++ b/tests/functional/safetycenter/singleuser/TEST_MAPPING
@@ -0,0 +1,17 @@
+{
+ "presubmit": [
+ {
+ "name": "SafetyCenterFunctionalTestCases"
+ }
+ ],
+ "mainline-presubmit": [
+ {
+ "name": "SafetyCenterFunctionalTestCases[com.google.android.permission.apex]",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.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
new file mode 100644
index 000000000..75d2fd57d
--- /dev/null
+++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterManagerTest.kt
@@ -0,0 +1,3674 @@
+/*
+ * 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.safetycenter.functional
+
+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.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_OK
+import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION
+import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN
+import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED
+import android.safetycenter.SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO
+import android.safetycenter.SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON
+import android.safetycenter.SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION
+import android.safetycenter.SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY
+import android.safetycenter.SafetyCenterEntryGroup
+import android.safetycenter.SafetyCenterEntryOrGroup
+import android.safetycenter.SafetyCenterErrorDetails
+import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetyCenterManager.REFRESH_REASON_OTHER
+import android.safetycenter.SafetyCenterManager.REFRESH_REASON_PAGE_OPEN
+import android.safetycenter.SafetyCenterManager.REFRESH_REASON_RESCAN_BUTTON_CLICK
+import android.safetycenter.SafetyCenterStaticEntry
+import android.safetycenter.SafetyCenterStaticEntryGroup
+import android.safetycenter.SafetyCenterStatus
+import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING
+import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK
+import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION
+import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN
+import android.safetycenter.SafetyCenterStatus.REFRESH_STATUS_DATA_FETCH_IN_PROGRESS
+import android.safetycenter.SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS
+import android.safetycenter.SafetyCenterStatus.REFRESH_STATUS_NONE
+import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING
+import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_INFORMATION
+import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION
+import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED
+import android.safetycenter.SafetySourceErrorDetails
+import android.safetycenter.SafetySourceIssue
+import android.safetycenter.config.SafetyCenterConfig
+import android.safetycenter.config.SafetySource
+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.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.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_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
+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
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.DYNAMIC_HIDDEN_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.DYNAMIC_HIDDEN_WITH_SEARCH_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.DYNAMIC_IN_STATEFUL_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.DYNAMIC_IN_STATELESS_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.DYNAMIC_OTHER_PACKAGE_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.ISSUE_ONLY_ALL_OPTIONAL_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.ISSUE_ONLY_BAREBONE_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.ISSUE_ONLY_GROUP_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.ISSUE_ONLY_IN_STATELESS_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.MIXED_STATEFUL_GROUP_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.MIXED_STATELESS_GROUP_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.MULTIPLE_SOURCES_GROUP_ID_1
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.MULTIPLE_SOURCES_GROUP_ID_2
+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.SafetyCenterTestConfigs.Companion.SOURCE_ID_4
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_5
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_6
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_7
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.STATIC_IN_STATEFUL_ID
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SUMMARY_TEST_GROUP_ID
+import com.android.safetycenter.testing.SafetyCenterTestData
+import com.android.safetycenter.testing.SafetyCenterTestData.Companion.withAttributionTitleInIssuesIfAtLeastU
+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.SafetySourceIntentHandler.Request
+import com.android.safetycenter.testing.SafetySourceIntentHandler.Response
+import com.android.safetycenter.testing.SafetySourceReceiver
+import com.android.safetycenter.testing.SafetySourceReceiver.Companion.dismissSafetyCenterIssueWithPermissionAndWait
+import com.android.safetycenter.testing.SafetySourceReceiver.Companion.executeSafetyCenterIssueActionWithPermissionAndWait
+import com.android.safetycenter.testing.SafetySourceReceiver.Companion.refreshSafetySourcesWithReceiverPermissionAndWait
+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 com.android.safetycenter.testing.SafetySourceTestData.Companion.EVENT_SOURCE_STATE_CHANGED
+import com.android.safetycenter.testing.SafetySourceTestData.Companion.INFORMATION_ISSUE_ID
+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.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.Test
+import org.junit.runner.RunWith
+
+/** Functional tests for [SafetyCenterManager]. */
+@RunWith(AndroidJUnit4::class)
+class SafetyCenterManagerTest {
+ private val context: Context = getApplicationContext()
+ private val safetyCenterResourcesContext = SafetyCenterResourcesContext.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 safetyCenterStatusUnknownScanning =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesContext.getStringByName("scanning_title"),
+ safetyCenterResourcesContext.getStringByName("loading_summary")
+ )
+ .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)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK)
+ .build()
+
+ private val safetyCenterStatusOkReviewOneAlert =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_ok_review_title"
+ ),
+ safetyCenterTestData.getAlertString(1)
+ )
+ .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"
+ )
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK)
+ .build()
+
+ private val safetyCenterStatusGeneralRecommendationOneAlert =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_safety_recommendation_title"
+ ),
+ safetyCenterTestData.getAlertString(1)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_RECOMMENDATION)
+ .build()
+
+ private val safetyCenterStatusAccountRecommendationOneAlert =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_account_recommendation_title"
+ ),
+ safetyCenterTestData.getAlertString(1)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_RECOMMENDATION)
+ .build()
+
+ private val safetyCenterStatusDeviceRecommendationOneAlert =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_device_recommendation_title"
+ ),
+ safetyCenterTestData.getAlertString(1)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_RECOMMENDATION)
+ .build()
+
+ private val safetyCenterStatusGeneralCriticalOneAlert =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_critical_safety_warning_title"
+ ),
+ safetyCenterTestData.getAlertString(1)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .build()
+
+ private val safetyCenterStatusGeneralCriticalTwoAlerts =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_critical_safety_warning_title"
+ ),
+ safetyCenterTestData.getAlertString(2)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .build()
+
+ private val safetyCenterStatusAccountCriticalOneAlert =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_critical_account_warning_title"
+ ),
+ safetyCenterTestData.getAlertString(1)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .build()
+
+ private val safetyCenterStatusAccountCriticalTwoAlerts =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_critical_account_warning_title"
+ ),
+ safetyCenterTestData.getAlertString(2)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .build()
+
+ private val safetyCenterStatusDeviceCriticalOneAlert =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_critical_device_warning_title"
+ ),
+ safetyCenterTestData.getAlertString(1)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .build()
+
+ private val safetyCenterStatusDeviceCriticalTwoAlerts =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_critical_device_warning_title"
+ ),
+ safetyCenterTestData.getAlertString(2)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .build()
+
+ private val safetyCenterEntryOrGroupRecommendation =
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID)
+ )
+
+ private val safetyCenterEntryOrGroupCritical =
+ SafetyCenterEntryOrGroup(safetyCenterTestData.safetyCenterEntryCritical(SINGLE_SOURCE_ID))
+
+ 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()
+ )
+ )
+ .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()
+ )
+ )
+
+ 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 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 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 safetyCenterDataDeviceCriticalOneAlert =
+ SafetyCenterData(
+ safetyCenterStatusDeviceCriticalOneAlert,
+ 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 safetyCenterDataOkReviewOneDismissedAlertInFlight =
+ SafetyCenterData(
+ safetyCenterStatusOkReview,
+ emptyList(),
+ listOf(safetyCenterEntryOrGroupCritical),
+ emptyList()
+ )
+ .withDismissedIssuesIfAtLeastU(
+ listOf(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SINGLE_SOURCE_ID,
+ isActionInFlight = true
+ )
+ )
+ )
+
+ 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")
+ )
+ .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
+ ),
+ 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
+ ),
+ 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()
+ )
+ )
+ .build()
+ ),
+ safetyCenterEntryGroupMixedFromComplexConfig
+ ),
+ 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()
+
+ @Before
+ fun assumeDeviceSupportsSafetyCenterToRunTests() {
+ assumeTrue(shouldRunTests)
+ }
+
+ @Before
+ fun enableSafetyCenterBeforeTest() {
+ if (!shouldRunTests) {
+ return
+ }
+ safetyCenterTestHelper.setup()
+ }
+
+ @After
+ fun clearDataAfterTest() {
+ if (!shouldRunTests) {
+ return
+ }
+ safetyCenterTestHelper.reset()
+ }
+
+ @Test
+ fun refreshSafetySources_withShowEntriesOnTimeout_marksSafetySourceAsError() {
+ SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_SHORT)
+ SafetyCenterFlags.showErrorEntriesOnTimeout = true
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+
+ val safetyCenterBeforeTimeout = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterBeforeTimeout).isEqualTo(safetyCenterDataFromConfigScanning)
+ val safetyCenterDataAfterTimeout = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataAfterTimeout).isEqualTo(safetyCenterDataUnknownReviewError)
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterErrorDetails(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun refreshSafetySources_withShowEntriesOnTimeout_keepsShowingErrorUntilClearedBySource() {
+ SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_SHORT)
+ SafetyCenterFlags.showErrorEntriesOnTimeout = true
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val listener = safetyCenterTestHelper.addListener()
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+ val scanningData = listener.receiveSafetyCenterData()
+ checkState(scanningData == safetyCenterDataFromConfigScanning)
+ val initialData = listener.receiveSafetyCenterData()
+ checkState(initialData == safetyCenterDataUnknownReviewError)
+
+ SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_LONG)
+ SafetySourceReceiver.setResponse(
+ Request.Rescan(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+
+ val safetyCenterDataWhenTryingAgain = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataWhenTryingAgain)
+ .isEqualTo(safetyCenterDataUnknownScanningWithError)
+ val safetyCenterDataWhenFinishingRefresh = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataWhenFinishingRefresh).isEqualTo(safetyCenterDataOk)
+ }
+
+ @Test
+ fun refreshSafetySources_withShowEntriesOnTimeout_doesntSetErrorForBackgroundRefreshes() {
+ SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_SHORT)
+ SafetyCenterFlags.showErrorEntriesOnTimeout = true
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(REFRESH_REASON_OTHER)
+
+ val safetyCenterBeforeTimeout = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterBeforeTimeout.status.refreshStatus)
+ .isEqualTo(REFRESH_STATUS_DATA_FETCH_IN_PROGRESS)
+ val safetyCenterDataAfterTimeout = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataAfterTimeout).isEqualTo(safetyCenterDataFromConfig)
+ }
+
+ @Test
+ fun refreshSafetySources_withRefreshReasonRescanButtonClick_notifiesUiDuringRescan() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Rescan(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+
+ val status1 = listener.receiveSafetyCenterData().status
+ assertThat(status1.refreshStatus).isEqualTo(REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS)
+ assertThat(status1.title.toString())
+ .isEqualTo(safetyCenterResourcesContext.getStringByName("scanning_title"))
+ assertThat(status1.summary.toString())
+ .isEqualTo(safetyCenterResourcesContext.getStringByName("loading_summary"))
+ val status2 = listener.receiveSafetyCenterData().status
+ assertThat(status2.refreshStatus).isEqualTo(REFRESH_STATUS_NONE)
+ assertThat(status2).isEqualTo(safetyCenterStatusOk)
+ }
+
+ @Test
+ fun refreshSafetySources_withRefreshReasonPageOpen_notifiesUiWithFetch() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN
+ )
+
+ val status1 = listener.receiveSafetyCenterData().status
+ assertThat(status1.refreshStatus).isEqualTo(REFRESH_STATUS_DATA_FETCH_IN_PROGRESS)
+ assertThat(status1.title.toString())
+ .isEqualTo(safetyCenterResourcesContext.getStringByName("scanning_title"))
+ assertThat(status1.summary.toString())
+ .isEqualTo(safetyCenterResourcesContext.getStringByName("loading_summary"))
+ val status2 = listener.receiveSafetyCenterData().status
+ assertThat(status2.refreshStatus).isEqualTo(REFRESH_STATUS_NONE)
+ assertThat(status2).isEqualTo(safetyCenterStatusOk)
+ }
+
+ @Test
+ fun refreshSafetySources_pageOpenRefreshWithPreExistingData_notifiesUiWithExistingTitle() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN
+ )
+
+ val status1 = listener.receiveSafetyCenterData().status
+ 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"))
+ val status2 = listener.receiveSafetyCenterData().status
+ assertThat(status2.refreshStatus).isEqualTo(REFRESH_STATUS_NONE)
+ assertThat(status2).isEqualTo(safetyCenterStatusOk)
+ }
+
+ @Test
+ fun getSafetyCenterData_withoutDataProvided_returnsDataFromConfig() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataFromConfig)
+ }
+
+ @Test
+ fun getSafetyCenterData_withoutDataImplicitIntentConfig_defaultEntryHasImplicitIntent() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.implicitIntentSingleSourceConfig)
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ val implicitPendingIntentCreatedByCts =
+ PendingIntent.getActivity(
+ context,
+ 0 /* requestCode */,
+ Intent(ACTION_TEST_ACTIVITY_EXPORTED),
+ PendingIntent.FLAG_IMMUTABLE
+ )
+ val defaultEntryPendingIntent =
+ apiSafetyCenterData.entriesOrGroups.firstOrNull()?.entry?.pendingIntent
+ val defaultEntryIntentFilterEqualsToImplicitIntent =
+ callWithShellPermissionIdentity("android.permission.GET_INTENT_SENDER_INTENT") {
+ implicitPendingIntentCreatedByCts.intentFilterEquals(defaultEntryPendingIntent)
+ }
+ assertThat(defaultEntryIntentFilterEqualsToImplicitIntent).isTrue()
+ }
+
+ @Test
+ fun getSafetyCenterData_withComplexConfigWithoutDataProvided_returnsDataFromConfig() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData.withoutExtras()).isEqualTo(safetyCenterDataFromComplexConfig)
+ }
+
+ @Test
+ fun getSafetyCenterData_withOnlyHiddenSourcesWithoutDataProvided_returnsNoGroups() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.hiddenOnlyConfig)
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData)
+ .isEqualTo(
+ SafetyCenterData(safetyCenterStatusOk, emptyList(), emptyList(), emptyList())
+ )
+ }
+
+ @Test
+ fun getSafetyCenterData_withSomeDataProvided_returnsDataProvided() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.unspecified)
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataUnspecified)
+ }
+
+ @Test
+ fun getSafetyCenterData_withIconAction_returnsDataWithIconAction() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.informationWithIconAction
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataOkWithIconAction)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_attributionTitleProvidedBySource_returnsIssueWithAttributionTitle() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.informationWithIssueWithAttributionTitle
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ val expectedSafetyCenterData =
+ safetyCenterDataOkOneAlert.withAttributionTitleInIssuesIfAtLeastU("Attribution Title")
+ assertThat(apiSafetyCenterData).isEqualTo(expectedSafetyCenterData)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_attributionTitleNotProvided_returnsGroupTitleAsAttributionTitle() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.informationWithIssue)
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ val expectedSafetyCenterData =
+ safetyCenterDataOkOneAlert.withAttributionTitleInIssuesIfAtLeastU("OK")
+ assertThat(apiSafetyCenterData).isEqualTo(expectedSafetyCenterData)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_attributionNotSetAndGroupTitleNull_returnsNullAttributionTitle() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceNoGroupTitleConfig)
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ SafetySourceTestData.issuesOnly(safetySourceTestData.recommendationGeneralIssue)
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ val expectedSafetyCenterData =
+ SafetyCenterData(
+ safetyCenterStatusGeneralRecommendationOneAlert,
+ listOf(
+ safetyCenterTestData.safetyCenterIssueRecommendation(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ attributionTitle = null
+ )
+ ),
+ emptyList(),
+ emptyList()
+ )
+ assertThat(apiSafetyCenterData).isEqualTo(expectedSafetyCenterData)
+ }
+
+ @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)
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataOkOneAlert)
+ }
+
+ @Test
+ fun getSafetyCenterData_withUpdatedData_returnsUpdatedData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+ val previousApiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData).isNotEqualTo(previousApiSafetyCenterData)
+ assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataGeneralCriticalOneAlert)
+ }
+
+ @Test
+ fun getSafetyCenterData_reportError_returnsUnknownReviewErrorStatus() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterManager.reportSafetySourceErrorWithPermission(
+ SINGLE_SOURCE_ID,
+ SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED)
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataUnknownReviewError)
+ }
+
+ @Test
+ fun getSafetyCenterData_withInformationIssue_returnsOverallStatusOkWithOneAlert() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.informationWithIssue)
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataOkOneAlert)
+ }
+
+ @Test
+ fun getSafetyCenterData_withCriticalStatusAndInfoIssue_returnsOverallStatusOkReviewOneAlert() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithInformationIssue
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataOkReviewOneAlert)
+ }
+
+ @Test
+ fun getSafetyCenterData_withRecommendationGeneralIssue_returnsGeneralRecommendationOneAlert() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.recommendationWithGeneralIssue
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataGeneralRecommendationOneAlert)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_withActionConfirmation_returnsRecommendationWithActionConfirmation() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.recommendationWithIssueWithActionConfirmation
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData)
+ .isEqualTo(safetyCenterDataGeneralRecommendationAlertWithConfirmation)
+ }
+
+ @Test
+ fun getSafetyCenterData_withRecommendationAccountIssue_returnsAccountRecommendationOneAlert() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.recommendationWithAccountIssue
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataAccountRecommendationOneAlert)
+ }
+
+ @Test
+ fun getSafetyCenterData_withRecommendationDeviceIssue_returnsDeviceRecommendationOneAlert() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.recommendationWithDeviceIssue
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataDeviceRecommendationOneAlert)
+ }
+
+ @Test
+ fun getSafetyCenterData_withCriticalGeneralIssue_returnsOverallStatusGeneralCriticalOneAlert() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataGeneralCriticalOneAlert)
+ }
+
+ @Test
+ fun getSafetyCenterData_withCriticalAccountIssue_returnsOverallStatusAccountCriticalOneAlert() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingAccountIssue
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataAccountCriticalOneAlert)
+ }
+
+ @Test
+ fun getSafetyCenterData_withCriticalDeviceIssue_returnsOverallStatusDeviceCriticalOneAlert() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingDeviceIssue
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataDeviceCriticalOneAlert)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_withRecommendationDataIssue_returnsDataRecommendationStatus() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder()
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DATA)
+ .build()
+ )
+ )
+
+ val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status
+
+ assertThat(apiSafetyCenterStatus)
+ .isEqualTo(
+ safetyCenterTestData.safetyCenterStatusOneAlert(
+ "overall_severity_level_data_recommendation_title",
+ OVERALL_SEVERITY_LEVEL_RECOMMENDATION
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_withCriticalDataIssue_returnsDataCriticalStatus() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData
+ .defaultCriticalResolvingIssueBuilder()
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DATA)
+ .build()
+ )
+ )
+
+ val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status
+
+ assertThat(apiSafetyCenterStatus)
+ .isEqualTo(
+ safetyCenterTestData.safetyCenterStatusOneAlert(
+ "overall_severity_level_critical_data_warning_title",
+ OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_withRecommendationPasswordsIssue_returnsDataRecommendationStatus() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder()
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_PASSWORDS)
+ .build()
+ )
+ )
+
+ val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status
+
+ assertThat(apiSafetyCenterStatus)
+ .isEqualTo(
+ safetyCenterTestData.safetyCenterStatusOneAlert(
+ "overall_severity_level_passwords_recommendation_title",
+ OVERALL_SEVERITY_LEVEL_RECOMMENDATION
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_withCriticalPasswordsIssue_returnsDataCriticalStatus() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData
+ .defaultCriticalResolvingIssueBuilder()
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_PASSWORDS)
+ .build()
+ )
+ )
+
+ val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status
+
+ assertThat(apiSafetyCenterStatus)
+ .isEqualTo(
+ safetyCenterTestData.safetyCenterStatusOneAlert(
+ "overall_severity_level_critical_passwords_warning_title",
+ OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_withRecommendationPersonalIssue_returnsDataRecommendationStatus() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder()
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_PERSONAL_SAFETY)
+ .build()
+ )
+ )
+
+ val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status
+
+ assertThat(apiSafetyCenterStatus)
+ .isEqualTo(
+ safetyCenterTestData.safetyCenterStatusOneAlert(
+ "overall_severity_level_personal_recommendation_title",
+ OVERALL_SEVERITY_LEVEL_RECOMMENDATION
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_withCriticalPersonalIssue_returnsDataCriticalStatus() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData
+ .defaultCriticalResolvingIssueBuilder()
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_PERSONAL_SAFETY)
+ .build()
+ )
+ )
+
+ val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status
+
+ assertThat(apiSafetyCenterStatus)
+ .isEqualTo(
+ safetyCenterTestData.safetyCenterStatusOneAlert(
+ "overall_severity_level_critical_personal_warning_title",
+ OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_infoStatusTipFirstIssueSingleTip_infoStatusWithTipSummary() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData
+ .defaultInformationIssueBuilder()
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_TIP)
+ .build()
+ )
+ )
+
+ val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status
+
+ assertThat(apiSafetyCenterStatus)
+ .isEqualTo(safetyCenterTestData.safetyCenterStatusTips(numTipIssues = 1))
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_infoStatusTipFirstIssueMultiTips_infoStatusWithTipsSummary() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData
+ .defaultInformationIssueBuilder("id_1")
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_TIP)
+ .build(),
+ safetySourceTestData
+ .defaultInformationIssueBuilder("id_2")
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_MANUAL)
+ .build(),
+ safetySourceTestData
+ .defaultInformationIssueBuilder("id_3")
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC)
+ .build(),
+ safetySourceTestData
+ .defaultInformationIssueBuilder("id_4")
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_TIP)
+ .build(),
+ safetySourceTestData
+ .defaultInformationIssueBuilder("id_5")
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_TIP)
+ .build(),
+ )
+ )
+
+ val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status
+
+ assertThat(apiSafetyCenterStatus)
+ .isEqualTo(safetyCenterTestData.safetyCenterStatusTips(numTipIssues = 3))
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_infoStatusActionFirstIssueSingleAction_infoStatusWithActionSummary() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData
+ .defaultInformationIssueBuilder()
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC)
+ .build()
+ )
+ )
+
+ val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status
+
+ assertThat(apiSafetyCenterStatus)
+ .isEqualTo(safetyCenterTestData.safetyCenterStatusActionsTaken(numAutomaticIssues = 1))
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_infoStatusActionFirstIssueMultiActions_infoStatusWithActionsSummary() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData
+ .defaultInformationIssueBuilder("id_1")
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC)
+ .build(),
+ safetySourceTestData
+ .defaultInformationIssueBuilder("id_2")
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_TIP)
+ .build(),
+ safetySourceTestData
+ .defaultInformationIssueBuilder("id_3")
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC)
+ .build(),
+ safetySourceTestData
+ .defaultInformationIssueBuilder("id_4")
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_TIP)
+ .build(),
+ safetySourceTestData
+ .defaultInformationIssueBuilder("id_5")
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_MANUAL)
+ .build(),
+ )
+ )
+
+ val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status
+
+ assertThat(apiSafetyCenterStatus)
+ .isEqualTo(safetyCenterTestData.safetyCenterStatusActionsTaken(numAutomaticIssues = 2))
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_infoStatusManualFirstIssueSingleManual_infoStatusWithAlertSummary() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData
+ .defaultInformationIssueBuilder()
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_MANUAL)
+ .build(),
+ )
+ )
+
+ val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status
+
+ assertThat(apiSafetyCenterStatus)
+ .isEqualTo(
+ safetyCenterTestData.safetyCenterStatusNAlerts(
+ "overall_severity_level_ok_title",
+ OVERALL_SEVERITY_LEVEL_OK,
+ numAlerts = 1
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_infoStatusManualFirstIssueMultiManual_infoStatusWithAlertsSummary() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceConfig)
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData
+ .defaultInformationIssueBuilder("id_1")
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_MANUAL)
+ .build(),
+ safetySourceTestData
+ .defaultInformationIssueBuilder("id_2")
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_TIP)
+ .build(),
+ safetySourceTestData
+ .defaultInformationIssueBuilder("id_3")
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_MANUAL)
+ .build(),
+ safetySourceTestData
+ .defaultInformationIssueBuilder("id_4")
+ .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC)
+ .build(),
+ )
+ )
+
+ val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status
+
+ assertThat(apiSafetyCenterStatus)
+ .isEqualTo(
+ safetyCenterTestData.safetyCenterStatusNAlerts(
+ "overall_severity_level_ok_title",
+ OVERALL_SEVERITY_LEVEL_OK,
+ numAlerts = 2
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_withStaticEntryGroups_hasStaticEntriesToIdsMapping() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.staticSourcesConfig)
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(
+ SafetyCenterBundles.getStaticEntryId(
+ apiSafetyCenterData,
+ apiSafetyCenterData.staticEntryGroups[0].staticEntries[0]
+ )
+ )
+ .isEqualTo(
+ SafetyCenterEntryId.newBuilder()
+ .setSafetySourceId("test_static_source_id_1")
+ .setUserId(UserHandle.myUserId())
+ .build()
+ )
+ assertThat(
+ SafetyCenterBundles.getStaticEntryId(
+ apiSafetyCenterData,
+ apiSafetyCenterData.staticEntryGroups[1].staticEntries[0]
+ )
+ )
+ .isEqualTo(
+ SafetyCenterEntryId.newBuilder()
+ .setSafetySourceId("test_static_source_id_2")
+ .setUserId(UserHandle.myUserId())
+ .build()
+ )
+ }
+
+ @Test
+ fun getSafetyCenterData_singleSourceIssues_returnsOverallStatusBasedOnHigherSeverityIssue() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingDeviceIssueAndRecommendationIssue
+ )
+
+ val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status
+
+ assertThat(apiSafetyCenterStatus).isEqualTo(safetyCenterStatusDeviceCriticalTwoAlerts)
+ }
+
+ @Test
+ fun getSafetyCenterData_multipleSourcesIssues_returnsOverallStatusBasedOnHigherSeverityIssue() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ safetySourceTestData.recommendationWithAccountIssue
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_3,
+ safetySourceTestData.criticalWithResolvingDeviceIssue
+ )
+
+ val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status
+
+ assertThat(apiSafetyCenterStatus).isEqualTo(safetyCenterStatusDeviceCriticalTwoAlerts)
+ }
+
+ @Test
+ fun getSafetyCenterData_multipleIssues_returnsOverallStatusBasedOnConfigOrdering() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_3,
+ safetySourceTestData.criticalWithResolvingDeviceIssue
+ )
+
+ val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status
+
+ assertThat(apiSafetyCenterStatus).isEqualTo(safetyCenterStatusGeneralCriticalTwoAlerts)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_duplicateIssuesOfSameSeverities_issueOfFirstSourceInConfigShown() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+
+ val apiSafetyCenterIssues = safetyCenterManager.getSafetyCenterDataWithPermission().issues
+
+ assertThat(apiSafetyCenterIssues)
+ .containsExactly(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SOURCE_ID_1,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_1
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_duplicateIssuesInDifferentSourceGroups_topIssueRelevantForBothGroups() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ // Belongs to DEDUPLICATION_GROUP_1 and source group MULTIPLE_SOURCES_GROUP_ID_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_1 and source group MULTIPLE_SOURCES_GROUP_ID_2
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+ val issueId = apiSafetyCenterData.issues.first().id
+ val issueToGroupBelonging =
+ apiSafetyCenterData.extras.getBundle(ISSUES_TO_GROUPS_BUNDLE_KEY)
+
+ assertThat(issueToGroupBelonging!!.getStringArrayList(issueId))
+ .containsExactly(MULTIPLE_SOURCES_GROUP_ID_1, MULTIPLE_SOURCES_GROUP_ID_2)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_duplicateIssuesInSameSourceGroups_topIssueRelevantForThatGroup() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ // Belongs to DEDUPLICATION_GROUP_1 and source group MULTIPLE_SOURCES_GROUP_ID_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_1 and source group MULTIPLE_SOURCES_GROUP_ID_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+ val issueId = apiSafetyCenterData.issues.first().id
+ val issueToGroupBelonging =
+ apiSafetyCenterData.extras.getBundle(ISSUES_TO_GROUPS_BUNDLE_KEY)
+
+ assertThat(issueToGroupBelonging!!.getStringArrayList(issueId))
+ .containsExactly(MULTIPLE_SOURCES_GROUP_ID_1)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_noDuplicateIssues_noGroupBelongingSpecified() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ // Belongs to DEDUPLICATION_GROUP_1 and source group MULTIPLE_SOURCES_GROUP_ID_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_3 and source group MULTIPLE_SOURCES_GROUP_ID_2
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_6,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.recommendationIssueWithDeduplicationId("same")
+ )
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+ val issueToGroupBelonging =
+ apiSafetyCenterData.extras.getBundle(ISSUES_TO_GROUPS_BUNDLE_KEY)
+
+ assertThat(issueToGroupBelonging).isNull()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_differentDuplicationId_bothIssuesShown() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("different")
+ )
+ )
+
+ val apiSafetyCenterIssues = safetyCenterManager.getSafetyCenterDataWithPermission().issues
+
+ assertThat(apiSafetyCenterIssues)
+ .containsExactly(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SOURCE_ID_1,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_1
+ ),
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SOURCE_ID_5,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_2
+ )
+ )
+ .inOrder()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_differentDuplicationGroup_bothIssuesShown() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_3
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_6,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+
+ val apiSafetyCenterIssues = safetyCenterManager.getSafetyCenterDataWithPermission().issues
+
+ assertThat(apiSafetyCenterIssues)
+ .containsExactly(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SOURCE_ID_1,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_1
+ ),
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SOURCE_ID_6,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_2
+ )
+ )
+ .inOrder()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_threeDuplicateIssues_onlyOneIssueShown() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ // Belongs to DEDUPLICATION_GROUP_3
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_4,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_3
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_6,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_3
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_7,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+
+ val apiSafetyCenterIssues = safetyCenterManager.getSafetyCenterDataWithPermission().issues
+
+ assertThat(apiSafetyCenterIssues)
+ .containsExactly(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SOURCE_ID_4,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_1
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_duplicateIssuesOfDifferentSeverities_moreSevereIssueShown() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.recommendationIssueWithDeduplicationId("same")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+
+ val apiSafetyCenterIssues = safetyCenterManager.getSafetyCenterDataWithPermission().issues
+
+ assertThat(apiSafetyCenterIssues)
+ .containsExactly(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SOURCE_ID_5,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_2
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_multipleDuplicationsOfIssues_correctlyDeduplicated() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.recommendationIssueWithDeduplicationId("A")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.recommendationIssueWithDeduplicationId("A")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_2
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_3,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.recommendationIssueWithDeduplicationId("B")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_3
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_4,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.recommendationIssueWithDeduplicationId("B")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("A")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_3
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_6,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.recommendationIssueWithDeduplicationId("B")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_3
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_7,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.recommendationIssueWithDeduplicationId("B")
+ )
+ )
+
+ val apiSafetyCenterIssues = safetyCenterManager.getSafetyCenterDataWithPermission().issues
+
+ assertThat(apiSafetyCenterIssues)
+ .containsExactly(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SOURCE_ID_5,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_2
+ ),
+ safetyCenterTestData.safetyCenterIssueRecommendation(
+ SOURCE_ID_3,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_1
+ ),
+ safetyCenterTestData.safetyCenterIssueRecommendation(
+ SOURCE_ID_4,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_1
+ )
+ )
+ .inOrder()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_duplicateIssuesBothDismissed_topOneShownAsDismissed() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.recommendationIssueWithDeduplicationId("same")
+ )
+ )
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SOURCE_ID_1, CRITICAL_ISSUE_ID)
+ )
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SOURCE_ID_5, RECOMMENDATION_ISSUE_ID)
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+ val apiSafetyCenterIssues = apiSafetyCenterData.issues
+ val apiSafetyCenterDismissedIssues = apiSafetyCenterData.dismissedIssues
+
+ assertThat(apiSafetyCenterIssues).isEmpty()
+ assertThat(apiSafetyCenterDismissedIssues)
+ .containsExactly(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SOURCE_ID_1,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_1
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_duplicateIssuesLowerSeverityOneDismissed_topOneShown() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.recommendationIssueWithDeduplicationId("same")
+ )
+ )
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SOURCE_ID_5, RECOMMENDATION_ISSUE_ID)
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+ val apiSafetyCenterIssues = apiSafetyCenterData.issues
+ val apiSafetyCenterDismissedIssues = apiSafetyCenterData.dismissedIssues
+
+ assertThat(apiSafetyCenterIssues)
+ .containsExactly(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SOURCE_ID_1,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_1
+ )
+ )
+ assertThat(apiSafetyCenterDismissedIssues).isEmpty()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_duplicateIssuesHigherSeverityOneDismissed_topOneShownAsDismissed() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.recommendationIssueWithDeduplicationId("same")
+ )
+ )
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SOURCE_ID_1, CRITICAL_ISSUE_ID)
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+ val apiSafetyCenterIssues = apiSafetyCenterData.issues
+ val apiSafetyCenterDismissedIssues = apiSafetyCenterData.dismissedIssues
+
+ assertThat(apiSafetyCenterIssues).isEmpty()
+ assertThat(apiSafetyCenterDismissedIssues)
+ .containsExactly(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SOURCE_ID_1,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_1
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_dupIssuesLowerPrioritySameSeverityOneDismissed_topShownAsDismissed() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SOURCE_ID_5, CRITICAL_ISSUE_ID)
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+ val apiSafetyCenterIssues = apiSafetyCenterData.issues
+ val apiSafetyCenterDismissedIssues = apiSafetyCenterData.dismissedIssues
+
+ assertThat(apiSafetyCenterIssues).isEmpty()
+ assertThat(apiSafetyCenterDismissedIssues)
+ .containsExactly(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SOURCE_ID_1,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_1
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_dupIssuesTopOneDismissedThenDisappears_bottomOneReemergesTimely() {
+ SafetyCenterFlags.tempHiddenIssueResurfaceDelay = Duration.ZERO
+ SafetyCenterFlags.resurfaceIssueMaxCounts = mapOf(SEVERITY_LEVEL_CRITICAL_WARNING to 99L)
+ SafetyCenterFlags.resurfaceIssueDelays =
+ mapOf(SEVERITY_LEVEL_CRITICAL_WARNING to RESURFACE_DELAY)
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SOURCE_ID_1, CRITICAL_ISSUE_ID)
+ )
+ safetyCenterTestHelper.setData(SOURCE_ID_1, SafetySourceTestData.issuesOnly())
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+ val apiSafetyCenterDismissedIssues = apiSafetyCenterData.dismissedIssues
+
+ assertThat(apiSafetyCenterDismissedIssues)
+ .containsExactly(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SOURCE_ID_5,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_2
+ )
+ )
+ waitForWithTimeout(timeout = RESURFACE_TIMEOUT, checkPeriod = RESURFACE_CHECK) {
+ val hasResurfaced =
+ safetyCenterManager
+ .getSafetyCenterDataWithPermission()
+ .issues
+ .contains(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SOURCE_ID_5,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_2
+ )
+ )
+ hasResurfaced
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_dupsOfDiffSeveritiesTopOneDismissedThenGone_bottomOneReemergesTimely() {
+ SafetyCenterFlags.tempHiddenIssueResurfaceDelay = Duration.ZERO
+ SafetyCenterFlags.resurfaceIssueMaxCounts =
+ mapOf(
+ SEVERITY_LEVEL_INFORMATION to 0L,
+ SEVERITY_LEVEL_RECOMMENDATION to 99L,
+ SEVERITY_LEVEL_CRITICAL_WARNING to 0L
+ )
+ SafetyCenterFlags.resurfaceIssueDelays =
+ mapOf(
+ SEVERITY_LEVEL_INFORMATION to Duration.ZERO,
+ SEVERITY_LEVEL_RECOMMENDATION to RESURFACE_DELAY,
+ SEVERITY_LEVEL_CRITICAL_WARNING to Duration.ZERO
+ )
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.recommendationIssueWithDeduplicationId("same")
+ )
+ )
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SOURCE_ID_1, CRITICAL_ISSUE_ID)
+ )
+ safetyCenterTestHelper.setData(SOURCE_ID_1, SafetySourceTestData.issuesOnly())
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+ val apiSafetyCenterDismissedIssues = apiSafetyCenterData.dismissedIssues
+
+ assertThat(apiSafetyCenterDismissedIssues)
+ .containsExactly(
+ safetyCenterTestData.safetyCenterIssueRecommendation(
+ SOURCE_ID_5,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_2
+ )
+ )
+ waitForWithTimeout(timeout = RESURFACE_TIMEOUT, checkPeriod = RESURFACE_CHECK) {
+ val hasResurfaced =
+ safetyCenterManager
+ .getSafetyCenterDataWithPermission()
+ .issues
+ .contains(
+ safetyCenterTestData.safetyCenterIssueRecommendation(
+ SOURCE_ID_5,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_2
+ )
+ )
+ hasResurfaced
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_duplicateIssuesLowerOneResurfaces_lowerOneStillFilteredOut() {
+ SafetyCenterFlags.resurfaceIssueMaxCounts =
+ mapOf(
+ SEVERITY_LEVEL_INFORMATION to 0L,
+ SEVERITY_LEVEL_RECOMMENDATION to 99L,
+ SEVERITY_LEVEL_CRITICAL_WARNING to 99L
+ )
+ SafetyCenterFlags.resurfaceIssueDelays =
+ mapOf(
+ SEVERITY_LEVEL_INFORMATION to Duration.ZERO,
+ SEVERITY_LEVEL_RECOMMENDATION to RESURFACE_DELAY,
+ SEVERITY_LEVEL_CRITICAL_WARNING to RESURFACE_DELAY.multipliedBy(100)
+ )
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.recommendationIssueWithDeduplicationId("same")
+ )
+ )
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SOURCE_ID_1, CRITICAL_ISSUE_ID)
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+ val apiSafetyCenterDismissedIssues = apiSafetyCenterData.dismissedIssues
+
+ assertThat(apiSafetyCenterDismissedIssues)
+ .containsExactly(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SOURCE_ID_1,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_1
+ )
+ )
+ assertFailsWith(TimeoutCancellationException::class) {
+ waitForWithTimeout(timeout = RESURFACE_TIMEOUT, checkPeriod = RESURFACE_CHECK) {
+ val hasResurfaced =
+ safetyCenterManager
+ .getSafetyCenterDataWithPermission()
+ .issues
+ .contains(
+ safetyCenterTestData.safetyCenterIssueRecommendation(
+ SOURCE_ID_5,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_2
+ )
+ )
+ hasResurfaced
+ }
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_duplicateIssuesTopOneResurfaces_topOneShown() {
+ SafetyCenterFlags.resurfaceIssueMaxCounts =
+ mapOf(
+ SEVERITY_LEVEL_INFORMATION to 0L,
+ SEVERITY_LEVEL_RECOMMENDATION to 99L,
+ SEVERITY_LEVEL_CRITICAL_WARNING to 99L
+ )
+ SafetyCenterFlags.resurfaceIssueDelays =
+ mapOf(
+ SEVERITY_LEVEL_INFORMATION to Duration.ZERO,
+ SEVERITY_LEVEL_RECOMMENDATION to RESURFACE_DELAY.multipliedBy(100),
+ SEVERITY_LEVEL_CRITICAL_WARNING to RESURFACE_DELAY
+ )
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.recommendationIssueWithDeduplicationId("same")
+ )
+ )
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SOURCE_ID_1, CRITICAL_ISSUE_ID)
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+ val apiSafetyCenterDismissedIssues = apiSafetyCenterData.dismissedIssues
+
+ assertThat(apiSafetyCenterDismissedIssues)
+ .containsExactly(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SOURCE_ID_1,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_1
+ )
+ )
+ waitForWithTimeout(timeout = RESURFACE_TIMEOUT, checkPeriod = RESURFACE_CHECK) {
+ val hasResurfaced =
+ safetyCenterManager
+ .getSafetyCenterDataWithPermission()
+ .issues
+ .contains(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SOURCE_ID_1,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_1
+ )
+ )
+ hasResurfaced
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun getSafetyCenterData_dupIssuesTopOneResolved_bottomOneReemergesAfterTemporaryHiddenPeriod() {
+ SafetyCenterFlags.tempHiddenIssueResurfaceDelay = RESURFACE_DELAY
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ // Belongs to DEDUPLICATION_GROUP_1
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+
+ val listener = safetyCenterTestHelper.addListener()
+ safetyCenterTestHelper.setData(SOURCE_ID_1, SafetySourceTestData.issuesOnly())
+
+ val apiSafetyCenterIssues = listener.receiveSafetyCenterData().issues
+
+ assertThat(apiSafetyCenterIssues).isEmpty()
+
+ waitForWithTimeout(timeout = RESURFACE_TIMEOUT, checkPeriod = RESURFACE_CHECK) {
+ val hasResurfaced =
+ safetyCenterManager
+ .getSafetyCenterDataWithPermission()
+ .issues
+ .contains(
+ safetyCenterTestData.safetyCenterIssueCritical(
+ SOURCE_ID_5,
+ groupId = MULTIPLE_SOURCES_GROUP_ID_2
+ )
+ )
+ hasResurfaced
+ }
+ }
+
+ @Test
+ fun getSafetyCenterData_criticalDeviceIssues_returnsOverallStatusBasedOnAddIssueCallOrder() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData
+ .defaultCriticalDataBuilder()
+ .addIssue(
+ safetySourceTestData
+ .defaultCriticalResolvingIssueBuilder("critical issue num 1")
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_ACCOUNT)
+ .build()
+ )
+ .addIssue(
+ safetySourceTestData
+ .defaultCriticalResolvingIssueBuilder("critical issue num 2")
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
+ .build()
+ )
+ .build()
+ )
+
+ val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status
+
+ assertThat(apiSafetyCenterStatus).isEqualTo(safetyCenterStatusAccountCriticalTwoAlerts)
+ }
+
+ @Test
+ fun getSafetyCenterData_withComplexConfigWithSomeDataProvided_returnsDataProvided() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig)
+ safetyCenterTestHelper.setData(
+ DYNAMIC_BAREBONE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ safetyCenterTestHelper.setData(
+ DYNAMIC_DISABLED_ID,
+ safetySourceTestData.recommendationWithGeneralIssue
+ )
+ safetyCenterTestHelper.setData(DYNAMIC_HIDDEN_ID, safetySourceTestData.unspecified)
+ safetyCenterTestHelper.setData(
+ DYNAMIC_HIDDEN_WITH_SEARCH_ID,
+ safetySourceTestData.information
+ )
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_BAREBONE_ID,
+ SafetySourceTestData.issuesOnly(safetySourceTestData.criticalResolvingGeneralIssue)
+ )
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ SafetySourceTestData.issuesOnly(safetySourceTestData.recommendationGeneralIssue)
+ )
+ safetyCenterTestHelper.setData(
+ DYNAMIC_IN_STATELESS_ID,
+ safetySourceTestData.unspecifiedWithIssue
+ )
+ safetyCenterTestHelper.setData(
+ ISSUE_ONLY_IN_STATELESS_ID,
+ SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue)
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData.withoutExtras())
+ .isEqualTo(safetyCenterDataFromComplexConfigUpdated)
+ }
+
+ @Test
+ fun getSafetyCenterData_withCriticalEntriesAsMax_usesCriticalSummaryForGroup() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.summaryTestConfig)
+ safetyCenterManager.reportSafetySourceErrorWithPermission(
+ SOURCE_ID_1,
+ SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED)
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_3,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entrySummary = "information without issues"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_4,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entrySummary = "information with issue",
+ withIssue = true
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_RECOMMENDATION,
+ entrySummary = "recommendation"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_6,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_CRITICAL_WARNING,
+ entrySummary = "critical 1"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_7,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_CRITICAL_WARNING,
+ entrySummary = "critical 2"
+ )
+ )
+ // STATIC_IN_STATEFUL_ID behaves like an UNSPECIFIED dynamic entry
+
+ val group =
+ safetyCenterManager.getSafetyCenterDataWithPermission().getGroup(SUMMARY_TEST_GROUP_ID)
+
+ assertThat(group.summary).isEqualTo("critical 1")
+ assertThat(group.severityLevel).isEqualTo(ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING)
+ }
+
+ @Test
+ fun getSafetyCenterData_withRecommendationEntriesAsMax_usesRecommendationSummaryForGroup() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.summaryTestConfig)
+ safetyCenterManager.reportSafetySourceErrorWithPermission(
+ SOURCE_ID_1,
+ SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED)
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_3,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entrySummary = "information without issues"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_4,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entrySummary = "information with issue",
+ withIssue = true
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_RECOMMENDATION,
+ entrySummary = "recommendation 1"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_6,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_RECOMMENDATION,
+ entrySummary = "recommendation 2"
+ )
+ )
+ // SOURCE_ID_7 leave as an UNKNOWN dynamic entry
+ // STATIC_IN_STATEFUL_ID behaves like an UNSPECIFIED dynamic entry
+
+ val group =
+ safetyCenterManager.getSafetyCenterDataWithPermission().getGroup(SUMMARY_TEST_GROUP_ID)
+
+ assertThat(group.summary).isEqualTo("recommendation 1")
+ assertThat(group.severityLevel).isEqualTo(ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
+ }
+
+ @Test
+ fun getSafetyCenterData_withInformationWithIssueEntriesAsMax_usesInformationSummaryForGroup() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.summaryTestConfig)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified 1"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified 2"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_3,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entrySummary = "information without issues 1"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_4,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entrySummary = "information with issue 1",
+ withIssue = true
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entrySummary = "information with issue 2",
+ withIssue = true
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_6,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entrySummary = "information without issues 2"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_7,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified 3"
+ )
+ )
+ // STATIC_IN_STATEFUL_ID behaves like an UNSPECIFIED dynamic entry
+
+ val group =
+ safetyCenterManager.getSafetyCenterDataWithPermission().getGroup(SUMMARY_TEST_GROUP_ID)
+
+ assertThat(group.summary).isEqualTo("information with issue 1")
+ assertThat(group.severityLevel).isEqualTo(ENTRY_SEVERITY_LEVEL_OK)
+ }
+
+ @Test
+ fun getSafetyCenterData_withInformationEntriesAsMax_usesDefaultSummaryForGroup() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.summaryTestConfig)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified 1"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified 2"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_3,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entrySummary = "information without issues 1"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_4,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entrySummary = "information without issues 2"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified 3"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_6,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entrySummary = "information without issues 3"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_7,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified 4"
+ )
+ )
+ // STATIC_IN_STATEFUL_ID behaves like an UNSPECIFIED dynamic entry
+
+ val group =
+ safetyCenterManager.getSafetyCenterDataWithPermission().getGroup(SUMMARY_TEST_GROUP_ID)
+
+ assertThat(group.summary).isEqualTo("OK")
+ assertThat(group.severityLevel).isEqualTo(ENTRY_SEVERITY_LEVEL_OK)
+ }
+
+ @Test
+ fun getSafetyCenterData_withUnspecifiedEntriesAsMax_usesDefaultSummaryForGroup() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.summaryTestConfig)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified 1"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified 2"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_3,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified 3"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_4,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified 4"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified with issue",
+ withIssue = true
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_6,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified 6"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_7,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified 7"
+ )
+ )
+ // STATIC_IN_STATEFUL_ID behaves like an UNSPECIFIED dynamic entry
+
+ val group =
+ safetyCenterManager.getSafetyCenterDataWithPermission().getGroup(SUMMARY_TEST_GROUP_ID)
+
+ assertThat(group.summary).isEqualTo("OK")
+ assertThat(group.severityLevel).isEqualTo(ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
+ }
+
+ @Test
+ fun getSafetyCenterData_withMultipleErrorEntries_usesSingularErrorSummaryForGroup() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.summaryTestConfig)
+ safetyCenterManager.reportSafetySourceErrorWithPermission(
+ SOURCE_ID_1,
+ SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED)
+ )
+ safetyCenterManager.reportSafetySourceErrorWithPermission(
+ SOURCE_ID_2,
+ SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED)
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_3,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entrySummary = "information with issue",
+ withIssue = true
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_4,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified"
+ )
+ )
+ // SOURCE_ID_5 leave as an UNKNOWN dynamic entry
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_6,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entrySummary = "information"
+ )
+ )
+ // SOURCE_ID_7 leave as an UNKNOWN dynamic entry
+ // STATIC_IN_STATEFUL_ID behaves like an UNSPECIFIED dynamic entry
+
+ val group =
+ safetyCenterManager.getSafetyCenterDataWithPermission().getGroup(SUMMARY_TEST_GROUP_ID)
+
+ assertThat(group.summary).isEqualTo(safetyCenterTestData.getRefreshErrorString(1))
+ assertThat(group.severityLevel).isEqualTo(ENTRY_SEVERITY_LEVEL_UNKNOWN)
+ }
+
+ @Test
+ fun getSafetyCenterData_withSingleErrorEntry_usesSingularErrorSummaryForGroup() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.summaryTestConfig)
+ safetyCenterManager.reportSafetySourceErrorWithPermission(
+ SOURCE_ID_1,
+ SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED)
+ )
+ // SOURCE_ID_2 leave as an UNKNOWN dynamic entry
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_3,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entrySummary = "information with issue",
+ withIssue = true
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_4,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified"
+ )
+ )
+ // SOURCE_ID_5 leave as an UNKNOWN dynamic entry
+ // SOURCE_ID_6 leave as an UNKNOWN dynamic entry
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_7,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entrySummary = "information"
+ )
+ )
+ // STATIC_IN_STATEFUL_ID behaves like an UNSPECIFIED dynamic entry
+
+ val group =
+ safetyCenterManager.getSafetyCenterDataWithPermission().getGroup(SUMMARY_TEST_GROUP_ID)
+
+ assertThat(group.summary).isEqualTo(safetyCenterTestData.getRefreshErrorString(1))
+ assertThat(group.severityLevel).isEqualTo(ENTRY_SEVERITY_LEVEL_UNKNOWN)
+ }
+
+ @Test
+ fun getSafetyCenterData_withUnknownEntries_usesUnknownSummaryForGroup() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.summaryTestConfig)
+ // SOURCE_ID_1 leave as an UNKNOWN dynamic entry
+ // SOURCE_ID_2 leave as an UNKNOWN dynamic entry
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_3,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entrySummary = "information with issue",
+ withIssue = true
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_4,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified"
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_INFORMATION,
+ entrySummary = "information"
+ )
+ )
+ // SOURCE_ID_6 leave as an UNKNOWN dynamic entry
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_7,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SEVERITY_LEVEL_UNSPECIFIED,
+ entrySummary = "unspecified with issue",
+ withIssue = true
+ )
+ )
+ // STATIC_IN_STATEFUL_ID behaves like an UNSPECIFIED dynamic entry
+
+ val group =
+ safetyCenterManager.getSafetyCenterDataWithPermission().getGroup(SUMMARY_TEST_GROUP_ID)
+
+ assertThat(group.summary)
+ .isEqualTo(safetyCenterResourcesContext.getStringByName("group_unknown_summary"))
+ assertThat(group.severityLevel).isEqualTo(ENTRY_SEVERITY_LEVEL_UNKNOWN)
+ }
+
+ @Test
+ fun getSafetyCenterData_withAndroidLockScreenGroup_returnsCombinedTitlesAsSummaryForGroup() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.androidLockScreenSourcesConfig)
+
+ val initialGroup =
+ safetyCenterManager
+ .getSafetyCenterDataWithPermission()
+ .getGroup(ANDROID_LOCK_SCREEN_SOURCES_GROUP_ID)
+
+ assertThat(initialGroup.summary)
+ .isEqualTo(safetyCenterResourcesContext.getStringByName("group_unknown_summary"))
+ assertThat(initialGroup.severityLevel).isEqualTo(ENTRY_SEVERITY_LEVEL_UNKNOWN)
+
+ safetyCenterTestHelper.setData(DYNAMIC_BAREBONE_ID, safetySourceTestData.unspecified)
+ safetyCenterTestHelper.setData(DYNAMIC_DISABLED_ID, safetySourceTestData.information)
+
+ val partialGroup =
+ safetyCenterManager
+ .getSafetyCenterDataWithPermission()
+ .getGroup(ANDROID_LOCK_SCREEN_SOURCES_GROUP_ID)
+
+ assertThat(partialGroup.summary).isEqualTo("Unspecified title, Ok title")
+ assertThat(partialGroup.severityLevel).isEqualTo(ENTRY_SEVERITY_LEVEL_OK)
+
+ safetyCenterTestHelper.setData(DYNAMIC_HIDDEN_ID, safetySourceTestData.information)
+
+ val fullGroup =
+ safetyCenterManager
+ .getSafetyCenterDataWithPermission()
+ .getGroup(ANDROID_LOCK_SCREEN_SOURCES_GROUP_ID)
+
+ assertThat(fullGroup.summary).isEqualTo("Unspecified title, Ok title, Ok title")
+ assertThat(fullGroup.severityLevel).isEqualTo(ENTRY_SEVERITY_LEVEL_OK)
+
+ safetyCenterTestHelper.setData(
+ DYNAMIC_DISABLED_ID,
+ safetySourceTestData.informationWithIssue
+ )
+
+ val informationWithIssueGroup =
+ safetyCenterManager
+ .getSafetyCenterDataWithPermission()
+ .getGroup(ANDROID_LOCK_SCREEN_SOURCES_GROUP_ID)
+
+ assertThat(informationWithIssueGroup.summary).isEqualTo("Ok summary")
+ assertThat(informationWithIssueGroup.severityLevel).isEqualTo(ENTRY_SEVERITY_LEVEL_OK)
+ }
+
+ @Test
+ fun getSafetyCenterData_withFlagDisabled_returnsDefaultData() {
+ safetyCenterTestHelper.setEnabled(false)
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData).isEqualTo(SafetyCenterTestData.DEFAULT)
+ }
+
+ @Test
+ fun getSafetyCenterData_defaultDataWithIncorrectIntent_returnsDisabledEntries() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceInvalidIntentConfig)
+
+ val safetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ val expectedSafetyCenterData =
+ SafetyCenterData(
+ safetyCenterTestData.safetyCenterStatusUnknown,
+ emptyList(),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData
+ .safetyCenterEntryDefaultBuilder(SINGLE_SOURCE_ID)
+ .setPendingIntent(null)
+ .setEnabled(false)
+ .build()
+ )
+ ),
+ emptyList()
+ )
+ assertThat(safetyCenterData).isEqualTo(expectedSafetyCenterData)
+ }
+
+ @Test
+ fun getSafetyCenterData_withInvalidDefaultIntent_shouldReturnUnspecifiedSeverityLevel() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceInvalidIntentConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.informationWithNullIntent
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ val expectedSafetyCenterData =
+ SafetyCenterData(
+ safetyCenterStatusOk,
+ emptyList(),
+ listOf(
+ SafetyCenterEntryOrGroup(
+ safetyCenterTestData
+ .safetyCenterEntryOkBuilder(SINGLE_SOURCE_ID)
+ .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
+ .setPendingIntent(null)
+ .setEnabled(false)
+ .build()
+ )
+ ),
+ emptyList()
+ )
+ assertThat(apiSafetyCenterData).isEqualTo(expectedSafetyCenterData)
+ }
+
+ @Test
+ fun addOnSafetyCenterDataChangedListener_listenerCalledWithSafetyCenterDataFromConfig() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ val listener = safetyCenterTestHelper.addListener(skipInitialData = false)
+
+ val safetyCenterDataFromListener = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataFromListener).isEqualTo(safetyCenterDataFromConfig)
+ }
+
+ @Test
+ fun addOnSafetyCenterDataChangedListener_listenerCalledOnSafetySourceData() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+ val safetyCenterDataFromListener = listener.receiveSafetyCenterData()
+
+ assertThat(safetyCenterDataFromListener).isEqualTo(safetyCenterDataOk)
+ }
+
+ @Test
+ fun addOnSafetyCenterDataChangedListener_listenerCalledWhenSafetySourceDataChanges() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val listener = safetyCenterTestHelper.addListener()
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+ // Receive update from #setSafetySourceData call.
+ listener.receiveSafetyCenterData()
+
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ val safetyCenterDataFromListener = listener.receiveSafetyCenterData()
+
+ assertThat(safetyCenterDataFromListener).isEqualTo(safetyCenterDataGeneralCriticalOneAlert)
+ }
+
+ @Test
+ fun addOnSafetyCenterDataChangedListener_listenerCalledWhenSafetySourceDataCleared() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val listener = safetyCenterTestHelper.addListener()
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+ // Receive update from #setSafetySourceData call.
+ listener.receiveSafetyCenterData()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceData = null)
+ val safetyCenterDataFromListener = listener.receiveSafetyCenterData()
+
+ assertThat(safetyCenterDataFromListener).isEqualTo(safetyCenterDataFromConfig)
+ }
+
+ @Test
+ fun dismissSafetyCenterIssue_existing_callsListenerAndDismisses() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID)
+ )
+
+ val safetyCenterDataFromListener = listener.receiveSafetyCenterData()
+ val expectedSafetyCenterData =
+ safetyCenterDataOkReviewCriticalEntry.withDismissedIssuesIfAtLeastU(
+ listOf(safetyCenterTestData.safetyCenterIssueCritical(SINGLE_SOURCE_ID))
+ )
+ assertThat(safetyCenterDataFromListener).isEqualTo(expectedSafetyCenterData)
+ }
+
+ @Test
+ fun dismissSafetyCenterIssue_issueShowsUpAgainIfSourceStopsSendingItAtLeastOnce() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID)
+ )
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+
+ val safetyCenterDataAfterSourceStopsSendingDismissedIssue =
+ listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataAfterSourceStopsSendingDismissedIssue)
+ .isEqualTo(safetyCenterDataOk)
+
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+
+ val safetyCenterDataAfterSourcePushesDismissedIssueAgain =
+ listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataAfterSourcePushesDismissedIssueAgain)
+ .isEqualTo(safetyCenterDataGeneralCriticalOneAlert)
+ }
+
+ @Test
+ fun dismissSafetyCenterIssue_existingWithDifferentIssueType_callsListenerAndDismisses() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ val listener = safetyCenterTestHelper.addListener()
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ issueTypeId = "some_other_issue_type_id"
+ )
+ )
+
+ val safetyCenterDataFromListener = listener.receiveSafetyCenterData()
+ val expectedSafetyCenterData =
+ safetyCenterDataOkReviewCriticalEntry.withDismissedIssuesIfAtLeastU(
+ listOf(safetyCenterTestData.safetyCenterIssueCritical(SINGLE_SOURCE_ID))
+ )
+ assertThat(safetyCenterDataFromListener).isEqualTo(expectedSafetyCenterData)
+ }
+
+ @Test
+ fun dismissSafetyCenterIssue_withDismissPendingIntent_callsDismissPendingIntentAndDismisses() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.recommendationDismissPendingIntentIssue
+ )
+ SafetySourceReceiver.setResponse(
+ Request.DismissIssue(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.dismissSafetyCenterIssueWithPermissionAndWait(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, RECOMMENDATION_ISSUE_ID)
+ )
+
+ val safetyCenterDataAfterDismissal = listener.receiveSafetyCenterData()
+ val expectedSafetyCenterData =
+ safetyCenterDataOkReviewRecommendationEntry.withDismissedIssuesIfAtLeastU(
+ listOf(safetyCenterTestData.safetyCenterIssueRecommendation(SINGLE_SOURCE_ID))
+ )
+ assertThat(safetyCenterDataAfterDismissal).isEqualTo(expectedSafetyCenterData)
+ val safetyCenterDataAfterSourceHandledDismissal = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataAfterSourceHandledDismissal).isEqualTo(safetyCenterDataOk)
+ }
+
+ @Test
+ fun dismissSafetyCenterIssue_errorDispatchPendingIntent_doesntCallErrorListenerAndDismisses() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val recommendationDismissPendingIntentIssue =
+ safetySourceTestData.recommendationDismissPendingIntentIssue
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, recommendationDismissPendingIntentIssue)
+ recommendationDismissPendingIntentIssue.issues.first().onDismissPendingIntent!!.cancel()
+ val listener = safetyCenterTestHelper.addListener()
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, RECOMMENDATION_ISSUE_ID)
+ )
+
+ val safetyCenterDataFromListener = listener.receiveSafetyCenterData()
+ val exectedSafetyCenterData =
+ safetyCenterDataOkReviewRecommendationEntry.withDismissedIssuesIfAtLeastU(
+ listOf(safetyCenterTestData.safetyCenterIssueRecommendation(SINGLE_SOURCE_ID))
+ )
+ assertThat(safetyCenterDataFromListener).isEqualTo(exectedSafetyCenterData)
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterErrorDetails(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun dismissSafetyCenterIssue_withEmptyMaxCountMap_doesNotResurface() {
+ SafetyCenterFlags.resurfaceIssueMaxCounts = emptyMap()
+ SafetyCenterFlags.resurfaceIssueDelays = mapOf(SEVERITY_LEVEL_INFORMATION to Duration.ZERO)
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.informationWithIssue)
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+ checkState(apiSafetyCenterData == safetyCenterDataOkOneAlert)
+
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, INFORMATION_ISSUE_ID)
+ )
+
+ val expectedSafetyCenterData =
+ safetyCenterDataOk.withDismissedIssuesIfAtLeastU(
+ listOf(safetyCenterTestData.safetyCenterIssueInformation(SINGLE_SOURCE_ID))
+ )
+ assertFailsWith(TimeoutCancellationException::class) {
+ waitForWithTimeout(timeout = TIMEOUT_SHORT) {
+ val hasResurfaced =
+ safetyCenterManager.getSafetyCenterDataWithPermission() !=
+ expectedSafetyCenterData
+ hasResurfaced
+ }
+ }
+ }
+
+ @Test
+ fun dismissSafetyCenterIssue_withZeroMaxCount_doesNotResurface() {
+ SafetyCenterFlags.resurfaceIssueMaxCounts =
+ mapOf(
+ SEVERITY_LEVEL_INFORMATION to 0L,
+ SEVERITY_LEVEL_RECOMMENDATION to 99L,
+ SEVERITY_LEVEL_CRITICAL_WARNING to 99L
+ )
+ SafetyCenterFlags.resurfaceIssueDelays =
+ mapOf(
+ SEVERITY_LEVEL_INFORMATION to Duration.ZERO,
+ SEVERITY_LEVEL_RECOMMENDATION to Duration.ZERO,
+ SEVERITY_LEVEL_CRITICAL_WARNING to Duration.ZERO
+ )
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.informationWithIssue)
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+ checkState(apiSafetyCenterData == safetyCenterDataOkOneAlert)
+
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, INFORMATION_ISSUE_ID)
+ )
+
+ val expectedSafetyCenterData =
+ safetyCenterDataOk.withDismissedIssuesIfAtLeastU(
+ listOf(safetyCenterTestData.safetyCenterIssueInformation(SINGLE_SOURCE_ID))
+ )
+ assertFailsWith(TimeoutCancellationException::class) {
+ waitForWithTimeout(timeout = TIMEOUT_SHORT) {
+ val hasResurfaced =
+ safetyCenterManager.getSafetyCenterDataWithPermission() !=
+ expectedSafetyCenterData
+ hasResurfaced
+ }
+ }
+ }
+
+ @Test
+ fun dismissSafetyCenterIssue_withTwoMaxCount_resurfacesTwice() {
+ SafetyCenterFlags.resurfaceIssueMaxCounts =
+ mapOf(
+ SEVERITY_LEVEL_INFORMATION to 0L,
+ SEVERITY_LEVEL_RECOMMENDATION to 0L,
+ SEVERITY_LEVEL_CRITICAL_WARNING to 2L
+ )
+ SafetyCenterFlags.resurfaceIssueDelays =
+ mapOf(
+ SEVERITY_LEVEL_INFORMATION to RESURFACE_DELAY,
+ SEVERITY_LEVEL_RECOMMENDATION to RESURFACE_DELAY,
+ SEVERITY_LEVEL_CRITICAL_WARNING to Duration.ZERO
+ )
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingDeviceIssue
+ )
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+ checkState(apiSafetyCenterData == safetyCenterDataDeviceCriticalOneAlert)
+
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID)
+ )
+ val apiSafetyCenterDataResurface = safetyCenterManager.getSafetyCenterDataWithPermission()
+ checkState(apiSafetyCenterDataResurface == safetyCenterDataDeviceCriticalOneAlert)
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID)
+ )
+ val apiSafetyCenterDataResurfaceAgain =
+ safetyCenterManager.getSafetyCenterDataWithPermission()
+ checkState(apiSafetyCenterDataResurfaceAgain == safetyCenterDataDeviceCriticalOneAlert)
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID)
+ )
+
+ val expectedSafetyCenterData =
+ safetyCenterDataOkReviewCriticalEntry.withDismissedIssuesIfAtLeastU(
+ listOf(safetyCenterTestData.safetyCenterIssueCritical(SINGLE_SOURCE_ID))
+ )
+ assertFailsWith(TimeoutCancellationException::class) {
+ waitForWithTimeout(timeout = TIMEOUT_SHORT) {
+ val hasResurfaced =
+ safetyCenterManager.getSafetyCenterDataWithPermission() !=
+ expectedSafetyCenterData
+
+ hasResurfaced
+ }
+ }
+ }
+
+ @Test
+ fun dismissSafetyCenterIssue_withNonZeroMaxCountAndNonZeroDelay_resurfacesAfterDelay() {
+ // We cannot rely on a listener in this test to assert on the API content at all times!
+ // The listener will not receive an update when a dismissed issue resurfaces, and it will
+ // not receive an update after subsequent dismissals because as far as the listener cache is
+ // concerned the dismissed issue never resurfaced. This is working as intended.
+ SafetyCenterFlags.resurfaceIssueMaxCounts =
+ mapOf(
+ SEVERITY_LEVEL_INFORMATION to 0L,
+ SEVERITY_LEVEL_RECOMMENDATION to 99L,
+ SEVERITY_LEVEL_CRITICAL_WARNING to 0L
+ )
+ SafetyCenterFlags.resurfaceIssueDelays =
+ mapOf(
+ SEVERITY_LEVEL_INFORMATION to Duration.ZERO,
+ SEVERITY_LEVEL_RECOMMENDATION to RESURFACE_DELAY,
+ SEVERITY_LEVEL_CRITICAL_WARNING to Duration.ZERO
+ )
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.recommendationWithDeviceIssue
+ )
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+ checkState(apiSafetyCenterData == safetyCenterDataDeviceRecommendationOneAlert)
+ val listener = safetyCenterTestHelper.addListener()
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, RECOMMENDATION_ISSUE_ID)
+ )
+
+ val safetyCenterDataAfterDismissal = listener.receiveSafetyCenterData()
+ val expectedSafetyCenterData =
+ safetyCenterDataOkReviewRecommendationEntry.withDismissedIssuesIfAtLeastU(
+ listOf(safetyCenterTestData.safetyCenterIssueRecommendation(SINGLE_SOURCE_ID))
+ )
+ assertThat(safetyCenterDataAfterDismissal).isEqualTo(expectedSafetyCenterData)
+ waitForWithTimeout(timeout = RESURFACE_TIMEOUT, checkPeriod = RESURFACE_CHECK) {
+ val hasResurfacedExactly =
+ safetyCenterManager.getSafetyCenterDataWithPermission() ==
+ safetyCenterDataDeviceRecommendationOneAlert
+ hasResurfacedExactly
+ }
+ }
+
+ @Test
+ fun executeSafetyCenterIssueAction_existing_callsListenerWithInFlightActionAndExecutes() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ val listener = safetyCenterTestHelper.addListener()
+ SafetySourceReceiver.setResponse(
+ Request.ResolveAction(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID
+ )
+ )
+
+ val safetyCenterDataFromListenerDuringResolveAction = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataFromListenerDuringResolveAction)
+ .isEqualTo(safetyCenterDataCriticalOneAlertInFlight)
+ val safetyCenterDataFromListenerAfterResolveAction = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataFromListenerAfterResolveAction).isEqualTo(safetyCenterDataOk)
+ }
+
+ @Test
+ fun executeSafetyCenterIssueAction_existing_unmarkInFlightWhenResolveActionError() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ val listener = safetyCenterTestHelper.addListener()
+ SafetySourceReceiver.setResponse(Request.ResolveAction(SINGLE_SOURCE_ID), Response.Error)
+
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID
+ )
+ )
+
+ val safetyCenterDataFromListenerDuringResolveAction = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataFromListenerDuringResolveAction)
+ .isEqualTo(safetyCenterDataCriticalOneAlertInFlight)
+ val safetyCenterDataFromListenerAfterResolveAction = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataFromListenerAfterResolveAction)
+ .isEqualTo(safetyCenterDataGeneralCriticalOneAlert)
+ val error = listener.receiveSafetyCenterErrorDetails()
+ assertThat(error)
+ .isEqualTo(
+ SafetyCenterErrorDetails(
+ safetyCenterResourcesContext.getStringByName("resolving_action_error")
+ )
+ )
+ }
+
+ @Test
+ fun executeSafetyCenterIssueAction_sourceDoesNotRespond_timesOutAndCallsListener() {
+ SafetyCenterFlags.resolveActionTimeout = TIMEOUT_SHORT
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID
+ )
+ )
+
+ val safetyCenterDataFromListenerDuringResolveAction = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataFromListenerDuringResolveAction)
+ .isEqualTo(safetyCenterDataCriticalOneAlertInFlight)
+ val safetyCenterDataFromListenerAfterResolveAction = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataFromListenerAfterResolveAction)
+ .isEqualTo(safetyCenterDataGeneralCriticalOneAlert)
+ val error = listener.receiveSafetyCenterErrorDetails()
+ assertThat(error)
+ .isEqualTo(
+ SafetyCenterErrorDetails(
+ safetyCenterResourcesContext.getStringByName("resolving_action_error")
+ )
+ )
+ }
+
+ @Test
+ fun executeSafetyCenterIssueAction_tryAgainAfterTimeout_callsListenerWithInFlightAndExecutes() {
+ SafetyCenterFlags.resolveActionTimeout = TIMEOUT_SHORT
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ val listener = safetyCenterTestHelper.addListener()
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID
+ )
+ )
+ listener.receiveSafetyCenterData()
+ listener.receiveSafetyCenterData()
+ listener.receiveSafetyCenterErrorDetails()
+ SafetyCenterFlags.resolveActionTimeout = TIMEOUT_LONG
+ SafetySourceReceiver.setResponse(
+ Request.ResolveAction(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID
+ )
+ )
+
+ val safetyCenterDataFromListenerDuringResolveAction = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataFromListenerDuringResolveAction)
+ .isEqualTo(safetyCenterDataCriticalOneAlertInFlight)
+ val safetyCenterDataFromListenerAfterResolveAction = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataFromListenerAfterResolveAction).isEqualTo(safetyCenterDataOk)
+ }
+
+ @Test
+ fun executeSafetyCenterIssueAction_allowsDismissedIssuesToExecuteActions() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ SafetySourceReceiver.setResponse(
+ Request.ResolveAction(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+ val issueId = SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID)
+ val listener = safetyCenterTestHelper.addListener()
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(issueId)
+ val safetyCenterDataAfterDismissal = listener.receiveSafetyCenterData()
+ checkState(safetyCenterDataAfterDismissal.status == safetyCenterStatusOkReview)
+
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
+ issueId,
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID
+ )
+ )
+
+ if (SdkLevel.isAtLeastU()) {
+ // On U+, the dismissed issue is marked as "in-flight" before resolving.
+ val safetyCenterDataFromListenerDuringResolveAction = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataFromListenerDuringResolveAction)
+ .isEqualTo(safetyCenterDataOkReviewOneDismissedAlertInFlight)
+ }
+ // On T, the dismissed issue is never shown, so only the status will change after
+ // resolution.
+ val safetyCenterDataFromListenerAfterResolveAction = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataFromListenerAfterResolveAction).isEqualTo(safetyCenterDataOk)
+ }
+
+ @Test
+ fun executeSafetyCenterIssueAction_idsDontMatch_canStillResolve() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ val listener = safetyCenterTestHelper.addListener()
+ SafetySourceReceiver.setResponse(
+ Request.ResolveAction(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID + "invalid",
+ CRITICAL_ISSUE_ACTION_ID
+ ),
+ TIMEOUT_SHORT
+ )
+ }
+
+ safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
+ SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
+ SafetyCenterTestData.issueActionId(
+ SINGLE_SOURCE_ID,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID
+ )
+ )
+
+ val safetyCenterDataFromListenerDuringResolveAction = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataFromListenerDuringResolveAction)
+ .isEqualTo(safetyCenterDataCriticalOneAlertInFlight)
+ val safetyCenterDataFromListenerAfterResolveAction = listener.receiveSafetyCenterData()
+ assertThat(safetyCenterDataFromListenerAfterResolveAction).isEqualTo(safetyCenterDataOk)
+ }
+
+ @Test
+ fun refreshSafetySources_forSettingsSources_providesDataToSafetyCenter() {
+ val settingsSourcesWithEntries =
+ safetyCenterManager.getSafetyCenterConfigWithPermission().getDynamicSettingsSources()
+ assumeFalse(settingsSourcesWithEntries.isEmpty())
+ val listener = safetyCenterTestHelper.addListener()
+
+ safetyCenterManager.refreshSafetySourcesWithPermission(REFRESH_REASON_RESCAN_BUTTON_CLICK)
+
+ // Wait until some data is provided by all the Settings sources that have a user-visible
+ // entry. This will exclude the hidden-by-default entries (unless some data ends up being
+ // provided for them).
+ waitForWithTimeout {
+ val data = listener.receiveSafetyCenterData()
+ val entries =
+ data.entriesOrGroups.flatMap {
+ val entry = it.entry
+ if (entry != null) {
+ listOf(entry)
+ } else {
+ it.entryGroup!!.entries
+ }
+ }
+ val visibleSettingsEntries =
+ settingsSourcesWithEntries.mapNotNull { settingsSource ->
+ entries.find { entry ->
+ val entrySourceId =
+ SafetyCenterIds.entryIdFromString(entry.id).safetySourceId
+ entrySourceId == settingsSource.id
+ }
+ }
+ val visibleSettingEntriesHaveData =
+ visibleSettingsEntries.all { it.severityLevel != ENTRY_SEVERITY_LEVEL_UNKNOWN }
+
+ visibleSettingEntriesHaveData
+ }
+ }
+
+ @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)
+
+ val lastUpdated = dumpLastUpdated()
+ assertThat(lastUpdated).isEmpty()
+ }
+
+ @Test
+ fun setSafetySourceData_setsLastUpdatedTimestamp() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.unspecified)
+
+ val lastUpdated = dumpLastUpdated()
+ val key = lastUpdated.keys.find { it.contains(SINGLE_SOURCE_ID) }
+ assertThat(key).isNotNull()
+ assertThat(lastUpdated[key]).isNotNull()
+ }
+
+ @Test
+ fun setSafetySourceData_twice_updatesLastUpdatedTimestamp() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.unspecified)
+
+ val initialEntry = dumpLastUpdated().entries.find { it.key.contains(SINGLE_SOURCE_ID) }
+ assertThat(initialEntry).isNotNull()
+
+ Thread.sleep(1) // Ensure uptime millis will actually be different
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+
+ val updatedValue = dumpLastUpdated()[initialEntry!!.key]
+ assertThat(updatedValue).isNotNull()
+ assertThat(updatedValue).isNotEqualTo(initialEntry.value)
+ }
+
+ @Test
+ fun setSafetySourceError_setsLastUpdatedTimestamp() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ safetyCenterManager.reportSafetySourceErrorWithPermission(
+ SINGLE_SOURCE_ID,
+ SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED)
+ )
+
+ val lastUpdated = dumpLastUpdated()
+ val key = lastUpdated.keys.find { it.contains(SINGLE_SOURCE_ID) }
+ assertThat(key).isNotNull()
+ assertThat(lastUpdated[key]).isNotNull()
+ }
+
+ private fun dumpLastUpdated(): Map<String, String> {
+ val dump = SystemUtil.runShellCommand("dumpsys safety_center data")
+ return dump
+ .linesAfter { it.contains("LAST UPDATED") }
+ .map { line -> Regex("""\[\d+] (.+) -> (\d+)""").matchEntire(line.trim()) }
+ .takeWhile { it != null }
+ .associate { matchResult -> matchResult!!.groupValues[1] to matchResult.groupValues[2] }
+ }
+
+ private fun String.linesAfter(predicate: (String) -> Boolean): List<String> =
+ split('\n').dropWhile { !predicate(it) }.drop(1)
+
+ private fun SafetyCenterData.getGroup(groupId: String): SafetyCenterEntryGroup =
+ entriesOrGroups.first { it.entryGroup?.id == groupId }.entryGroup!!
+
+ private fun SafetyCenterConfig?.getDynamicSettingsSources(): List<SafetySource> {
+ if (this == null) {
+ return emptyList()
+ }
+ return safetySourcesGroups
+ .flatMap { it.safetySources }
+ .filter {
+ it.type == SAFETY_SOURCE_TYPE_DYNAMIC &&
+ it.packageName == context.getSettingsPackageName()
+ }
+ }
+
+ companion object {
+ private val RESURFACE_DELAY = Duration.ofMillis(500)
+ // Wait 1.5 times the RESURFACE_DELAY before asserting whether an issue has or has not
+ // resurfaced. Use a constant additive error buffer if we increase the delay considerably.
+ private val RESURFACE_TIMEOUT = RESURFACE_DELAY.multipliedBy(3).dividedBy(2)
+ // Check more than once during a RESURFACE_DELAY before asserting whether an issue has or
+ // has not resurfaced. Use a different check logic (focused at the expected resurface time)
+ // if we increase the delay considerably.
+ private val RESURFACE_CHECK = RESURFACE_DELAY.dividedBy(4)
+ }
+}
diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterNotificationTest.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterNotificationTest.kt
new file mode 100644
index 000000000..70d6468fa
--- /dev/null
+++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterNotificationTest.kt
@@ -0,0 +1,995 @@
+/*
+ * 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.safetycenter.functional
+
+import android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE
+import android.app.Notification
+import android.app.NotificationManager
+import android.content.Context
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import android.safetycenter.SafetyCenterData
+import android.safetycenter.SafetyCenterIssue
+import android.safetycenter.SafetyCenterManager
+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 androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import com.android.safetycenter.pendingintents.PendingIntentSender
+import com.android.safetycenter.testing.Coroutines.TIMEOUT_SHORT
+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
+import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_2
+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.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.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.Test
+import org.junit.runner.RunWith
+
+/** Notification-related tests for [SafetyCenterManager]. */
+@RunWith(AndroidJUnit4::class)
+class SafetyCenterNotificationTest {
+ private val context: Context = getApplicationContext()
+ private val safetyCenterTestHelper = SafetyCenterTestHelper(context)
+ private val safetySourceTestData = SafetySourceTestData(context)
+ private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context)
+ private val safetyCenterManager =
+ requireNotNull(context.getSystemService(SafetyCenterManager::class.java)) {
+ "Could not get system service"
+ }
+
+ // 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 setUp() {
+ if (!shouldRunTests) {
+ return
+ }
+ safetyCenterTestHelper.setup()
+ TestNotificationListener.setup()
+ 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)
+
+ TestNotificationListener.waitForZeroNotifications()
+ }
+
+ @Test
+ fun setSafetySourceData_withoutImmediateNotificationBehavior_noNotification() {
+ SafetyCenterFlags.immediateNotificationBehaviorIssues = emptySet()
+
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.recommendationWithAccountIssue
+ )
+
+ TestNotificationListener.waitForZeroNotifications()
+ }
+
+ @Test
+ fun setSafetySourceData_withoutNotificationsAllowedSource_noNotification() {
+ SafetyCenterFlags.notificationsAllowedSources = emptySet()
+
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.recommendationWithAccountIssue
+ )
+
+ TestNotificationListener.waitForZeroNotifications()
+ }
+
+ @Test
+ fun setSafetySourceData_withFlagDisabled_noNotification() {
+ SafetyCenterFlags.notificationsEnabled = false
+
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.recommendationWithAccountIssue
+ )
+
+ TestNotificationListener.waitForZeroNotifications()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun setSafetySourceData_withNotificationBehaviorNever_noNotification() {
+ val data =
+ safetySourceTestData
+ .defaultRecommendationDataBuilder()
+ .addIssue(
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder()
+ .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_NEVER)
+ .build()
+ )
+ .build()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ TestNotificationListener.waitForZeroNotifications()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun setSafetySourceData_withNotificationBehaviorDelay_noImmediateNotification() {
+ SafetyCenterFlags.notificationsMinDelay = Duration.ofDays(1)
+ val data =
+ safetySourceTestData
+ .defaultRecommendationDataBuilder()
+ .addIssue(
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder()
+ .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_DELAYED)
+ .build()
+ )
+ .build()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ TestNotificationListener.waitForZeroNotifications()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun setSafetySourceData_withNotificationBehaviorDelay_sendsNotificationAfterDelay() {
+ SafetyCenterFlags.notificationsMinDelay = Duration.ofDays(1)
+ val delayedNotificationIssue =
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder("Notify later", "This is not urgent.")
+ .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_DELAYED)
+ .build()
+ val neverNotifyIssue =
+ safetySourceTestData
+ .defaultInformationIssueBuilder()
+ .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_NEVER)
+ .build()
+ val data1 =
+ safetySourceTestData
+ .defaultRecommendationDataBuilder()
+ .addIssue(delayedNotificationIssue)
+ .build()
+ val data2 =
+ safetySourceTestData
+ .defaultRecommendationDataBuilder()
+ .addIssue(delayedNotificationIssue)
+ .addIssue(neverNotifyIssue)
+ .build()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data1)
+ TestNotificationListener.waitForZeroNotifications()
+
+ SafetyCenterFlags.notificationsMinDelay = TIMEOUT_SHORT
+
+ // Sending new data causes Safety Center to recompute which issues to send notifications
+ // about and this should now include the delayed issue sent in data1 above.
+ Thread.sleep(TIMEOUT_SHORT.toMillis())
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data2)
+
+ TestNotificationListener.waitForSingleNotificationMatching(
+ NotificationCharacteristics(
+ title = "Notify later",
+ text = "This is not urgent.",
+ actions = listOf("See issue")
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun setSafetySourceData_withNotificationBehaviorDelayOfZero_sendsNotificationImmediately() {
+ SafetyCenterFlags.immediateNotificationBehaviorIssues = emptySet()
+ SafetyCenterFlags.notificationsMinDelay = Duration.ofSeconds(0)
+ val data =
+ safetySourceTestData
+ .defaultRecommendationDataBuilder()
+ .addIssue(
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder("Notify immediately", "This is urgent!")
+ .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_DELAYED)
+ .build()
+ )
+ .build()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ TestNotificationListener.waitForSingleNotificationMatching(
+ NotificationCharacteristics(
+ title = "Notify immediately",
+ text = "This is urgent!",
+ actions = listOf("See issue")
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun setSafetySourceData_withNotificationBehaviorImmediately_sendsNotification() {
+ SafetyCenterFlags.immediateNotificationBehaviorIssues = emptySet()
+ val data =
+ safetySourceTestData
+ .defaultRecommendationDataBuilder()
+ .addIssue(
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder("Notify immediately", "This is urgent!")
+ .setNotificationBehavior(
+ SafetySourceIssue.NOTIFICATION_BEHAVIOR_IMMEDIATELY
+ )
+ .build()
+ )
+ .build()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ TestNotificationListener.waitForSingleNotificationMatching(
+ NotificationCharacteristics(
+ title = "Notify immediately",
+ text = "This is urgent!",
+ actions = listOf("See issue")
+ )
+ )
+ }
+
+ @Test
+ fun setSafetySourceData_withNotificationsAllowedForSourceByFlag_sendsNotification() {
+ SafetyCenterFlags.notificationsAllowedSources = setOf(SINGLE_SOURCE_ID)
+ val data = safetySourceTestData.recommendationWithAccountIssue
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ TestNotificationListener.waitForSingleNotificationMatching(
+ NotificationCharacteristics(
+ title = "Recommendation issue title",
+ text = "Recommendation issue summary",
+ actions = listOf("See issue")
+ )
+ )
+ }
+
+ @Test
+ fun setSafetySourceData_issueWithTwoActions_notificationWithTwoActions() {
+ val intent1 = safetySourceTestData.testActivityRedirectPendingIntent(identifier = "1")
+ val intent2 = safetySourceTestData.testActivityRedirectPendingIntent(identifier = "2")
+
+ val data =
+ safetySourceTestData
+ .defaultRecommendationDataBuilder()
+ .addIssue(
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder()
+ .clearActions()
+ .addAction(
+ SafetySourceIssue.Action.Builder("action1", "Action 1", intent1).build()
+ )
+ .addAction(
+ SafetySourceIssue.Action.Builder("action2", "Action 2", intent2).build()
+ )
+ .build()
+ )
+ .build()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ TestNotificationListener.waitForSingleNotificationMatching(
+ NotificationCharacteristics(
+ title = "Recommendation issue title",
+ text = "Recommendation issue summary",
+ actions = listOf("Action 1", "Action 2")
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun setSafetySourceData_withNotificationsAllowedForSourceByConfig_sendsNotification() {
+ SafetyCenterFlags.notificationsAllowedSources = emptySet()
+ SafetyCenterFlags.immediateNotificationBehaviorIssues = emptySet()
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.singleSourceConfig(
+ safetyCenterTestConfigs
+ .dynamicSafetySourceBuilder("MyNotifiableSource")
+ .setNotificationsAllowed(true)
+ .build()
+ )
+ )
+ val data =
+ safetySourceTestData
+ .defaultRecommendationDataBuilder()
+ .addIssue(
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder("Notify immediately", "This is urgent!")
+ .setNotificationBehavior(
+ SafetySourceIssue.NOTIFICATION_BEHAVIOR_IMMEDIATELY
+ )
+ .build()
+ )
+ .build()
+
+ safetyCenterTestHelper.setData("MyNotifiableSource", data)
+
+ TestNotificationListener.waitForSingleNotification()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun setSafetySourceData_withCustomNotification_usesCustomValues() {
+ val intent1 = safetySourceTestData.testActivityRedirectPendingIntent(identifier = "1")
+ val intent2 = safetySourceTestData.testActivityRedirectPendingIntent(identifier = "2")
+
+ val notification =
+ SafetySourceIssue.Notification.Builder("Custom title", "Custom text")
+ .addAction(
+ SafetySourceIssue.Action.Builder("action1", "Custom action 1", intent1).build()
+ )
+ .addAction(
+ SafetySourceIssue.Action.Builder("action2", "Custom action 2", intent2).build()
+ )
+ .build()
+
+ val data =
+ safetySourceTestData
+ .defaultRecommendationDataBuilder()
+ .addIssue(
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder("Default title", "Default text")
+ .addAction(
+ SafetySourceIssue.Action.Builder(
+ "default_action",
+ "Default action",
+ safetySourceTestData.testActivityRedirectPendingIntent
+ )
+ .build()
+ )
+ .setCustomNotification(notification)
+ .build()
+ )
+ .build()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ TestNotificationListener.waitForSingleNotificationMatching(
+ NotificationCharacteristics(
+ title = "Custom title",
+ text = "Custom text",
+ actions = listOf("Custom action 1", "Custom action 2")
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun setSafetySourceData_withEmptyCustomActions_notificationHasNoActions() {
+ val notification =
+ SafetySourceIssue.Notification.Builder("Custom title", "Custom text")
+ .clearActions()
+ .build()
+
+ val data =
+ safetySourceTestData
+ .defaultRecommendationDataBuilder()
+ .addIssue(
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder("Default title", "Default text")
+ .addAction(
+ SafetySourceIssue.Action.Builder(
+ "default_action",
+ "Default action",
+ safetySourceTestData.testActivityRedirectPendingIntent
+ )
+ .build()
+ )
+ .setCustomNotification(notification)
+ .build()
+ )
+ .build()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ TestNotificationListener.waitForSingleNotificationMatching(
+ NotificationCharacteristics(
+ title = "Custom title",
+ text = "Custom text",
+ actions = emptyList()
+ )
+ )
+ }
+
+ @Test
+ fun setSafetySourceData_twiceWithSameIssueId_updatesNotification() {
+ val data1 =
+ safetySourceTestData
+ .defaultRecommendationDataBuilder()
+ .addIssue(
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder("Initial", "Blah")
+ .build()
+ )
+ .build()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data1)
+
+ val initialNotification =
+ TestNotificationListener.waitForSingleNotificationMatching(
+ NotificationCharacteristics(
+ title = "Initial",
+ text = "Blah",
+ actions = listOf("See issue")
+ )
+ )
+
+ val data2 =
+ safetySourceTestData
+ .defaultRecommendationDataBuilder()
+ .addIssue(
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder("Revised", "Different")
+ .addAction(
+ SafetySourceIssue.Action.Builder(
+ "new_action",
+ "New action",
+ safetySourceTestData.testActivityRedirectPendingIntent(
+ identifier = "new_action"
+ )
+ )
+ .build()
+ )
+ .build()
+ )
+ .build()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data2)
+
+ val revisedNotification =
+ TestNotificationListener.waitForSingleNotificationMatching(
+ NotificationCharacteristics(
+ title = "Revised",
+ text = "Different",
+ actions = listOf("See issue", "New action")
+ )
+ )
+ assertThat(initialNotification.statusBarNotification.key)
+ .isEqualTo(revisedNotification.statusBarNotification.key)
+ }
+
+ @Test
+ fun setSafetySourceData_twiceWithExactSameIssue_doNotNotifyTwice() {
+ val data = safetySourceTestData.recommendationWithAccountIssue
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ TestNotificationListener.waitForSingleNotification()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ TestNotificationListener.waitForZeroNotificationEvents()
+ }
+
+ @Test
+ fun setSafetySourceData_twiceRemovingAnIssue_cancelsNotification() {
+ val data1 = safetySourceTestData.recommendationWithAccountIssue
+ val data2 = safetySourceTestData.information
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data1)
+
+ TestNotificationListener.waitForSingleNotification()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data2)
+
+ TestNotificationListener.waitForZeroNotifications()
+ }
+
+ @Test
+ fun reportSafetySourceError_sourceWithNotification_cancelsNotification() {
+ val data = safetySourceTestData.recommendationWithAccountIssue
+ val error =
+ SafetySourceErrorDetails(
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
+ )
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ TestNotificationListener.waitForSingleNotification()
+
+ safetyCenterManager.reportSafetySourceErrorWithPermission(SINGLE_SOURCE_ID, error)
+
+ TestNotificationListener.waitForZeroNotifications()
+ }
+
+ @Test
+ fun setSafetySourceData_withDismissedIssueId_doesNotNotify() {
+ // We use two different issues/data here to ensure that the reason the notification is not
+ // posted the second time is specifically because of the dismissal. Notifications are not
+ // re-posted/updated for unchanged issues but that functionality is different and tested
+ // separately.
+ val data1 =
+ safetySourceTestData
+ .defaultRecommendationDataBuilder()
+ .addIssue(
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder("Initial", "Blah")
+ .build()
+ )
+ .build()
+ val data2 =
+ safetySourceTestData
+ .defaultRecommendationDataBuilder()
+ .addIssue(
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder("Revised", "Different")
+ .build()
+ )
+ .build()
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data1)
+
+ val notificationWithChannel =
+ TestNotificationListener.waitForSingleNotificationMatching(
+ NotificationCharacteristics(
+ title = "Initial",
+ text = "Blah",
+ actions = listOf("See issue")
+ )
+ )
+
+ TestNotificationListener.cancelAndWait(notificationWithChannel.statusBarNotification.key)
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data2)
+
+ TestNotificationListener.waitForZeroNotifications()
+ }
+
+ @Test
+ fun setSafetySourceData_withDismissedIssueIdButResurfaceDelayZero_doesNotify() {
+ SafetyCenterFlags.notificationResurfaceInterval = Duration.ZERO
+ val data1 =
+ safetySourceTestData
+ .defaultRecommendationDataBuilder()
+ .addIssue(
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder("Initial", "Blah")
+ .build()
+ )
+ .build()
+ val data2 =
+ safetySourceTestData
+ .defaultRecommendationDataBuilder()
+ .addIssue(
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder("Revised", "Different")
+ .build()
+ )
+ .build()
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data1)
+ val notificationWithChannel = TestNotificationListener.waitForSingleNotification()
+ TestNotificationListener.cancelAndWait(notificationWithChannel.statusBarNotification.key)
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data2)
+
+ TestNotificationListener.waitForSingleNotification()
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun setSafetySourceData_duplicateIssues_sendsOneNotification() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ setFlagsForImmediateNotifications(SOURCE_ID_1, SOURCE_ID_5)
+
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.recommendationIssueWithDeduplicationId("same")
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+
+ TestNotificationListener.waitForNotificationsMatching(
+ NotificationCharacteristics(
+ "Critical issue title",
+ "Critical issue summary",
+ actions = listOf("Solve issue"),
+ )
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun setSafetySourceData_duplicateIssueOfLowerSeverityDismissed_sendsNotification() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ setFlagsForImmediateNotifications(SOURCE_ID_1, SOURCE_ID_5)
+
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.recommendationIssueWithDeduplicationId("same")
+ )
+ )
+
+ val notificationWithChannel = TestNotificationListener.waitForSingleNotification()
+
+ TestNotificationListener.cancelAndWait(notificationWithChannel.statusBarNotification.key)
+
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+
+ TestNotificationListener.waitForNotificationsMatching(
+ NotificationCharacteristics(
+ "Critical issue title",
+ "Critical issue summary",
+ actions = listOf("Solve issue"),
+ )
+ )
+ }
+
+ @Test
+ fun setSafetySourceData_withInformationIssue_lowImportanceBlockableNotification() {
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.informationWithIssue)
+
+ TestNotificationListener.waitForNotificationsMatching(
+ NotificationCharacteristics(
+ "Information issue title",
+ "Information issue summary",
+ actions = listOf("Review"),
+ importance = NotificationManager.IMPORTANCE_LOW,
+ blockable = true
+ )
+ )
+ }
+
+ @Test
+ fun setSafetySourceData_withRecommendationIssue_defaultImportanceUnblockableNotification() {
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.recommendationWithAccountIssue
+ )
+
+ TestNotificationListener.waitForNotificationsMatching(
+ NotificationCharacteristics(
+ "Recommendation issue title",
+ "Recommendation issue summary",
+ importance = NotificationManager.IMPORTANCE_DEFAULT,
+ actions = listOf("See issue"),
+ blockable = false
+ )
+ )
+ }
+
+ @Test
+ fun setSafetySourceData_withCriticalIssue_highImportanceUnblockableNotification() {
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingDeviceIssue
+ )
+
+ TestNotificationListener.waitForNotificationsMatching(
+ NotificationCharacteristics(
+ "Critical issue title",
+ "Critical issue summary",
+ actions = listOf("Solve issue"),
+ importance = NotificationManager.IMPORTANCE_HIGH,
+ blockable = false
+ )
+ )
+ }
+
+ @Test
+ fun dismissSafetyCenterIssue_dismissesNotification() {
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.recommendationWithAccountIssue
+ )
+
+ TestNotificationListener.waitForSingleNotification()
+
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(
+ SafetyCenterTestData.issueId(
+ SINGLE_SOURCE_ID,
+ SafetySourceTestData.RECOMMENDATION_ISSUE_ID
+ )
+ )
+
+ TestNotificationListener.waitForZeroNotifications()
+ }
+
+ @Test
+ fun dismissingNotification_doesNotUpdateSafetyCenterData() {
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ // Add the listener after setting the initial data so that we don't need to consume/receive
+ // an update for that
+ val listener = safetyCenterTestHelper.addListener()
+
+ val notificationWithChannel = TestNotificationListener.waitForSingleNotification()
+
+ TestNotificationListener.cancelAndWait(notificationWithChannel.statusBarNotification.key)
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ listener.receiveSafetyCenterData(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ fun dismissingNotification_withDuplicateIssues_allDismissed() {
+ safetyCenterTestHelper.setConfig(
+ safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig
+ )
+ setFlagsForImmediateNotifications(SOURCE_ID_1, SOURCE_ID_5)
+
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.criticalIssueWithDeduplicationId("same")
+ )
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_5,
+ SafetySourceTestData.issuesOnly(
+ safetySourceTestData.recommendationIssueWithDeduplicationId("same")
+ )
+ )
+
+ val notificationWithChannel =
+ TestNotificationListener.waitForSingleNotificationMatching(
+ NotificationCharacteristics(
+ "Critical issue title",
+ "Critical issue summary",
+ actions = listOf("Solve issue"),
+ )
+ )
+
+ // We dismiss the notification and then clear the corresponding issue belonging to
+ // SOURCE_ID_1. This ensures that the only reason no notification is shown for the issue
+ // belonging to SOURCE_ID_5 is that the dismissal data was copied.
+ TestNotificationListener.cancelAndWait(notificationWithChannel.statusBarNotification.key)
+ safetyCenterTestHelper.setData(SOURCE_ID_1, SafetySourceTestData.issuesOnly())
+
+ TestNotificationListener.waitForZeroNotifications()
+ }
+
+ @Test
+ fun clearSafetySourceData_cancelsAllNotifications() {
+ val data = safetySourceTestData.recommendationWithAccountIssue
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, data)
+
+ TestNotificationListener.waitForSingleNotification()
+
+ safetyCenterManager.clearAllSafetySourceDataForTestsWithPermission()
+
+ TestNotificationListener.waitForZeroNotifications()
+ }
+
+ @Test
+ fun sendActionPendingIntent_successful_updatesListener() {
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ 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)
+ )
+ val listener = safetyCenterTestHelper.addListener()
+
+ sendActionPendingIntentAndWaitWithPermission(action)
+
+ val listenerData1 = listener.receiveSafetyCenterData()
+ assertThat(listenerData1.inFlightActions).hasSize(1)
+ val listenerData2 = listener.receiveSafetyCenterData()
+ assertThat(listenerData2.issues).isEmpty()
+ assertThat(listenerData2.status.severityLevel)
+ .isEqualTo(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK)
+ }
+
+ @Test
+ fun sendActionPendingIntent_successfulNoSuccessMessage_removesNotification() {
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ 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.waitForZeroNotifications()
+ }
+
+ @Test
+ fun sendActionPendingIntent_successfulWithSuccessMessage_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)
+ )
+
+ sendActionPendingIntentAndWaitWithPermission(action)
+
+ TestNotificationListener.waitForSingleNotificationMatching(
+ NotificationCharacteristics(
+ "Issue solved",
+ "",
+ actions = emptyList(),
+ )
+ )
+ }
+
+ @Test
+ fun sendActionPendingIntent_error_updatesListenerDoesNotRemoveNotification() {
+ // Here we cause a notification with an action to be posted and prepare the fake receiver
+ // to resolve that action successfully.
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ 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.Error)
+ val listener = safetyCenterTestHelper.addListener()
+
+ sendActionPendingIntentAndWaitWithPermission(action)
+
+ val listenerData1 = listener.receiveSafetyCenterData()
+ assertThat(listenerData1.inFlightActions).hasSize(1)
+ val listenerData2 = listener.receiveSafetyCenterData()
+ assertThat(listenerData2.issues).hasSize(1)
+ assertThat(listenerData2.inFlightActions).isEmpty()
+ assertThat(listenerData2.status.severityLevel)
+ .isEqualTo(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ TestNotificationListener.waitForSingleNotification()
+ }
+
+ @Test
+ fun sendContentPendingIntent_singleIssue_opensSafetyCenterWithIssueVisible() {
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.recommendationWithDeviceIssue
+ )
+ val notificationWithChannel = TestNotificationListener.waitForSingleNotification()
+ val contentIntent = notificationWithChannel.statusBarNotification.notification.contentIntent
+
+ executeBlockAndExit(
+ launchActivity = { PendingIntentSender.send(contentIntent) },
+ block = { waitSourceIssueDisplayed(safetySourceTestData.recommendationDeviceIssue) }
+ )
+ }
+
+ @Test
+ fun sendContentPendingIntent_anotherHigherSeverityIssue_opensSafetyCenterWithIssueVisible() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ setFlagsForImmediateNotifications(SOURCE_ID_1)
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_1,
+ safetySourceTestData.recommendationWithDeviceIssue
+ )
+ safetyCenterTestHelper.setData(
+ SOURCE_ID_2,
+ safetySourceTestData.criticalWithResolvingGeneralIssue
+ )
+ val notificationWithChannel = TestNotificationListener.waitForSingleNotification()
+ val contentIntent = notificationWithChannel.statusBarNotification.notification.contentIntent
+
+ executeBlockAndExit(
+ launchActivity = { PendingIntentSender.send(contentIntent) },
+ block = {
+ waitSourceIssueDisplayed(safetySourceTestData.criticalResolvingGeneralIssue)
+ waitSourceIssueDisplayed(safetySourceTestData.recommendationGeneralIssue)
+ }
+ )
+ }
+
+ companion object {
+ private val SafetyCenterData.inFlightActions: List<SafetyCenterIssue.Action>
+ get() = issues.flatMap { it.actions }.filter { it.isInFlight }
+
+ private fun sendActionPendingIntentAndWaitWithPermission(action: Notification.Action) {
+ 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()
+ }
+ }
+
+ private fun setFlagsForImmediateNotifications(vararg sourceIds: String) {
+ SafetyCenterFlags.notificationsAllowedSources = sourceIds.toSet()
+ SafetyCenterFlags.immediateNotificationBehaviorIssues =
+ sourceIds.map { "$it/$ISSUE_TYPE_ID" }.toSet()
+ }
+ }
+}
diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/NotificationCharacteristics.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/NotificationCharacteristics.kt
new file mode 100644
index 000000000..b91c72422
--- /dev/null
+++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/NotificationCharacteristics.kt
@@ -0,0 +1,71 @@
+/*
+ * 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.safetycenter.functional.testing
+
+import android.app.Notification
+
+/** The characteristic properties of a notification. */
+data class NotificationCharacteristics(
+ val title: String,
+ val text: String,
+ val actions: List<CharSequence> = emptyList(),
+ val importance: Int = IMPORTANCE_ANY,
+ val blockable: Boolean? = null
+) {
+ companion object {
+ const val IMPORTANCE_ANY = -1
+
+ private fun importanceMatches(
+ statusBarNotificationWithChannel: StatusBarNotificationWithChannel,
+ characteristicImportance: Int
+ ): Boolean {
+ return characteristicImportance == IMPORTANCE_ANY ||
+ statusBarNotificationWithChannel.channel.importance == characteristicImportance
+ }
+
+ private fun blockableMatches(
+ statusBarNotificationWithChannel: StatusBarNotificationWithChannel,
+ characteristicBlockable: Boolean?
+ ): Boolean {
+ return characteristicBlockable == null ||
+ statusBarNotificationWithChannel.channel.isBlockable == characteristicBlockable
+ }
+
+ private fun isMatch(
+ statusBarNotificationWithChannel: StatusBarNotificationWithChannel,
+ characteristic: NotificationCharacteristics
+ ): Boolean {
+ val notif = statusBarNotificationWithChannel.statusBarNotification.notification
+ return notif != null &&
+ notif.extras.getString(Notification.EXTRA_TITLE) == characteristic.title &&
+ notif.extras.getString(Notification.EXTRA_TEXT).orEmpty() == characteristic.text &&
+ notif.actions.orEmpty().map { it.title } == characteristic.actions &&
+ importanceMatches(statusBarNotificationWithChannel, characteristic.importance) &&
+ blockableMatches(statusBarNotificationWithChannel, characteristic.blockable)
+ }
+
+ fun areMatching(
+ statusBarNotifications: List<StatusBarNotificationWithChannel>,
+ characteristics: List<NotificationCharacteristics>
+ ): Boolean {
+ if (statusBarNotifications.size != characteristics.size) {
+ return false
+ }
+ return statusBarNotifications.zip(characteristics).all { isMatch(it.first, it.second) }
+ }
+ }
+}
diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/StatusBarNotificationWithChannel.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/StatusBarNotificationWithChannel.kt
new file mode 100644
index 000000000..d9a998c3e
--- /dev/null
+++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/StatusBarNotificationWithChannel.kt
@@ -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.
+ */
+
+package android.safetycenter.functional.testing
+
+import android.app.NotificationChannel
+import android.service.notification.StatusBarNotification
+
+/** Tuple of [StatusBarNotification] and the [NotificationChannel] it was posted to. */
+data class StatusBarNotificationWithChannel(
+ val statusBarNotification: StatusBarNotification,
+ val channel: NotificationChannel
+)
diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/TestNotificationListener.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/TestNotificationListener.kt
new file mode 100644
index 000000000..113ad3b23
--- /dev/null
+++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/testing/TestNotificationListener.kt
@@ -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 android.safetycenter.functional.testing
+
+import android.app.NotificationChannel
+import android.content.ComponentName
+import android.os.ConditionVariable
+import android.service.notification.NotificationListenerService
+import android.service.notification.StatusBarNotification
+import android.util.Log
+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.Coroutines.runBlockingWithTimeoutOrNull
+import com.android.safetycenter.testing.Coroutines.waitForWithTimeout
+import com.google.common.truth.Truth.assertThat
+import java.time.Duration
+import java.util.concurrent.TimeoutException
+import kotlinx.coroutines.TimeoutCancellationException
+import kotlinx.coroutines.channels.Channel
+
+/** Used in tests to check whether expected notifications are present in the status bar. */
+class TestNotificationListener : NotificationListenerService() {
+
+ private sealed class NotificationEvent(val statusBarNotification: StatusBarNotification)
+
+ private class NotificationPosted(statusBarNotification: StatusBarNotification) :
+ NotificationEvent(statusBarNotification) {
+ override fun toString(): String = "Posted $statusBarNotification"
+ }
+
+ private class NotificationRemoved(statusBarNotification: StatusBarNotification) :
+ NotificationEvent(statusBarNotification) {
+ override fun toString(): String = "Removed $statusBarNotification"
+ }
+
+ override fun onNotificationPosted(statusBarNotification: StatusBarNotification) {
+ super.onNotificationPosted(statusBarNotification)
+ if (statusBarNotification.isSafetyCenterNotification()) {
+ runBlockingWithTimeout {
+ safetyCenterNotificationEvents.send(NotificationPosted(statusBarNotification))
+ }
+ }
+ }
+
+ override fun onNotificationRemoved(statusBarNotification: StatusBarNotification) {
+ super.onNotificationRemoved(statusBarNotification)
+ if (statusBarNotification.isSafetyCenterNotification()) {
+ runBlockingWithTimeout {
+ safetyCenterNotificationEvents.send(NotificationRemoved(statusBarNotification))
+ }
+ }
+ }
+
+ override fun onListenerConnected() {
+ Log.d(TAG, "onListenerConnected")
+ super.onListenerConnected()
+ disconnected.close()
+ instance = this
+ connected.open()
+ }
+
+ override fun onListenerDisconnected() {
+ Log.d(TAG, "onListenerDisconnected")
+ super.onListenerDisconnected()
+ connected.close()
+ instance = null
+ disconnected.open()
+ }
+
+ 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 val connected = ConditionVariable(false)
+ private val disconnected = ConditionVariable(true)
+ private var instance: TestNotificationListener? = null
+
+ @Volatile
+ private var safetyCenterNotificationEvents =
+ Channel<NotificationEvent>(capacity = Channel.UNLIMITED)
+
+ /**
+ * Blocks until there are zero Safety Center notifications and there remain zero for a short
+ * duration. Throws an [AssertionError] if a this condition is not met within [timeout], or
+ * if it is met and then violated.
+ */
+ fun waitForZeroNotifications(timeout: Duration = TIMEOUT_LONG) {
+ waitForNotificationCount(0, timeout)
+ }
+
+ /**
+ * Blocks until there is exactly one Safety Center notification and ensures that remains
+ * true for a short duration. Returns that notification, or throws an [AssertionError] if a
+ * this condition is not met within [timeout], or if it is met and then violated.
+ */
+ fun waitForSingleNotification(
+ timeout: Duration = TIMEOUT_LONG
+ ): StatusBarNotificationWithChannel {
+ return waitForNotificationCount(1, timeout).first()
+ }
+
+ /**
+ * Blocks until there are exactly [count] Safety Center notifications and ensures that
+ * remains true for a short duration. Returns those notifications, or throws an
+ * [AssertionError] if a this condition is not met within [timeout], or if it is met and
+ * then violated.
+ */
+ private fun waitForNotificationCount(
+ count: Int,
+ timeout: Duration = TIMEOUT_LONG
+ ): List<StatusBarNotificationWithChannel> {
+ return waitForNotificationsToSatisfy(timeout, description = "$count notifications") {
+ it.size == count
+ }
+ }
+
+ /**
+ * Blocks until there is a single Safety Center notification, which matches the given
+ * [characteristics] and ensures that remains true for a short duration. Returns that
+ * notification, or throws an [AssertionError] if a this condition is not met within
+ * [timeout], or if it is met and then violated.
+ */
+ fun waitForSingleNotificationMatching(
+ characteristics: NotificationCharacteristics,
+ timeout: Duration = TIMEOUT_LONG
+ ): StatusBarNotificationWithChannel {
+ return waitForNotificationsMatching(characteristics, timeout = timeout).first()
+ }
+
+ /**
+ * Blocks until the Safety Center notifications match the given [characteristics] and
+ * ensures that remains true for a short duration. Returns those notifications, or throws an
+ * [AssertionError] if a this condition is not met within [timeout], or if it is met and
+ * then violated.
+ */
+ fun waitForNotificationsMatching(
+ vararg characteristics: NotificationCharacteristics,
+ timeout: Duration = TIMEOUT_LONG
+ ): List<StatusBarNotificationWithChannel> {
+ val charsList = characteristics.toList()
+ return waitForNotificationsToSatisfy(
+ timeout,
+ description = "notification(s) matching characteristics $charsList"
+ ) { NotificationCharacteristics.areMatching(it, charsList) }
+ }
+
+ /**
+ * Blocks until [forAtLeast] has elapsed, or throw an [AssertionError] if any notification
+ * is posted or removed before then.
+ */
+ fun waitForZeroNotificationEvents(forAtLeast: Duration = TIMEOUT_SHORT) {
+ val event =
+ runBlockingWithTimeoutOrNull(forAtLeast) {
+ safetyCenterNotificationEvents.receive()
+ }
+ assertThat(event).isNull()
+ }
+
+ private fun waitForNotificationsToSatisfy(
+ timeout: Duration = TIMEOUT_LONG,
+ forAtLeast: Duration = TIMEOUT_SHORT,
+ 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 =
+ try {
+ runBlockingWithTimeout(timeout) {
+ waitForNotificationsToSatisfyAsync(predicate)
+ }
+ } catch (e: TimeoutCancellationException) {
+ throw AssertionError(formatError(getSafetyCenterNotifications()), e)
+ }
+
+ // Assuming the predicate was satisfied, now we ensure it is not violated for the
+ // forAtLeast duration as well:
+ val nonSatisfyingNotifications =
+ runBlockingWithTimeoutOrNull(forAtLeast) {
+ waitForNotificationsToSatisfyAsync { !predicate(it) }
+ }
+ if (nonSatisfyingNotifications != null) {
+ // In this case the negated-predicate was satisfied before forAtLeast had elapsed
+ throw AssertionError(formatError(nonSatisfyingNotifications))
+ }
+
+ return satisfyingNotifications
+ }
+
+ private suspend fun waitForNotificationsToSatisfyAsync(
+ predicate: (List<StatusBarNotificationWithChannel>) -> Boolean
+ ): List<StatusBarNotificationWithChannel> {
+ var currentNotifications = getSafetyCenterNotifications()
+ while (!predicate(currentNotifications)) {
+ val event = safetyCenterNotificationEvents.receive()
+ Log.d(TAG, "Received notification event: $event")
+ currentNotifications = getSafetyCenterNotifications()
+ }
+ return currentNotifications
+ }
+
+ private fun getSafetyCenterNotifications(): List<StatusBarNotificationWithChannel> {
+ return with(getInstanceOrThrow()) {
+ val notificationsSnapshot =
+ checkNotNull(getActiveNotifications()) {
+ "getActiveNotifications() returned null"
+ }
+ val rankingSnapshot =
+ checkNotNull(getCurrentRanking()) { "getCurrentRanking() returned null" }
+
+ fun getChannel(key: String): NotificationChannel? {
+ // This API uses a result parameter:
+ val rankingOut = Ranking()
+ val success = rankingSnapshot.getRanking(key, rankingOut)
+ return if (success) {
+ rankingOut.channel
+ } else {
+ null
+ }
+ }
+
+ notificationsSnapshot
+ .filter { it.isSafetyCenterNotification() }
+ .mapNotNull { statusBarNotification ->
+ val channel = getChannel(statusBarNotification.key)
+ if (channel != null) {
+ StatusBarNotificationWithChannel(statusBarNotification, channel)
+ } else {
+ null
+ }
+ }
+ }
+ }
+
+ private fun getInstanceOrThrow(): TestNotificationListener {
+ // We want to check the current values of the connected and disconnected
+ // ConditionVariables, but importantly block(0) actually does not timeout immediately!
+ val isConnected = connected.block(1)
+ val isDisconnected = disconnected.block(1)
+ check(isConnected == !isDisconnected) {
+ "Notification listener condition variables are inconsistent"
+ }
+ check(isConnected && !isDisconnected) {
+ "Notification listener was unexpectedly disconnected"
+ }
+ return checkNotNull(instance) { "Notification listener was unexpectedly null" }
+ }
+
+ /**
+ * 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].
+ */
+ fun cancelAndWait(key: String, timeout: Duration = TIMEOUT_LONG) {
+ getInstanceOrThrow().cancelNotification(key)
+ waitForNotificationsToSatisfy(
+ timeout,
+ description = "no notification with the key $key"
+ ) { notifications -> notifications.none { it.statusBarNotification.key == key } }
+
+ waitForIssueCacheToContainAnyDismissedNotification()
+ }
+
+ private fun waitForIssueCacheToContainAnyDismissedNotification() {
+ // Here we wait for an issue to be recorded as dismissed according to the dumpsys
+ // output. The cancelAndWait helper above first "waits" for the notification to
+ // be dismissed, but this additional wait is needed to ensure the notification's delete
+ // PendingIntent is handled. Without this wait there is a race condition between
+ // SafetyCenterNotificationReceiver#onReceive and subsequent calls that set source data
+ // and that race makes tests flaky because the dismissal status of the previous
+ // notification is not well defined.
+ fun dumpIssueDismissalsRepositoryState(): String =
+ SystemUtil.runShellCommand("dumpsys safety_center data")
+ try {
+ waitForWithTimeout {
+ dumpIssueDismissalsRepositoryState()
+ .contains(Regex("""mNotificationDismissedAt=\d+"""))
+ }
+ } catch (e: TimeoutCancellationException) {
+ throw IllegalStateException(
+ "Notification dismissal was not recorded in the issue cache: " +
+ dumpIssueDismissalsRepositoryState(),
+ e
+ )
+ }
+ }
+
+ /** 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
+ val verb = if (allowed) "allow" else "disallow"
+ SystemUtil.runShellCommand("cmd notification ${verb}_listener $id")
+ if (allowed) {
+ requestRebind(componentName)
+ if (!connected.block(TIMEOUT_LONG.toMillis())) {
+ throw TimeoutException("Notification listener did not connect in $TIMEOUT_LONG")
+ }
+ } else {
+ if (!disconnected.block(TIMEOUT_LONG.toMillis())) {
+ throw TimeoutException(
+ "Notification listener did not disconnect in $TIMEOUT_LONG"
+ )
+ }
+ }
+ }
+
+ /** Prepare the [TestNotificationListener] for a notification test */
+ fun setup() {
+ toggleListenerAccess(true)
+ }
+
+ /** Clean up the [TestNotificationListener] after executing a notification test. */
+ fun reset() {
+ waitForNotificationsToSatisfy(
+ forAtLeast = Duration.ZERO,
+ description = "all Safety Center notifications removed in tear down"
+ ) { it.isEmpty() }
+ toggleListenerAccess(false)
+ safetyCenterNotificationEvents.cancel()
+ safetyCenterNotificationEvents = Channel(capacity = Channel.UNLIMITED)
+ }
+
+ private fun StatusBarNotification.isSafetyCenterNotification(): Boolean =
+ packageName == "android" && notification.channelId.startsWith("safety_center")
+ }
+}
diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/PrivacySubpageTest.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/PrivacySubpageTest.kt
new file mode 100644
index 000000000..0c90029e0
--- /dev/null
+++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/PrivacySubpageTest.kt
@@ -0,0 +1,222 @@
+/*
+ * 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.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.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
+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.SafetySourceTestData
+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.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
+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)
+
+ // 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()
+ SafetyCenterFlags.showSubpages = true
+ }
+
+ @After
+ fun clearDataAfterTest() {
+ if (!shouldRunTests) {
+ return
+ }
+ safetyCenterTestHelper.reset()
+ UiAutomatorUtils2.getUiDevice().resetRotation()
+ }
+
+ @Test
+ fun privacySubpage_openWithIntentExtra_showsSubpageData() {
+ val config = safetyCenterTestConfigs.privacySubpageConfig
+ safetyCenterTestHelper.setConfig(config)
+ val sourcesGroup = config.safetySourcesGroups.first()
+ val firstSource: SafetySource = sourcesGroup.safetySources.first()
+ val lastSource: SafetySource = sourcesGroup.safetySources.last()
+ val extras = Bundle()
+ extras.putString(EXTRA_SAFETY_SOURCES_GROUP_ID, sourcesGroup.id)
+
+ context.launchSafetyCenterActivity(extras) {
+ waitAllTextDisplayed(
+ context.getString(firstSource.titleResId),
+ context.getString(firstSource.summaryResId),
+ "Controls",
+ context.getString(lastSource.titleResId),
+ context.getString(lastSource.summaryResId)
+ )
+ }
+ }
+
+ @Test
+ fun privacySubpage_clickingOnEntry_redirectsToDifferentScreen() {
+ val config = safetyCenterTestConfigs.privacySubpageConfig
+ safetyCenterTestHelper.setConfig(config)
+ val sourcesGroup = config.safetySourcesGroups.first()
+ val source: SafetySource = sourcesGroup.safetySources.first()
+ val extras = Bundle()
+ extras.putString(EXTRA_SAFETY_SOURCES_GROUP_ID, sourcesGroup.id)
+
+ context.launchSafetyCenterActivity(extras) {
+ waitDisplayed(By.text(context.getString(source.titleResId))) { it.click() }
+ waitButtonDisplayed("Exit test activity") { it.click() }
+ waitAllTextDisplayed(
+ context.getString(source.titleResId),
+ context.getString(source.summaryResId)
+ )
+ }
+ }
+
+ @Test
+ fun privacySubpage_withMultipleIssues_displaysExpectedWarningCards() {
+ val config = safetyCenterTestConfigs.privacySubpageConfig
+ safetyCenterTestHelper.setConfig(config)
+ val firstSourceData = safetySourceTestData.criticalWithIssueWithAttributionTitle
+ val secondSourceData = safetySourceTestData.informationWithIssueWithAttributionTitle
+ safetyCenterTestHelper.setData(PRIVACY_SOURCE_ID_1, firstSourceData)
+ safetyCenterTestHelper.setData(SOURCE_ID_1, secondSourceData)
+ val extras = Bundle()
+ extras.putString(EXTRA_SAFETY_SOURCES_GROUP_ID, config.safetySourcesGroups.first().id)
+
+ context.launchSafetyCenterActivity(extras) {
+ waitSourceIssueDisplayed(firstSourceData.issues[0])
+ waitAllTextDisplayed(MORE_ISSUES_LABEL)
+ waitSourceIssueNotDisplayed(secondSourceData.issues[0])
+
+ clickMoreIssuesCard()
+
+ waitSourceIssueDisplayed(firstSourceData.issues[0])
+ waitAllTextDisplayed(MORE_ISSUES_LABEL)
+ waitSourceIssueDisplayed(secondSourceData.issues[0])
+ }
+ }
+
+ @Test
+ fun privacySubpage_openWithIntentExtra_showsPrivacyControls() {
+ val config = safetyCenterTestConfigs.privacySubpageConfig
+ safetyCenterTestHelper.setConfig(config)
+ val extras = Bundle()
+ 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"
+ )
+ }
+ }
+
+ @Test
+ fun privacySubpage_clickingOnLocationEntry_redirectsToLocationScreen() {
+ val config = safetyCenterTestConfigs.privacySubpageConfig
+ safetyCenterTestHelper.setConfig(config)
+ val sourcesGroup = config.safetySourcesGroups.first()
+ val source: SafetySource = sourcesGroup.safetySources.first()
+ val extras = Bundle()
+ extras.putString(EXTRA_SAFETY_SOURCES_GROUP_ID, sourcesGroup.id)
+
+ context.launchSafetyCenterActivity(extras) {
+ openPageAndExit("Location access") {
+ waitPageTitleDisplayed("Location")
+ waitAllTextDisplayed("Use location")
+ }
+
+ waitAllTextDisplayed(
+ context.getString(source.titleResId),
+ context.getString(source.summaryResId)
+ )
+ }
+ }
+
+ @Test
+ fun settingsSearch_openWithPrivacyIntentExtra_showsPrivacySubpage() {
+ val config = safetyCenterTestConfigs.privacySubpageConfig
+ val sourcesGroup = config.safetySourcesGroups.first()
+ val source: SafetySource = sourcesGroup.safetySources.first()
+ safetyCenterTestHelper.setConfig(config)
+ val extras = Bundle()
+ extras.putString(EXTRA_SETTINGS_FRAGMENT_ARGS_KEY, "privacy_camera_toggle")
+
+ context.launchSafetyCenterActivity(extras) {
+ waitAllTextDisplayed(
+ context.getString(source.titleResId),
+ context.getString(source.summaryResId),
+ "Controls",
+ )
+ }
+ }
+
+ 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/SafetyCenterQsActivityTest.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterQsActivityTest.kt
new file mode 100644
index 000000000..9c4d720d3
--- /dev/null
+++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterQsActivityTest.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.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.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.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
+import org.junit.runner.RunWith
+
+/** Functional tests for the Safety Center Quick Settings Activity. */
+@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)
+ }
+
+ @Before
+ fun enableSafetyCenterBeforeTest() {
+ if (!shouldRunTests) {
+ return
+ }
+ safetyCenterTestHelper.setup()
+ 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 {
+ waitPageTitleDisplayed("Security and privacy quick settings")
+ waitAllTextDisplayed("Your privacy controls")
+ waitDisplayed(By.desc("Close"))
+
+ // Verify privacy controls descriptions
+ waitDisplayed(By.desc("Switch. Camera access. Available"))
+ waitDisplayed(By.desc("Switch. Mic access. Available"))
+ }
+ }
+
+ @Test
+ @ScreenRecordRule.ScreenRecord
+ fun launchActivity_togglePrivacyControls_hasUpdatedDescriptions() {
+ context.launchSafetyCenterQsActivity {
+ // Toggle privacy controls
+ waitDisplayed(By.desc("Switch. Camera access. Available")) { it.click() }
+ waitDisplayed(By.desc("Switch. Mic access. Available")) { it.click() }
+
+ // Verify updated state of privacy controls
+ waitDisplayed(By.desc("Switch. Camera access. Blocked"))
+ 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
new file mode 100644
index 000000000..f4ed328ae
--- /dev/null
+++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterStatusCardTest.kt
@@ -0,0 +1,273 @@
+/*
+ * 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.safetycenter.functional.ui
+
+import android.content.Context
+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.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.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.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
+
+/** Functional tests for the Safety Center Status Card. */
+@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 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()
+ }
+
+ @Test
+ fun withUnknownStatus_displaysScanningOnLoad() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+
+ context.launchSafetyCenterActivity {
+ waitAllTextDisplayed(
+ safetyCenterResourcesContext.getStringByName("scanning_title"),
+ safetyCenterResourcesContext.getStringByName("loading_summary")
+ )
+ }
+ }
+
+ @Test
+ fun withKnownStatus_displaysStatusOnLoad() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(
+ SINGLE_SOURCE_ID,
+ safetySourceTestData.informationWithIconAction
+ )
+
+ context.launchSafetyCenterActivity {
+ waitAllTextDisplayed(
+ safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_title"),
+ safetyCenterResourcesContext.getStringByName("loading_summary")
+ )
+ }
+ }
+
+ @Test
+ fun withUnknownStatusAndNoIssues_hasRescanButton() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(Request.Refresh(SINGLE_SOURCE_ID), Response.Error)
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ waitAllTextDisplayed(
+ safetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_ok_review_title"
+ ),
+ safetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_ok_review_summary"
+ )
+ )
+ waitButtonDisplayed(RESCAN_BUTTON_LABEL)
+ }
+ }
+
+ @Test
+ fun withInformationAndNoIssues_hasRescanButton() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ waitAllTextDisplayed(
+ safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_title"),
+ safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_summary")
+ )
+ waitButtonDisplayed(RESCAN_BUTTON_LABEL)
+ }
+ }
+
+ @Test
+ fun withInformationAndNoIssues_hasContentDescriptions() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ waitDisplayed(By.descContains("Security and privacy status"))
+ waitNotDisplayed(By.desc("Protected by Android"))
+ }
+ }
+
+ @Test
+ fun withInformationIssue_doesNotHaveRescanButton() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.informationWithIssue)
+ )
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ waitAllTextDisplayed(
+ safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_title"),
+ safetyCenterTestData.getAlertString(1)
+ )
+ waitButtonNotDisplayed(RESCAN_BUTTON_LABEL)
+ }
+ }
+
+ @Test
+ fun withRecommendationIssue_doesNotHaveRescanButton() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.recommendationWithGeneralIssue)
+ )
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ waitAllTextDisplayed(
+ safetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_safety_recommendation_title"
+ ),
+ safetyCenterTestData.getAlertString(1)
+ )
+ waitButtonNotDisplayed(RESCAN_BUTTON_LABEL)
+ }
+ }
+
+ @Test
+ fun withCriticalWarningIssue_doesNotHaveRescanButton() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue)
+ )
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ waitAllTextDisplayed(
+ safetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_critical_safety_warning_title"
+ ),
+ safetyCenterTestData.getAlertString(1)
+ )
+ waitButtonNotDisplayed(RESCAN_BUTTON_LABEL)
+ }
+ }
+
+ @Test
+ fun withKnownStatus_displaysScanningOnRescan() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ waitAllTextDisplayed(
+ safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_title"),
+ safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_summary")
+ )
+
+ waitButtonDisplayed(RESCAN_BUTTON_LABEL) { it.click() }
+
+ waitAllTextDisplayed(
+ safetyCenterResourcesContext.getStringByName("scanning_title"),
+ safetyCenterResourcesContext.getStringByName("loading_summary")
+ )
+ }
+ }
+
+ @Test
+ fun rescan_updatesDataAfterScanCompletes() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.information)
+ )
+ SafetySourceReceiver.setResponse(
+ Request.Rescan(SINGLE_SOURCE_ID),
+ Response.SetData(safetySourceTestData.recommendationWithGeneralIssue)
+ )
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ waitAllTextDisplayed(
+ safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_title"),
+ safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_summary")
+ )
+
+ waitButtonDisplayed(RESCAN_BUTTON_LABEL) { it.click() }
+
+ waitAllTextDisplayed(
+ safetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_safety_recommendation_title"
+ ),
+ safetyCenterTestData.getAlertString(1)
+ )
+ }
+ }
+}
diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterSubpagesTest.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterSubpagesTest.kt
new file mode 100644
index 000000000..3aef2097a
--- /dev/null
+++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterSubpagesTest.kt
@@ -0,0 +1,1026 @@
+/*
+ * 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.safetycenter.functional.ui
+
+import android.content.Context
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import android.os.Bundle
+import android.platform.test.rule.ScreenRecordRule
+import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCES_GROUP_ID
+import android.safetycenter.SafetySourceData
+import android.safetycenter.SafetySourceIssue
+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.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
+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.SafetyCenterTestConfigs.Companion.SOURCE_ID_4
+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.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.UiTestHelper.MORE_ISSUES_LABEL
+import com.android.safetycenter.testing.UiTestHelper.clickConfirmDismissal
+import com.android.safetycenter.testing.UiTestHelper.clickDismissIssueCard
+import com.android.safetycenter.testing.UiTestHelper.clickMoreIssuesCard
+import com.android.safetycenter.testing.UiTestHelper.clickOpenSubpage
+import com.android.safetycenter.testing.UiTestHelper.clickSubpageBrandChip
+import com.android.safetycenter.testing.UiTestHelper.resetRotation
+import com.android.safetycenter.testing.UiTestHelper.rotate
+import com.android.safetycenter.testing.UiTestHelper.setAnimationsEnabled
+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.waitCollapsedIssuesDisplayed
+import com.android.safetycenter.testing.UiTestHelper.waitDisplayed
+import com.android.safetycenter.testing.UiTestHelper.waitExpandedIssuesDisplayed
+import com.android.safetycenter.testing.UiTestHelper.waitGroupShownOnHomepage
+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()
+
+ @get:Rule val screenRecordRule = ScreenRecordRule()
+
+ // 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)
+
+ // 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()
+ SafetyCenterFlags.showSubpages = true
+ }
+
+ @After
+ fun clearDataAfterTest() {
+ if (!shouldRunTests) {
+ return
+ }
+ safetyCenterTestHelper.reset()
+ UiAutomatorUtils2.getUiDevice().resetRotation()
+ }
+
+ @Test
+ fun launchSafetyCenter_withSubpagesIntentExtra_showsSubpageTitle() {
+ val config = safetyCenterTestConfigs.multipleSourceGroupsConfig
+ val sourceGroup = config.safetySourcesGroups.first()!!
+ safetyCenterTestHelper.setConfig(config)
+ val extras = Bundle()
+ extras.putString(EXTRA_SAFETY_SOURCES_GROUP_ID, MULTIPLE_SOURCES_GROUP_ID_1)
+
+ context.launchSafetyCenterActivity(extras) {
+ waitPageTitleDisplayed(context.getString(sourceGroup.titleResId))
+ }
+ }
+
+ @Test
+ fun launchSafetyCenter_withSubpagesIntentExtraButFlagDisabled_showsHomepageTitle() {
+ SafetyCenterFlags.showSubpages = false
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig)
+ val extras = Bundle()
+ extras.putString(EXTRA_SAFETY_SOURCES_GROUP_ID, MULTIPLE_SOURCES_GROUP_ID_1)
+
+ context.launchSafetyCenterActivity(extras) { waitPageTitleDisplayed("Security & privacy") }
+ }
+
+ @Test
+ fun launchSafetyCenter_withNonExistingGroupID_opensHomepageAsFallback() {
+ val config = safetyCenterTestConfigs.multipleSourceGroupsConfig
+ val sourceGroup = config.safetySourcesGroups.first()!!
+ safetyCenterTestHelper.setConfig(config)
+ val extras = Bundle()
+ extras.putString(EXTRA_SAFETY_SOURCES_GROUP_ID, "non_existing_group_id")
+
+ context.launchSafetyCenterActivity(extras) {
+ waitPageTitleNotDisplayed(context.getString(sourceGroup.titleResId))
+ waitPageTitleDisplayed("Security & privacy")
+ }
+ }
+
+ @Test
+ fun launchSafetyCenter_withMultipleGroups_showsHomepageEntries() {
+ val sourceTestData = safetySourceTestData.information
+ with(safetyCenterTestHelper) {
+ setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig)
+ setData(SOURCE_ID_1, sourceTestData)
+ setData(SOURCE_ID_2, sourceTestData)
+ setData(SOURCE_ID_3, sourceTestData)
+ setData(SOURCE_ID_4, sourceTestData)
+ setData(SOURCE_ID_5, sourceTestData)
+ }
+ val firstGroup =
+ safetyCenterTestConfigs.multipleSourceGroupsConfig.safetySourcesGroups.first()
+ val lastGroup =
+ safetyCenterTestConfigs.multipleSourceGroupsConfig.safetySourcesGroups.last()
+
+ context.launchSafetyCenterActivity {
+ waitAllTextDisplayed(
+ context.getString(firstGroup.titleResId),
+ context.getString(firstGroup.summaryResId),
+ context.getString(lastGroup.titleResId),
+ context.getString(lastGroup.summaryResId)
+ )
+
+ openPageAndExit(context.getString(lastGroup.titleResId)) {
+ waitPageTitleDisplayed(context.getString(lastGroup.titleResId))
+ waitAllTextNotDisplayed(context.getString(lastGroup.summaryResId))
+ }
+ }
+ }
+
+ @Test
+ fun launchSafetyCenter_withMultipleGroupsButFlagDisabled_showsExpandAndCollapseEntries() {
+ SafetyCenterFlags.showSubpages = false
+ val sourceTestData = safetySourceTestData.information
+ with(safetyCenterTestHelper) {
+ setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig)
+ setData(SOURCE_ID_1, sourceTestData)
+ setData(SOURCE_ID_2, sourceTestData)
+ setData(SOURCE_ID_3, sourceTestData)
+ setData(SOURCE_ID_4, sourceTestData)
+ setData(SOURCE_ID_5, sourceTestData)
+ }
+ val firstGroup =
+ safetyCenterTestConfigs.multipleSourceGroupsConfig.safetySourcesGroups.first()
+ val lastGroup =
+ safetyCenterTestConfigs.multipleSourceGroupsConfig.safetySourcesGroups.last()
+
+ context.launchSafetyCenterActivity {
+ waitAllTextDisplayed(
+ context.getString(firstGroup.titleResId),
+ context.getString(firstGroup.summaryResId),
+ context.getString(lastGroup.titleResId)
+ )
+ waitDisplayed(By.text(context.getString(lastGroup.summaryResId))) { it.click() }
+
+ // Verifying that the group is expanded and sources are displayed
+ waitAllTextDisplayed(sourceTestData.status!!.title, sourceTestData.status!!.summary)
+ waitAllTextNotDisplayed(context.getString(lastGroup.summaryResId))
+ }
+ }
+
+ @Test
+ fun launchSafetyCenter_redirectBackFromSubpage_showsHomepageEntries() {
+ with(safetyCenterTestHelper) {
+ setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig)
+ setData(SOURCE_ID_1, safetySourceTestData.information)
+ setData(SOURCE_ID_2, safetySourceTestData.information)
+ }
+ val firstGroup =
+ safetyCenterTestConfigs.multipleSourceGroupsConfig.safetySourcesGroups.first()
+
+ context.launchSafetyCenterActivity {
+ waitGroupShownOnHomepage(context, firstGroup)
+
+ openPageAndExit(context.getString(firstGroup.titleResId)) {
+ waitPageTitleDisplayed(context.getString(firstGroup.titleResId))
+ waitAllTextNotDisplayed(context.getString(firstGroup.summaryResId))
+ }
+
+ waitGroupShownOnHomepage(context, firstGroup)
+ }
+ }
+
+ @Test
+ fun entryListWithMultipleSources_clickingOnHomepageEntry_showsSubpageEntries() {
+ with(safetyCenterTestHelper) {
+ setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ setData(
+ SOURCE_ID_1,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SafetySourceData.SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_1_TITLE,
+ entrySummary = SAFETY_SOURCE_1_SUMMARY
+ )
+ )
+ setData(
+ SOURCE_ID_2,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SafetySourceData.SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_2_TITLE,
+ entrySummary = SAFETY_SOURCE_2_SUMMARY
+ )
+ )
+ setData(
+ SOURCE_ID_3,
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SafetySourceData.SEVERITY_LEVEL_INFORMATION,
+ entryTitle = SAFETY_SOURCE_3_TITLE,
+ entrySummary = SAFETY_SOURCE_3_SUMMARY
+ )
+ )
+ }
+ val firstGroup = safetyCenterTestConfigs.multipleSourcesConfig.safetySourcesGroups[0]
+ val secondGroup = safetyCenterTestConfigs.multipleSourcesConfig.safetySourcesGroups[1]
+
+ context.launchSafetyCenterActivity {
+ // Verifying that subpage entries of the first group are displayed
+ openPageAndExit(context.getString(firstGroup.titleResId)) {
+ waitAllTextNotDisplayed(context.getString(firstGroup.summaryResId))
+ waitAllTextDisplayed(
+ SAFETY_SOURCE_1_TITLE,
+ SAFETY_SOURCE_1_SUMMARY,
+ SAFETY_SOURCE_2_TITLE,
+ SAFETY_SOURCE_2_SUMMARY
+ )
+ }
+
+ // Verifying that subpage entries of the second group are displayed
+ openPageAndExit(context.getString(secondGroup.titleResId)) {
+ waitAllTextNotDisplayed(context.getString(secondGroup.summaryResId))
+ waitAllTextDisplayed(SAFETY_SOURCE_3_TITLE, SAFETY_SOURCE_3_SUMMARY)
+ }
+ }
+ }
+
+ @Test
+ fun entryListWithSingleSource_clickingOnSubpageEntry_redirectsToDifferentScreen() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val sourcesGroup = safetyCenterTestConfigs.singleSourceConfig.safetySourcesGroups.first()
+ val source: SafetySource = sourcesGroup.safetySources.first()
+
+ context.launchSafetyCenterActivity {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
+ waitDisplayed(By.text(context.getString(source.titleResId))) { it.click() }
+ waitButtonDisplayed("Exit test activity") { it.click() }
+ waitAllTextDisplayed(
+ context.getString(source.titleResId),
+ context.getString(source.summaryResId)
+ )
+ }
+ }
+ }
+
+ @Test
+ @ScreenRecordRule.ScreenRecord
+ fun entryListWithSingleSource_clickingTheInfoIcon_redirectsToDifferentScreen() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val sourceTestData = safetySourceTestData.informationWithIconAction
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, sourceTestData)
+ val sourcesGroup = safetyCenterTestConfigs.singleSourceConfig.safetySourcesGroups.first()
+
+ context.launchSafetyCenterActivity {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
+ waitDisplayed(By.desc("Information")) { it.click() }
+ waitButtonDisplayed("Exit test activity") { it.click() }
+ waitAllTextDisplayed(sourceTestData.status!!.title, sourceTestData.status!!.summary)
+ }
+ }
+ }
+
+ @Test
+ fun entryListWithSingleSource_clickingTheGearIcon_redirectsToDifferentScreen() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val sourceTestData = safetySourceTestData.informationWithGearIconAction
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, sourceTestData)
+ val sourcesGroup = safetyCenterTestConfigs.singleSourceConfig.safetySourcesGroups.first()
+
+ context.launchSafetyCenterActivity {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
+ waitDisplayed(By.desc("Settings")) { it.click() }
+ waitButtonDisplayed("Exit test activity") { it.click() }
+ waitAllTextDisplayed(sourceTestData.status!!.title, sourceTestData.status!!.summary)
+ }
+ }
+ }
+
+ @Test
+ fun entryListWithSingleSource_clickingAnUnclickableDisabledEntry_doesNothing() {
+ val config = safetyCenterTestConfigs.singleSourceInvalidIntentConfig
+ safetyCenterTestHelper.setConfig(config)
+ val sourceTestData = safetySourceTestData.informationWithNullIntent
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, sourceTestData)
+ val sourcesGroup = config.safetySourcesGroups.first()
+
+ context.launchSafetyCenterActivity {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
+ waitDisplayed(By.text(sourceTestData.status!!.title.toString())) { it.click() }
+
+ // Verifying that clicking on the entry doesn't redirect to any other screen
+ waitAllTextDisplayed(sourceTestData.status!!.title, sourceTestData.status!!.summary)
+ }
+ }
+ }
+
+ @Test
+ fun entryListWithSingleSource_clickingAClickableDisabledEntry_redirectsToDifferentScreen() {
+ val config = safetyCenterTestConfigs.singleSourceConfig
+ safetyCenterTestHelper.setConfig(config)
+ val sourceTestData = safetySourceTestData.unspecifiedDisabledWithTestActivityRedirect
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, sourceTestData)
+ val sourcesGroup = config.safetySourcesGroups.first()
+
+ context.launchSafetyCenterActivity {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
+ waitDisplayed(By.text(sourceTestData.status!!.title.toString())) { it.click() }
+
+ waitButtonDisplayed("Exit test activity") { it.click() }
+ }
+ }
+ }
+
+ @Test
+ fun entryListWithSingleSource_updateSafetySourceData_displayedDataIsUpdated() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val sourcesGroup = safetyCenterTestConfigs.singleSourceConfig.safetySourcesGroups.first()
+ val source: SafetySource = sourcesGroup.safetySources.first()
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
+ waitAllTextDisplayed(
+ context.getString(source.titleResId),
+ context.getString(source.summaryResId)
+ )
+ }
+
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION,
+ entryTitle = "Updated title",
+ entrySummary = "Updated summary"
+ )
+ )
+ )
+
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
+ waitAllTextNotDisplayed(
+ context.getString(source.titleResId),
+ context.getString(source.summaryResId)
+ )
+ waitAllTextDisplayed("Updated title", "Updated summary")
+ }
+ }
+ }
+
+ @Test
+ fun entryListWithSingleSource_updateSafetySourceDataAndRotate_displayedDataIsNotUpdated() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val sourcesGroup = safetyCenterTestConfigs.singleSourceConfig.safetySourcesGroups.first()
+ val source: SafetySource = sourcesGroup.safetySources.first()
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
+ waitAllTextDisplayed(
+ context.getString(source.titleResId),
+ context.getString(source.summaryResId)
+ )
+
+ SafetySourceReceiver.setResponse(
+ Request.Refresh(SINGLE_SOURCE_ID),
+ Response.SetData(
+ safetySourceTestData.buildSafetySourceDataWithSummary(
+ severityLevel = SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION,
+ entryTitle = "Updated title",
+ entrySummary = "Updated summary"
+ )
+ )
+ )
+ UiAutomatorUtils2.getUiDevice().rotate()
+
+ waitAllTextDisplayed(
+ context.getString(source.titleResId),
+ context.getString(source.summaryResId)
+ )
+ waitAllTextNotDisplayed("Updated title", "Updated summary")
+ }
+ }
+ }
+
+ @Test
+ fun issueCard_withMultipleGroups_onlyRelevantSubpageHasIssueCard() {
+ /* The default attribution title for an issue card is same as the entry group title on the
+ * homepage. This causes test flakiness as UiAutomator is unable to choose from duplicate
+ * strings. To address that, an issue with a different attribution title is used here. */
+ val sourceData = safetySourceTestData.informationWithIssueWithAttributionTitle
+ val issue = sourceData.issues[0]
+
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ val firstGroup = safetyCenterTestConfigs.multipleSourcesConfig.safetySourcesGroups[0]
+ val secondGroup = safetyCenterTestConfigs.multipleSourcesConfig.safetySourcesGroups[1]
+ safetyCenterTestHelper.setData(SOURCE_ID_3, sourceData)
+
+ context.launchSafetyCenterActivity {
+ // Verify that homepage has the issue card
+ waitSourceIssueDisplayed(issue)
+
+ // Verify that irrelevant subpage doesn't have the issue card
+ openPageAndExit(context.getString(firstGroup.titleResId)) {
+ waitSourceIssueNotDisplayed(issue)
+ }
+ // Verify that relevant subpage has the issue card
+ openPageAndExit(context.getString(secondGroup.titleResId)) {
+ waitSourceIssueDisplayed(issue)
+ }
+ }
+ }
+
+ @Test
+ @ScreenRecordRule.ScreenRecord
+ fun issueCard_updateSafetySourceData_subpageDisplaysUpdatedIssue() {
+ val initialDataToDisplay = safetySourceTestData.informationWithIssueWithAttributionTitle
+ val updatedDataToDisplay = safetySourceTestData.criticalWithIssueWithAttributionTitle
+
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val sourcesGroup = safetyCenterTestConfigs.singleSourceConfig.safetySourcesGroups.first()
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, initialDataToDisplay)
+
+ context.launchSafetyCenterActivity {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
+ waitSourceIssueDisplayed(initialDataToDisplay.issues[0])
+
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, updatedDataToDisplay)
+
+ waitSourceIssueDisplayed(updatedDataToDisplay.issues[0])
+ }
+ }
+ }
+
+ @Test
+ fun issueCard_resolveIssueOnSubpage_issueDismisses() {
+ val sourceData = safetySourceTestData.criticalWithIssueWithAttributionTitle
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, sourceData)
+ val sourcesGroup = safetyCenterTestConfigs.singleSourceConfig.safetySourcesGroups.first()
+ val issue = sourceData.issues[0]
+ val action = issue.actions[0]
+
+ // Clear the data when action is triggered to simulate resolution.
+ SafetySourceReceiver.setResponse(
+ Request.ResolveAction(SINGLE_SOURCE_ID),
+ Response.ClearData
+ )
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ openPageAndExitAllowingRetries(context.getString(sourcesGroup.titleResId)) {
+ waitSourceIssueDisplayed(issue)
+ waitButtonDisplayed(action.label) { it.click() }
+
+ // Wait for success message to go away, verify issue no longer displayed
+ waitAllTextNotDisplayed(action.successMessage)
+ waitSourceIssueNotDisplayed(issue)
+ }
+ }
+ }
+
+ @Test
+ fun issueCard_confirmDismissalOnSubpage_dismissesIssue() {
+ val sourceData = safetySourceTestData.criticalWithIssueWithAttributionTitle
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, sourceData)
+ val sourcesGroup = safetyCenterTestConfigs.singleSourceConfig.safetySourcesGroups.first()
+ val issue = sourceData.issues[0]
+
+ context.launchSafetyCenterActivity {
+ openPageAndExitAllowingRetries(context.getString(sourcesGroup.titleResId)) {
+ waitSourceIssueDisplayed(issue)
+ clickDismissIssueCard()
+
+ waitAllTextDisplayed("Dismiss this alert?")
+ clickConfirmDismissal()
+
+ waitSourceIssueNotDisplayed(issue)
+ }
+ }
+ }
+
+ @Test
+ fun issueCard_dismissOnSubpageWithRotation_cancellationPersistsIssue() {
+ val sourceData = safetySourceTestData.criticalWithIssueWithAttributionTitle
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, sourceData)
+ val sourcesGroup = safetyCenterTestConfigs.singleSourceConfig.safetySourcesGroups.first()
+ val issue = sourceData.issues[0]
+
+ context.launchSafetyCenterActivity {
+ openPageAndExitAllowingRetries(context.getString(sourcesGroup.titleResId)) {
+ waitSourceIssueDisplayed(issue)
+ clickDismissIssueCard()
+ waitAllTextDisplayed("Dismiss this alert?")
+
+ UiAutomatorUtils2.getUiDevice().rotate()
+
+ waitAllTextDisplayed("Dismiss this alert?")
+ waitButtonDisplayed("Cancel") { it.click() }
+ waitSourceIssueDisplayed(issue)
+ }
+ }
+ }
+
+ @Test
+ fun moreIssuesCard_expandOnSubpage_showsAdditionalCard() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
+ val sourcesGroup = safetyCenterTestConfigs.multipleSourcesConfig.safetySourcesGroups.first()
+ val firstSourceData = safetySourceTestData.criticalWithIssueWithAttributionTitle
+ val secondSourceData = safetySourceTestData.informationWithIssueWithAttributionTitle
+ safetyCenterTestHelper.setData(SOURCE_ID_1, firstSourceData)
+ safetyCenterTestHelper.setData(SOURCE_ID_2, secondSourceData)
+
+ context.launchSafetyCenterActivity {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
+ waitCollapsedIssuesDisplayed(firstSourceData.issues[0], secondSourceData.issues[0])
+
+ clickMoreIssuesCard()
+
+ waitExpandedIssuesDisplayed(firstSourceData.issues[0], secondSourceData.issues[0])
+ }
+ }
+ }
+
+ @Test
+ fun dismissedIssuesCard_expandWithOnlyDismissedIssues_showsAdditionalCard() {
+ val sourceData = safetySourceTestData.criticalWithIssueWithAttributionTitle
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, sourceData)
+ val sourcesGroup = safetyCenterTestConfigs.singleSourceConfig.safetySourcesGroups.first()
+ val issue = sourceData.issues[0]
+
+ context.launchSafetyCenterActivity {
+ openPageAndExitAllowingRetries(context.getString(sourcesGroup.titleResId)) {
+ waitSourceIssueDisplayed(issue)
+ clickDismissIssueCard()
+ waitAllTextDisplayed("Dismiss this alert?")
+ clickConfirmDismissal()
+ waitSourceIssueNotDisplayed(issue)
+
+ waitDisplayed(By.text("Dismissed alerts")) { it.click() }
+
+ waitAllTextDisplayed("Dismissed alerts")
+ waitSourceIssueDisplayed(issue)
+ }
+ }
+ }
+
+ @Test
+ fun dismissedIssuesCard_collapseWithOnlyDismissedIssues_hidesAdditionalCard() {
+ val sourceData = safetySourceTestData.criticalWithIssueWithAttributionTitle
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, sourceData)
+ val sourcesGroup = safetyCenterTestConfigs.singleSourceConfig.safetySourcesGroups.first()
+ val issue = sourceData.issues[0]
+
+ context.launchSafetyCenterActivity {
+ openPageAndExitAllowingRetries(context.getString(sourcesGroup.titleResId)) {
+ waitSourceIssueDisplayed(issue)
+ clickDismissIssueCard()
+ waitAllTextDisplayed("Dismiss this alert?")
+ clickConfirmDismissal()
+ waitSourceIssueNotDisplayed(issue)
+
+ waitDisplayed(By.text("Dismissed alerts")) { it.click() }
+ waitSourceIssueDisplayed(issue)
+
+ waitDisplayed(By.text("Dismissed alerts")) { it.click() }
+ waitSourceIssueNotDisplayed(issue)
+ }
+ }
+ }
+
+ @Test
+ fun dismissedIssuesCard_resolveIssue_successConfirmationShown() {
+ SafetyCenterFlags.hideResolvedIssueUiTransitionDelay = TIMEOUT_LONG
+ val (sourcesGroup, issue) =
+ prepareSingleSourceGroupWithIssue(
+ safetySourceTestData.criticalWithIssueWithAttributionTitle
+ )
+ prepareActionResponse(Response.ClearData)
+
+ checkOnDismissedIssue(sourcesGroup, issue) {
+ val action = issue.actions[0]
+ waitButtonDisplayed(action.label) {
+ // Re-enable animations for this test as this is needed to show the success message.
+ setAnimationsEnabled(true)
+ it.click()
+ }
+
+ // Success message should show up if issue marked as resolved
+ val successMessage = action.successMessage
+ waitAllTextDisplayed(successMessage)
+ }
+ }
+
+ @Test
+ fun dismissedIssuesCard_resolveIssue_issueDismisses() {
+ val (sourcesGroup, issue) =
+ prepareSingleSourceGroupWithIssue(
+ safetySourceTestData.criticalWithIssueWithAttributionTitle
+ )
+ prepareActionResponse(Response.ClearData)
+
+ checkOnDismissedIssue(sourcesGroup, issue) {
+ val action = issue.actions[0]
+ waitButtonDisplayed(action.label) { it.click() }
+
+ // Wait for success message to go away, verify issue no longer displayed
+ val successMessage = action.successMessage
+ waitAllTextNotDisplayed(successMessage)
+ waitSourceIssueNotDisplayed(issue)
+ }
+ }
+
+ @Test
+ fun dismissedIssuesCard_resolveIssue_withDialogClickYes_resolves() {
+ val (sourcesGroup, issue) =
+ prepareSingleSourceGroupWithIssue(
+ safetySourceTestData.criticalWithIssueWithConfirmationWithAttributionTitle
+ )
+ prepareActionResponse(Response.ClearData)
+
+ checkOnDismissedIssue(sourcesGroup, issue) {
+ val action = issue.actions[0]
+ waitButtonDisplayed(action.label) { it.click() }
+
+ waitAllTextDisplayed(SafetySourceTestData.CONFIRMATION_TITLE)
+ waitButtonDisplayed(SafetySourceTestData.CONFIRMATION_YES) { it.click() }
+
+ waitSourceIssueNotDisplayed(issue)
+ }
+ }
+
+ @Test
+ fun dismissedIssuesCard_resolveIssue_withDialog_rotates_clickYes_resolves() {
+ val (sourcesGroup, issue) =
+ prepareSingleSourceGroupWithIssue(
+ safetySourceTestData.criticalWithIssueWithConfirmationWithAttributionTitle
+ )
+ prepareActionResponse(Response.ClearData)
+
+ checkOnDismissedIssue(sourcesGroup, issue) {
+ val action = issue.actions[0]
+ waitButtonDisplayed(action.label) { it.click() }
+
+ waitAllTextDisplayed(SafetySourceTestData.CONFIRMATION_TITLE)
+
+ UiAutomatorUtils2.getUiDevice().rotate()
+
+ waitAllTextDisplayed(SafetySourceTestData.CONFIRMATION_TITLE)
+ waitButtonDisplayed(SafetySourceTestData.CONFIRMATION_YES) { it.click() }
+
+ waitSourceIssueNotDisplayed(issue)
+ }
+ }
+
+ @Test
+ fun dismissedIssuesCard_resolveIssue_withDialogClicksNo_cancels() {
+ val (sourcesGroup, issue) =
+ prepareSingleSourceGroupWithIssue(
+ safetySourceTestData.criticalWithIssueWithConfirmationWithAttributionTitle
+ )
+
+ checkOnDismissedIssue(sourcesGroup, issue) {
+ val action = issue.actions[0]
+ waitButtonDisplayed(action.label) { it.click() }
+
+ waitAllTextDisplayed(SafetySourceTestData.CONFIRMATION_TITLE)
+ waitButtonDisplayed(SafetySourceTestData.CONFIRMATION_NO) { it.click() }
+
+ waitSourceIssueDisplayed(issue)
+ }
+ }
+
+ @Test
+ fun dismissedIssuesCard_resolveIssue_noSuccessMessage_noResolutionUiShown_issueDismisses() {
+ SafetyCenterFlags.hideResolvedIssueUiTransitionDelay = TIMEOUT_LONG
+ val (sourcesGroup, issue) =
+ prepareSingleSourceGroupWithIssue(
+ safetySourceTestData.criticalWithIssueWithAttributionTitle
+ )
+ prepareActionResponse(Response.ClearData)
+
+ checkOnDismissedIssue(sourcesGroup, issue) {
+ val action = issue.actions[0]
+ waitButtonDisplayed(action.label) {
+ // Re-enable animations for this test as this is needed to show the success message.
+ setAnimationsEnabled(true)
+ it.click()
+ }
+
+ waitSourceIssueNotDisplayed(issue)
+ }
+ }
+
+ @Test
+ fun dismissedIssuesCard_resolvingInflightIssueFailed_issueRemains() {
+ val (sourcesGroup, issue) =
+ prepareSingleSourceGroupWithIssue(
+ safetySourceTestData.criticalWithIssueWithAttributionTitle
+ )
+ prepareActionResponse(Response.Error)
+
+ checkOnDismissedIssue(sourcesGroup, issue) {
+ val action = issue.actions[0]
+ waitButtonDisplayed(action.label) { it.click() }
+
+ waitSourceIssueDisplayed(issue)
+ }
+ }
+
+ @Test
+ fun dismissedIssuesCard_resolvingInFlightIssueTimesOut_issueRemains() {
+ SafetyCenterFlags.resolveActionTimeout = TIMEOUT_SHORT
+ val (sourcesGroup, issue) =
+ prepareSingleSourceGroupWithIssue(
+ safetySourceTestData.criticalWithIssueWithAttributionTitle
+ )
+
+ checkOnDismissedIssue(sourcesGroup, issue) {
+ val action = issue.actions[0]
+ waitButtonDisplayed(action.label) { it.click() }
+
+ waitSourceIssueDisplayed(issue)
+ }
+ }
+
+ @Test
+ fun dismissedIssuesCard_clickingNonResolvingActionButton_redirectsToDifferentScreen() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ val (sourcesGroup, issue) =
+ prepareSingleSourceGroupWithIssue(
+ safetySourceTestData.criticalWithTestActivityRedirectWithAttributionTitle
+ )
+
+ checkOnDismissedIssue(sourcesGroup, issue) {
+ val action = issue.actions[0]
+ waitButtonDisplayed(action.label) { it.click() }
+ waitButtonDisplayed("Exit test activity") { it.click() }
+ }
+ }
+
+ @Test
+ fun moreIssuesCard_expandWithDismissedIssues_showsAdditionalCards() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesInSingleGroupConfig)
+
+ val firstSourceData = safetySourceTestData.criticalWithIssueWithAttributionTitle
+ val secondSourceData = safetySourceTestData.informationWithIssueWithAttributionTitle
+ val thirdSourceData = safetySourceTestData.informationWithIssueWithAttributionTitle
+
+ safetyCenterTestHelper.setData(SOURCE_ID_1, firstSourceData)
+ safetyCenterTestHelper.setData(SOURCE_ID_2, secondSourceData)
+ safetyCenterTestHelper.setData(SOURCE_ID_3, thirdSourceData)
+
+ val sourcesGroup =
+ safetyCenterTestConfigs.multipleSourcesInSingleGroupConfig.safetySourcesGroups.first()
+ val issue = firstSourceData.issues[0]
+
+ context.launchSafetyCenterActivity {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
+ waitSourceIssueDisplayed(issue)
+ clickDismissIssueCard()
+ waitAllTextDisplayed("Dismiss this alert?")
+ clickConfirmDismissal()
+ waitSourceIssueNotDisplayed(issue)
+
+ clickMoreIssuesCard()
+
+ waitAllTextDisplayed(MORE_ISSUES_LABEL)
+ waitAllTextDisplayed("Dismissed alerts")
+ waitSourceIssueDisplayed(issue)
+ }
+ }
+ }
+
+ @Test
+ fun moreIssuesCard_collapseWithDismissedIssues_hidesAdditionalCards() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesInSingleGroupConfig)
+
+ val firstSourceData = safetySourceTestData.criticalWithIssueWithAttributionTitle
+ val secondSourceData = safetySourceTestData.informationWithIssueWithAttributionTitle
+ val thirdSourceData = safetySourceTestData.informationWithIssueWithAttributionTitle
+
+ safetyCenterTestHelper.setData(SOURCE_ID_1, firstSourceData)
+ safetyCenterTestHelper.setData(SOURCE_ID_2, secondSourceData)
+ safetyCenterTestHelper.setData(SOURCE_ID_3, thirdSourceData)
+
+ val sourcesGroup =
+ safetyCenterTestConfigs.multipleSourcesInSingleGroupConfig.safetySourcesGroups.first()
+ val issue = firstSourceData.issues[0]
+
+ context.launchSafetyCenterActivity {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
+ waitSourceIssueDisplayed(issue)
+ clickDismissIssueCard()
+ clickConfirmDismissal()
+ waitSourceIssueNotDisplayed(issue)
+
+ clickMoreIssuesCard()
+ waitSourceIssueDisplayed(issue)
+
+ clickMoreIssuesCard()
+ waitAllTextDisplayed(MORE_ISSUES_LABEL)
+ waitAllTextNotDisplayed("Dismissed alerts")
+ waitSourceIssueNotDisplayed(issue)
+ }
+ }
+ }
+
+ @Test
+ fun brandChip_openSubpageFromHomepage_homepageReopensOnClick() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+ val sourcesGroup = safetyCenterTestConfigs.singleSourceConfig.safetySourcesGroups.first()
+
+ context.launchSafetyCenterActivity {
+ waitGroupShownOnHomepage(context, sourcesGroup)
+
+ clickOpenSubpage(context, sourcesGroup)
+ waitPageTitleDisplayed(context.getString(sourcesGroup.titleResId))
+ waitAllTextNotDisplayed(context.getString(sourcesGroup.summaryResId))
+
+ clickSubpageBrandChip()
+ waitGroupShownOnHomepage(context, sourcesGroup)
+ }
+ }
+
+ @Test
+ fun brandChip_openSubpageFromIntent_homepageOpensOnClick() {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information)
+ val sourcesGroup = safetyCenterTestConfigs.singleSourceConfig.safetySourcesGroups.first()
+ val extras = Bundle()
+ extras.putString(EXTRA_SAFETY_SOURCES_GROUP_ID, sourcesGroup.id)
+
+ context.launchSafetyCenterActivity(extras) {
+ waitPageTitleDisplayed(context.getString(sourcesGroup.titleResId))
+ waitAllTextNotDisplayed(context.getString(sourcesGroup.summaryResId))
+
+ clickSubpageBrandChip()
+ waitGroupShownOnHomepage(context, sourcesGroup)
+ }
+ }
+
+ @Test
+ @ScreenRecordRule.ScreenRecord
+ fun settingsSearch_openWithGenericIntentExtra_showsGenericSubpage() {
+ val config = safetyCenterTestConfigs.multipleSourcesConfig
+ safetyCenterTestHelper.setConfig(config)
+ val sourcesGroup = config.safetySourcesGroups.first()
+ val source = sourcesGroup.safetySources.first()
+ val preferenceKey = "${source.id}_personal"
+ val extras = Bundle()
+ extras.putString(EXTRA_SETTINGS_FRAGMENT_ARGS_KEY, preferenceKey)
+
+ context.launchSafetyCenterActivity(extras) {
+ waitPageTitleDisplayed(context.getString(sourcesGroup.titleResId))
+ waitAllTextDisplayed(
+ context.getString(source.titleResId),
+ context.getString(source.summaryResId)
+ )
+ }
+ }
+
+ @Test
+ fun settingsSearch_openWithInvalidKey_showsHomepage() {
+ val config = safetyCenterTestConfigs.singleSourceConfig
+ val sourcesGroup = config.safetySourcesGroups.first()
+ safetyCenterTestHelper.setConfig(config)
+ val extras = Bundle()
+ extras.putString(EXTRA_SETTINGS_FRAGMENT_ARGS_KEY, "invalid_preference_key")
+
+ context.launchSafetyCenterActivity(extras) {
+ waitPageTitleDisplayed("Security & privacy")
+ waitGroupShownOnHomepage(context, sourcesGroup)
+ }
+ }
+
+ @Test
+ fun footerSummary_openGenericSubpageHavingFooter_showsExpectedText() {
+ val config = safetyCenterTestConfigs.singleSourceConfig
+ val sourcesGroup = config.safetySourcesGroups.first()
+ val source: SafetySource = sourcesGroup.safetySources.first()
+ safetyCenterTestHelper.setConfig(config)
+
+ context.launchSafetyCenterActivity {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
+ waitAllTextDisplayed(
+ context.getString(source.titleResId),
+ context.getString(source.summaryResId),
+ safetyCenterResourcesContext.getStringByName(
+ "test_single_source_group_id_footer"
+ )
+ )
+ }
+ }
+ }
+
+ private fun prepareSingleSourceGroupWithIssue(
+ sourceData: SafetySourceData
+ ): Pair<SafetySourcesGroup, SafetySourceIssue> {
+ safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
+ safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, sourceData)
+ val sourcesGroup = safetyCenterTestConfigs.singleSourceConfig.safetySourcesGroups.first()
+ val issue = sourceData.issues[0]
+ return sourcesGroup to issue
+ }
+
+ private fun prepareActionResponse(actionResponse: Response) {
+ SafetySourceReceiver.setResponse(Request.ResolveAction(SINGLE_SOURCE_ID), actionResponse)
+ }
+
+ private fun checkOnDismissedIssue(
+ sourcesGroup: SafetySourcesGroup,
+ issue: SafetySourceIssue,
+ block: () -> Unit
+ ) {
+ val safetyCenterIssueId = SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, issue.id)
+ safetyCenterTestHelper.dismissSafetyCenterIssue(safetyCenterIssueId)
+
+ context.launchSafetyCenterActivity(withReceiverPermission = true) {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {
+ waitDisplayed(By.text("Dismissed alerts")) { it.click() }
+ waitSourceIssueDisplayed(issue)
+
+ block()
+ }
+ }
+ }
+
+ companion object {
+ 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 EXTRA_SETTINGS_FRAGMENT_ARGS_KEY = ":settings:fragment_args_key"
+ }
+}
diff --git a/tests/hostside/safetycenter/Android.bp b/tests/hostside/safetycenter/Android.bp
new file mode 100644
index 000000000..499e44f62
--- /dev/null
+++ b/tests/hostside/safetycenter/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"],
+}
+
+java_test_host {
+ name: "SafetyCenterHostSideTestCases",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ libs: [
+ "tradefed",
+ "junit",
+ ],
+ static_libs: [
+ "cts-statsd-atom-host-test-utils",
+ ],
+ data: [":SafetyCenterHostSideTestsHelper"],
+ test_suites: [
+ "general-tests",
+ "mts-permission",
+ ],
+} \ No newline at end of file
diff --git a/tests/hostside/safetycenter/AndroidTest.xml b/tests/hostside/safetycenter/AndroidTest.xml
new file mode 100644
index 000000000..09ddf9d84
--- /dev/null
+++ b/tests/hostside/safetycenter/AndroidTest.xml
@@ -0,0 +1,41 @@
+<?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 Safety Center hostside tests">
+ <!-- TODO(b/239682646): Integrate these tests into MTS -->
+ <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"/>
+
+ <object class="com.android.tradefed.testtype.suite.module.Sdk33ModuleController"
+ type="module_controller"/>
+
+ <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" />
+ <!-- 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" />
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.StayAwakePreparer" />
+
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="SafetyCenterHostSideTestCases.jar" />
+ </test>
+</configuration> \ No newline at end of file
diff --git a/tests/hostside/safetycenter/OWNERS b/tests/hostside/safetycenter/OWNERS
new file mode 100644
index 000000000..5d8b8161b
--- /dev/null
+++ b/tests/hostside/safetycenter/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1026964
+
+include /SafetyCenter/OWNERS
diff --git a/tests/hostside/safetycenter/TEST_MAPPING b/tests/hostside/safetycenter/TEST_MAPPING
new file mode 100644
index 000000000..ba303cf90
--- /dev/null
+++ b/tests/hostside/safetycenter/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "SafetyCenterHostSideTestCases"
+ }
+ ],
+ "mainline-presubmit": [
+ {
+ "name": "SafetyCenterHostSideTestCases[com.google.android.permission.apex]"
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/hostside/safetycenter/helper-app/Android.bp b/tests/hostside/safetycenter/helper-app/Android.bp
new file mode 100644
index 000000000..cf4372d99
--- /dev/null
+++ b/tests/hostside/safetycenter/helper-app/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "SafetyCenterHostSideTestsHelper",
+ defaults: ["mts-target-sdk-version-current"],
+ sdk_version: "test_current",
+ min_sdk_version: "33",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "safety-center-test-util-lib",
+ ],
+} \ No newline at end of file
diff --git a/tests/hostside/safetycenter/helper-app/AndroidManifest.xml b/tests/hostside/safetycenter/helper-app/AndroidManifest.xml
new file mode 100644
index 000000000..ad329bbec
--- /dev/null
+++ b/tests/hostside/safetycenter/helper-app/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?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.hostside.device">
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.safetycenter.hostside.device" />
+</manifest> \ 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
new file mode 100644
index 000000000..c72166c65
--- /dev/null
+++ b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterInteractionLoggingHelperTests.kt
@@ -0,0 +1,105 @@
+/*
+ * 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.safetycenter.hostside.device
+
+import android.content.Context
+import android.os.Bundle
+import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCES_GROUP_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.openPageAndExit
+import com.android.safetycenter.testing.SafetyCenterFlags
+import com.android.safetycenter.testing.SafetyCenterTestConfigs
+import com.android.safetycenter.testing.SafetyCenterTestHelper
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Contains "helper tests" that perform on-device setup and interaction code for Safety Center's
+ * interaction logging host-side tests. These "helper tests" just perform arrange and act steps and
+ * should not contain assertions. Assertions are performed in the host-side tests that run these
+ * helper tests.
+ *
+ * Some context: host-side tests are unable to interact with the device UI in a detailed manner, and
+ * must run "helper tests" on the device to perform in-depth interactions or setup that must be
+ * performed by code running on the device.
+ */
+@RunWith(AndroidJUnit4::class)
+class SafetyCenterInteractionLoggingHelperTests {
+ private val context: Context = ApplicationProvider.getApplicationContext()
+ private val safetyCenterTestHelper = SafetyCenterTestHelper(context)
+ private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context)
+
+ @Before
+ fun setUp() {
+ safetyCenterTestHelper.setup()
+ SafetyCenterFlags.showSubpages = true
+ }
+
+ @After
+ fun tearDown() {
+ safetyCenterTestHelper.reset()
+ }
+
+ @Test
+ fun openSafetyCenter() {
+ context.launchSafetyCenterActivity {}
+ }
+
+ @Test
+ fun openSubpageFromIntentExtra() {
+ val config = safetyCenterTestConfigs.singleSourceConfig
+ safetyCenterTestHelper.setConfig(config)
+ val sourceGroup = config.safetySourcesGroups.first()!!
+ val extras = Bundle()
+ extras.putString(EXTRA_SAFETY_SOURCES_GROUP_ID, sourceGroup.id)
+
+ context.launchSafetyCenterActivity(extras) {}
+ }
+
+ @Test
+ fun openSubpageFromHomepage() {
+ val config = safetyCenterTestConfigs.singleSourceConfig
+ safetyCenterTestHelper.setConfig(config)
+ val sourcesGroup = config.safetySourcesGroups.first()!!
+
+ context.launchSafetyCenterActivity {
+ openPageAndExit(context.getString(sourcesGroup.titleResId)) {}
+ }
+ }
+
+ @Test
+ fun openSubpageFromSettingsSearch() {
+ val config = safetyCenterTestConfigs.singleSourceConfig
+ safetyCenterTestHelper.setConfig(config)
+ val sourcesGroup = config.safetySourcesGroups.first()!!
+ val extras = Bundle()
+ extras.putString(
+ EXTRA_SETTINGS_FRAGMENT_ARGS_KEY,
+ "${sourcesGroup.safetySources.first().id}_personal"
+ )
+
+ context.launchSafetyCenterActivity(extras) {}
+ }
+
+ companion object {
+ private const val EXTRA_SETTINGS_FRAGMENT_ARGS_KEY = ":settings:fragment_args_key"
+ }
+}
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
new file mode 100644
index 000000000..f4677cfed
--- /dev/null
+++ b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterNotificationLoggingHelperTests.kt
@@ -0,0 +1,80 @@
+/*
+ * 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.safetycenter.hostside.device
+
+import android.content.Context
+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.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.SafetySourceTestData
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Contains "helper tests" that perform on-device setup and interaction code for Safety Center's
+ * interaction logging host-side tests. These "helper tests" just perform arrange and act steps and
+ * should not contain assertions. Assertions are performed in the host-side tests that run these
+ * helper tests.
+ *
+ * Some context: host-side tests are unable to interact with the device UI in a detailed manner, and
+ * must run "helper tests" on the device to perform in-depth interactions or setup that must be
+ * performed by code running on the device.
+ */
+@RunWith(AndroidJUnit4::class)
+class SafetyCenterNotificationLoggingHelperTests {
+ private val context: Context = ApplicationProvider.getApplicationContext()
+ private val safetyCenterTestHelper = SafetyCenterTestHelper(context)
+ private val safetySourceTestData = SafetySourceTestData(context)
+ private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context)
+
+ @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())
+ }
+
+ private fun newTestDataWithNotifiableIssue(): SafetySourceData =
+ safetySourceTestData
+ .defaultCriticalDataBuilder()
+ .addIssue(
+ safetySourceTestData
+ .defaultRecommendationIssueBuilder("Notify immediately", "This is urgent!")
+ .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_IMMEDIATELY)
+ .build()
+ )
+ .build()
+}
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
new file mode 100644
index 000000000..b7bd60d10
--- /dev/null
+++ b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetySourceStateCollectedLoggingHelperTests.kt
@@ -0,0 +1,161 @@
+/*
+ * 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.safetycenter.hostside.device
+
+import android.content.Context
+import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetyEvent
+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.SafetyCenterApisWithShellPermissions.reportSafetySourceErrorWithPermission
+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.SafetySourceIntentHandler.Request
+import com.android.safetycenter.testing.SafetySourceIntentHandler.Response
+import com.android.safetycenter.testing.SafetySourceReceiver.Companion.refreshSafetySourcesWithReceiverPermissionAndWait
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SafetySourceStateCollectedLoggingHelperTests {
+ 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)!!
+
+ @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)
+ val state = 3 // START
+ val command = "cmd stats log-app-breadcrumb $label $state"
+ SystemUtil.runShellCommandOrThrow(command)
+ }
+
+ @Test
+ fun setSafetySourceData_source1() {
+ safetyCenterTestHelper.setData(SOURCE_ID_1, safetySourceTestData.information)
+ }
+
+ @Test
+ fun reportSafetySourceError_source1() {
+ safetyCenterManager.reportSafetySourceErrorWithPermission(
+ SOURCE_ID_1,
+ SafetySourceErrorDetails(
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
+ )
+ )
+ }
+
+ @Test
+ fun refreshAllSources_reasonPageOpen_allSuccessful() {
+ simulateRefresh(
+ Response.SetData(safetySourceTestData.information),
+ Response.SetData(safetySourceTestData.recommendationWithAccountIssue),
+ Response.SetData(safetySourceTestData.criticalWithResolvingDeviceIssue)
+ )
+ }
+
+ @Test
+ fun refreshAllSources_twiceSameData_allSuccessful() {
+ repeat(2) {
+ simulateRefresh(
+ Response.SetData(safetySourceTestData.information),
+ Response.SetData(safetySourceTestData.recommendationWithAccountIssue),
+ Response.SetData(safetySourceTestData.criticalWithResolvingDeviceIssue)
+ )
+ }
+ }
+
+ @Test
+ fun refreshAllSources_twiceDifferentData_onlySource1Unchanged() {
+ simulateRefresh(
+ Response.SetData(safetySourceTestData.information),
+ Response.SetData(safetySourceTestData.recommendationWithAccountIssue),
+ Response.SetData(safetySourceTestData.criticalWithResolvingDeviceIssue)
+ )
+ simulateRefresh(
+ Response.SetData(safetySourceTestData.information),
+ Response.SetData(safetySourceTestData.information),
+ Response.SetData(safetySourceTestData.information)
+ )
+ }
+
+ @Test
+ fun refreshAllSources_reasonPageOpen_oneError() {
+ simulateRefresh(
+ Response.SetData(safetySourceTestData.information),
+ Response.SetData(safetySourceTestData.information),
+ Response.Error
+ )
+ }
+
+ @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,
+ null,
+ refreshReason = SafetyCenterManager.REFRESH_REASON_RESCAN_BUTTON_CLICK
+ )
+ }
+
+ private fun simulateRefresh(
+ source1Response: Response?,
+ source2Response: Response?,
+ source3Response: Response?,
+ refreshReason: Int = SafetyCenterManager.REFRESH_REASON_PAGE_OPEN
+ ) {
+ if (source1Response != null) {
+ SafetySourceReceiver.setResponse(Request.Refresh(SOURCE_ID_1), source1Response)
+ }
+ if (source2Response != null) {
+ SafetySourceReceiver.setResponse(Request.Refresh(SOURCE_ID_2), source2Response)
+ }
+ if (source3Response != null) {
+ SafetySourceReceiver.setResponse(Request.Refresh(SOURCE_ID_3), source3Response)
+ }
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(refreshReason)
+ // Give time for responses to all sources
+ Thread.sleep(Coroutines.TIMEOUT_SHORT.toMillis())
+ }
+}
diff --git a/tests/hostside/safetycenter/src/android/safetycenter/hostside/HelperApp.kt b/tests/hostside/safetycenter/src/android/safetycenter/hostside/HelperApp.kt
new file mode 100644
index 000000000..810cce5c9
--- /dev/null
+++ b/tests/hostside/safetycenter/src/android/safetycenter/hostside/HelperApp.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 android.safetycenter.hostside
+
+/** Constants related to the hostside test helper app */
+internal object HelperApp {
+ const val APK_NAME = "SafetyCenterHostSideTestsHelper.apk"
+ const val PACKAGE_NAME = "android.safetycenter.hostside.device"
+}
diff --git a/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt b/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt
new file mode 100644
index 000000000..5ef8ed84a
--- /dev/null
+++ b/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt
@@ -0,0 +1,148 @@
+/*
+ * 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.safetycenter.hostside
+
+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.os.AtomsProto.Atom
+import com.android.os.AtomsProto.SafetyCenterInteractionReported
+import com.android.os.AtomsProto.SafetyCenterInteractionReported.Action
+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 org.junit.After
+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)
+
+ @Before
+ fun setUp() {
+ ConfigUtils.removeConfig(device)
+ ReportUtils.clearReports(device)
+ ConfigUtils.uploadConfigForPushedAtom(
+ device,
+ safetyCenterRule.getSafetyCenterPackageName(),
+ Atom.SAFETY_CENTER_INTERACTION_REPORTED_FIELD_NUMBER
+ )
+ // TODO(b/239682646): Consider adding a target preparer that unlocks the device (like CTS)
+ }
+
+ @After
+ fun tearDown() {
+ ConfigUtils.removeConfig(device)
+ ReportUtils.clearReports(device)
+ }
+
+ @Test
+ fun openSafetyCenter_recordsSafetyCenterViewedEvent() {
+ helperAppRule.runTest(TEST_CLASS_NAME, testMethodName = "openSafetyCenter")
+
+ val safetyCenterViewedAtoms = getInteractionReportedAtoms(Action.SAFETY_CENTER_VIEWED)
+
+ assertThat(safetyCenterViewedAtoms).isNotEmpty()
+ }
+
+ @Test
+ fun sendNotification_recordsNotificationPostedEvent() {
+ helperAppRule.runTest(
+ testClassName = ".SafetyCenterNotificationLoggingHelperTests",
+ testMethodName = "sendNotification"
+ )
+
+ val notificationPostedAtoms = getInteractionReportedAtoms(Action.NOTIFICATION_POSTED)
+
+ assertThat(notificationPostedAtoms).hasSize(1)
+ assertThat(notificationPostedAtoms.first().viewType)
+ .isEqualTo(ViewType.VIEW_TYPE_NOTIFICATION)
+ }
+
+ @Test
+ fun openSubpageFromIntentExtra_recordsEventWithUnknownNavigationSource() {
+ helperAppRule.runTest(TEST_CLASS_NAME, testMethodName = "openSubpageFromIntentExtra")
+
+ val safetyCenterViewedAtoms = getInteractionReportedAtoms(Action.SAFETY_CENTER_VIEWED)
+
+ assertThat(safetyCenterViewedAtoms).hasSize(1)
+ with(safetyCenterViewedAtoms.first()) {
+ assertThat(viewType).isEqualTo(ViewType.SUBPAGE)
+ assertThat(navigationSource)
+ .isEqualTo(SafetyCenterInteractionReported.NavigationSource.SOURCE_UNKNOWN)
+ assertThat(sessionId).isNotNull()
+ }
+ }
+
+ @Test
+ @Ignore
+ // TODO(b/278202773): Fix/de-flake this test
+ fun openSubpageFromHomepage_recordsEventWithSafetyCenterNavigationSource() {
+ helperAppRule.runTest(TEST_CLASS_NAME, testMethodName = "openSubpageFromHomepage")
+
+ val safetyCenterViewedAtoms = getInteractionReportedAtoms(Action.SAFETY_CENTER_VIEWED)
+
+ assertThat(safetyCenterViewedAtoms.map { it.viewType })
+ .containsExactly(ViewType.FULL, ViewType.SUBPAGE, ViewType.FULL)
+ .inOrder()
+ assertThat(safetyCenterViewedAtoms[1].navigationSource)
+ .isEqualTo(SafetyCenterInteractionReported.NavigationSource.SAFETY_CENTER)
+ assertThat(safetyCenterViewedAtoms.map { it.sessionId }.distinct()).hasSize(1)
+ }
+
+ @Test
+ @Ignore
+ // TODO(b/278202773): Fix/de-flake this test
+ fun openSubpageFromSettingsSearch_recordsEventWithSettingsNavigationSource() {
+ helperAppRule.runTest(TEST_CLASS_NAME, testMethodName = "openSubpageFromSettingsSearch")
+
+ val safetyCenterViewedAtoms = getInteractionReportedAtoms(Action.SAFETY_CENTER_VIEWED)
+
+ assertThat(safetyCenterViewedAtoms).hasSize(1)
+ with(safetyCenterViewedAtoms.first()) {
+ assertThat(viewType).isEqualTo(ViewType.SUBPAGE)
+ assertThat(navigationSource)
+ .isEqualTo(SafetyCenterInteractionReported.NavigationSource.SETTINGS)
+ assertThat(sessionId).isNotNull()
+ }
+ }
+
+ // TODO(b/239682646): Add more tests
+
+ private fun getInteractionReportedAtoms(action: SafetyCenterInteractionReported.Action) =
+ ReportUtils.getEventMetricDataList(device)
+ .mapNotNull { it.atom.safetyCenterInteractionReported }
+ .filter { it.action == action }
+
+ private companion object {
+ const val TEST_CLASS_NAME = ".SafetyCenterInteractionLoggingHelperTests"
+ }
+}
diff --git a/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterSystemEventReportedLoggingHostTest.kt b/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterSystemEventReportedLoggingHostTest.kt
new file mode 100644
index 000000000..65e47fa91
--- /dev/null
+++ b/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterSystemEventReportedLoggingHostTest.kt
@@ -0,0 +1,204 @@
+/*
+ * 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.safetycenter.hostside
+
+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.os.AtomsProto.Atom
+import com.android.os.AtomsProto.SafetyCenterSystemEventReported.EventType
+import com.android.os.AtomsProto.SafetyCenterSystemEventReported.Result
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+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)
+
+ @Before
+ fun setUp() {
+ ConfigUtils.removeConfig(device)
+ ReportUtils.clearReports(device)
+ ConfigUtils.uploadConfigForPushedAtom(
+ device,
+ safetyCenterRule.getSafetyCenterPackageName(),
+ Atom.SAFETY_CENTER_SYSTEM_EVENT_REPORTED_FIELD_NUMBER
+ )
+ // TODO(b/239682646): Consider adding a target preparer that unlocks the device (like CTS)
+ }
+
+ @After
+ fun tearDown() {
+ ReportUtils.clearReports(device)
+ ConfigUtils.removeConfig(device)
+ }
+
+ @Test
+ fun refreshAllSources_allSourcesSuccessful_successAtomsForEachSourceAndOverallCompletion() {
+ helperAppRule.runTest(
+ ".SafetySourceStateCollectedLoggingHelperTests",
+ "refreshAllSources_reasonPageOpen_allSuccessful"
+ )
+
+ val systemEventAtoms =
+ ReportUtils.getEventMetricDataList(device).mapNotNull {
+ it.atom.safetyCenterSystemEventReported
+ }
+
+ assertThat(systemEventAtoms.groupingBy { it.eventType }.eachCount())
+ .containsExactly(
+ EventType.COMPLETE_GET_NEW_DATA,
+ 1, // Overall refresh complete
+ EventType.SINGLE_SOURCE_GET_NEW_DATA,
+ 3 // For the three sources in the multiple sources test config
+ )
+ assertThat(systemEventAtoms.groupingBy { it.result }.eachCount())
+ .containsExactly(Result.SUCCESS, 4)
+ }
+
+ @Test
+ fun refreshAllSources_oneSourceError_errorAtomForThatSourceAndOverall() {
+ helperAppRule.runTest(
+ ".SafetySourceStateCollectedLoggingHelperTests",
+ "refreshAllSources_reasonPageOpen_oneError"
+ )
+
+ val systemEventAtoms =
+ ReportUtils.getEventMetricDataList(device).mapNotNull {
+ it.atom.safetyCenterSystemEventReported
+ }
+
+ assertThat(systemEventAtoms.groupingBy { Pair(it.eventType, it.result) }.eachCount())
+ .containsExactly(
+ Pair(EventType.COMPLETE_GET_NEW_DATA, Result.ERROR),
+ 1, // Overall refresh is an error
+ Pair(EventType.SINGLE_SOURCE_GET_NEW_DATA, Result.ERROR),
+ 1, // For the source which had an error
+ Pair(EventType.SINGLE_SOURCE_GET_NEW_DATA, Result.SUCCESS),
+ 2 // The remaining two sources
+ )
+ }
+
+ @Test
+ fun refreshAllSources_anyResult_atomsIncludeRefreshReason() {
+ helperAppRule.runTest(
+ ".SafetySourceStateCollectedLoggingHelperTests",
+ "refreshAllSources_reasonPageOpen_oneSuccessOneErrorOneTimeout"
+ )
+
+ val systemEventAtoms =
+ ReportUtils.getEventMetricDataList(device).mapNotNull {
+ it.atom.safetyCenterSystemEventReported
+ }
+
+ assertWithMessage("the system event atoms").that(systemEventAtoms).hasSize(4)
+ assertWithMessage("the number of atoms with the page-open refresh reason")
+ .that(systemEventAtoms.count { it.refreshReason == REFRESH_REASON_PAGE_OPEN })
+ .isEqualTo(4)
+ }
+
+ @Test
+ fun refreshAllSources_differentRefreshReason_atomsIncludeCorrectRefreshReason() {
+ helperAppRule.runTest(
+ ".SafetySourceStateCollectedLoggingHelperTests",
+ "refreshAllSources_reasonButtonClick_oneSuccessOneErrorOneTimeout"
+ )
+
+ val systemEventAtoms =
+ ReportUtils.getEventMetricDataList(device).mapNotNull {
+ it.atom.safetyCenterSystemEventReported
+ }
+
+ assertWithMessage("the system event atoms").that(systemEventAtoms).hasSize(4)
+ assertWithMessage("the number of atoms with the button-click refresh reason")
+ .that(systemEventAtoms.count { it.refreshReason == REFRESH_REASON_BUTTON_CLICK })
+ }
+
+ fun refreshAllSources_firstTime_allSourcesSuccessful_dataChangedTrueForAll() {
+ helperAppRule.runTest(
+ ".SafetySourceStateCollectedLoggingHelperTests",
+ "refreshAllSources_reasonPageOpen_allSuccessful"
+ )
+
+ val systemEventAtoms =
+ ReportUtils.getEventMetricDataList(device).mapNotNull {
+ it.atom.safetyCenterSystemEventReported
+ }
+
+ assertWithMessage("the number of atoms with dataChanged=true")
+ .that(systemEventAtoms.count { it.dataChanged })
+ .isEqualTo(4)
+ }
+
+ @Test
+ fun refreshAllSources_secondTime_allSourcesUnchanged_dataChangedFalseForAll() {
+ helperAppRule.runTest(
+ ".SafetySourceStateCollectedLoggingHelperTests",
+ "refreshAllSources_twiceSameData_allSuccessful"
+ )
+
+ val systemEventAtoms =
+ ReportUtils.getEventMetricDataList(device).mapNotNull {
+ it.atom.safetyCenterSystemEventReported
+ }
+
+ // There are three sources in the multiple sources config, of which one is not allowed to
+ // refresh on page open, except when there is no data. Plus, for each refresh there is an
+ // overall refresh atom making seven atoms in total.
+ assertWithMessage("the number of atoms").that(systemEventAtoms).hasSize(7)
+ assertWithMessage("the number of atoms with dataChanged=false")
+ .that(systemEventAtoms.count { !it.dataChanged })
+ .isEqualTo(3)
+ }
+
+ @Test
+ fun refreshAllSources_secondTime_someSourcesChanged_dataChangedCorrect() {
+ helperAppRule.runTest(
+ ".SafetySourceStateCollectedLoggingHelperTests",
+ "refreshAllSources_twiceDifferentData_onlySource1Unchanged"
+ )
+
+ val systemEventAtoms =
+ 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
+ }
+
+ companion object {
+ private const val REFRESH_REASON_PAGE_OPEN = 100L
+ private const val REFRESH_REASON_BUTTON_CLICK = 200L
+ }
+}
diff --git a/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetySourceStateCollectedLoggingHostTest.kt b/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetySourceStateCollectedLoggingHostTest.kt
new file mode 100644
index 000000000..22a380e12
--- /dev/null
+++ b/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetySourceStateCollectedLoggingHostTest.kt
@@ -0,0 +1,140 @@
+/*
+ * 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.safetycenter.hostside
+
+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.os.AtomsProto.Atom
+import com.android.os.AtomsProto.SafetySourceStateCollected
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
+import com.google.common.truth.Truth.assertThat
+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)
+
+ @Before
+ fun setUp() {
+ ConfigUtils.removeConfig(device)
+ ReportUtils.clearReports(device)
+ val config = ConfigUtils.createConfigBuilder(safetyCenterRule.getSafetyCenterPackageName())
+ ConfigUtils.addGaugeMetric(config, Atom.SAFETY_STATE_FIELD_NUMBER)
+ ConfigUtils.addEventMetric(config, Atom.SAFETY_SOURCE_STATE_COLLECTED_FIELD_NUMBER)
+ ConfigUtils.uploadConfig(device, config)
+ // TODO(b/239682646): Consider adding a target preparer that unlocks the device (like CTS)
+ }
+
+ @After
+ fun tearDown() {
+ ReportUtils.clearReports(device)
+ ConfigUtils.removeConfig(device)
+ }
+
+ @Test
+ fun triggerStatsPull_atomsPushedForAllSources() {
+ helperAppRule.runTest(TEST_CLASS_NAME, "triggerStatsPull")
+
+ val sourceStateAtoms = getSafetySourceStateCollectedAtoms()
+
+ assertThat(sourceStateAtoms.map { it.encodedSafetySourceId })
+ .containsExactly(
+ SOURCE_1_ENCODED_SOURCE_ID,
+ SOURCE_2_ENCODED_SOURCE_ID,
+ SOURCE_3_ENCODED_SOURCE_ID
+ )
+ }
+
+ @Test
+ fun triggerStatsPull_atomsHaveCollectionTypeAutomatic() {
+ helperAppRule.runTest(TEST_CLASS_NAME, "triggerStatsPull")
+
+ val sourceStateAtoms = getSafetySourceStateCollectedAtoms()
+
+ assertThat(sourceStateAtoms.map { it.collectionType }.distinct())
+ .containsExactly(SafetySourceStateCollected.CollectionType.AUTOMATIC)
+ }
+
+ @Test
+ fun setSafetySourceData_atomPushedForThatSource() {
+ helperAppRule.runTest(TEST_CLASS_NAME, "setSafetySourceData_source1")
+
+ val sourceStateAtoms = getSafetySourceStateCollectedAtoms()
+
+ assertThat(sourceStateAtoms.map { it.encodedSafetySourceId })
+ .containsExactly(SOURCE_1_ENCODED_SOURCE_ID)
+ }
+
+ @Test
+ fun setSafetySourceData_atomHasCollectionTypeSourceUpdated() {
+ helperAppRule.runTest(TEST_CLASS_NAME, "setSafetySourceData_source1")
+
+ val sourceStateAtoms = getSafetySourceStateCollectedAtoms()
+
+ assertThat(sourceStateAtoms.map { it.collectionType })
+ .containsExactly(SafetySourceStateCollected.CollectionType.SOURCE_UPDATED)
+ }
+
+ @Test
+ fun reportSafetySourceError_atomPushedForThatSource() {
+ helperAppRule.runTest(TEST_CLASS_NAME, "reportSafetySourceError_source1")
+
+ val sourceStateAtoms = getSafetySourceStateCollectedAtoms()
+
+ assertThat(sourceStateAtoms.map { it.encodedSafetySourceId })
+ .containsExactly(SOURCE_1_ENCODED_SOURCE_ID)
+ assertThat(sourceStateAtoms.map { it.collectionType })
+ .containsExactly(SafetySourceStateCollected.CollectionType.SOURCE_UPDATED)
+ }
+
+ private fun getSafetySourceStateCollectedAtoms() =
+ ReportUtils.getEventMetricDataList(device)
+ .mapNotNull { it.atom.safetySourceStateCollected }
+ .filterNot {
+ // Installing/uninstalling the helper app can cause Play Protect to run a scan and
+ // push new data to Safety Center which interferes with the test results so we
+ // specifically filter the resultant atoms out using the real encoded source ID.
+ // Similar failures are also observed on Android Test Hub due to the background
+ // location source (b/278782808)
+ it.encodedSafetySourceId == PLAY_PROTECT_ENCODED_SOURCE_ID ||
+ it.encodedSafetySourceId == BACKGROUND_LOCATION_ENCODED_SOURCE_ID
+ }
+
+ private companion object {
+ const val TEST_CLASS_NAME = ".SafetySourceStateCollectedLoggingHelperTests"
+ const val PLAY_PROTECT_ENCODED_SOURCE_ID = 7711894340233229936L
+ const val BACKGROUND_LOCATION_ENCODED_SOURCE_ID = 7355693215512427559L
+ const val SOURCE_1_ENCODED_SOURCE_ID = 6446219357586936066L
+ const val SOURCE_2_ENCODED_SOURCE_ID = -5887429047684886602L
+ const val SOURCE_3_ENCODED_SOURCE_ID = -619470868366498469L
+ }
+}
diff --git a/tests/hostside/safetycenter/src/android/safetycenter/hostside/rules/HelperAppRule.kt b/tests/hostside/safetycenter/src/android/safetycenter/hostside/rules/HelperAppRule.kt
new file mode 100644
index 000000000..cf46a8443
--- /dev/null
+++ b/tests/hostside/safetycenter/src/android/safetycenter/hostside/rules/HelperAppRule.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 android.safetycenter.hostside.rules
+
+import android.cts.statsdatom.lib.DeviceUtils
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/**
+ * JUnit rule for host side tests that installs a helper app with the given [apkName] and
+ * [packageName].
+ */
+class HelperAppRule(
+ private val hostTestClass: BaseHostJUnit4Test,
+ private val apkName: String,
+ private val packageName: String
+) : TestRule {
+
+ override fun apply(base: Statement, description: Description): Statement {
+ return object : Statement() {
+ override fun evaluate() {
+ try {
+ DeviceUtils.installTestApp(
+ hostTestClass.device,
+ apkName,
+ packageName,
+ hostTestClass.build
+ )
+ base.evaluate()
+ } finally {
+ DeviceUtils.uninstallTestApp(hostTestClass.device, packageName)
+ }
+ }
+ }
+ }
+
+ /** Runs the specified test in the helper app. */
+ fun runTest(testClassName: String, testMethodName: String) {
+ DeviceUtils.runDeviceTests(hostTestClass.device, packageName, testClassName, testMethodName)
+ }
+}
diff --git a/tests/hostside/safetycenter/src/android/safetycenter/hostside/rules/RequireSafetyCenterRule.kt b/tests/hostside/safetycenter/src/android/safetycenter/hostside/rules/RequireSafetyCenterRule.kt
new file mode 100644
index 000000000..809fe5f0f
--- /dev/null
+++ b/tests/hostside/safetycenter/src/android/safetycenter/hostside/rules/RequireSafetyCenterRule.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 android.safetycenter.hostside.rules
+
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
+import com.android.tradefed.util.CommandStatus
+import java.io.IOException
+import org.junit.Assume.assumeTrue
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/** 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()
+ }
+ private val safetyCenterEnabled: Boolean by lazy {
+ executeShellCommandOrThrow("cmd safety_center enabled").toBoolean()
+ }
+
+ override fun apply(base: Statement, description: Description): Statement {
+ return object : Statement() {
+ override fun evaluate() {
+ assumeTrue("Test device does not support Safety Center", safetyCenterSupported)
+ assumeTrue("Safety Center is not enabled on test device", safetyCenterEnabled)
+ base.evaluate()
+ }
+ }
+ }
+
+ /** Returns the package name of Safety Center on the test device. */
+ fun getSafetyCenterPackageName(): String =
+ executeShellCommandOrThrow("cmd safety_center package-name")
+
+ private fun executeShellCommandOrThrow(command: String): String {
+ val result = hostTestClass.device.executeShellV2Command(command)
+ if (result.status != CommandStatus.SUCCESS) {
+ throw IOException("$command exited with status ${result.exitCode}")
+ }
+ return result.stdout.trim()
+ }
+}
diff --git a/tests/utils/safetycenter/Android.bp b/tests/utils/safetycenter/Android.bp
new file mode 100644
index 000000000..1c76dc775
--- /dev/null
+++ b/tests/utils/safetycenter/Android.bp
@@ -0,0 +1,48 @@
+//
+// 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_library {
+ name: "safety-center-test-util-lib",
+ sdk_version: "test_current",
+ min_sdk_version: "29",
+ srcs: [
+ "java/**/*.kt",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "compatibility-device-util-axt",
+ // NOTE: when importing this library in a test you may have to add the following option to
+ // the test element of your AndroidTest.xml file in order to ignore guava tests:
+ // <option name="exclude-annotation" value="org.junit.Ignore"/>
+ "guava-android",
+ "guava-android-testlib",
+ "kotlinx-coroutines-android",
+ "safety-center-internal-data",
+ "safety-center-resources-lib",
+ ],
+ apex_available: [
+ "com.android.permission",
+ "test_com.android.permission",
+ ],
+ installable: false,
+ visibility: [
+ "//packages/modules/Permission:__subpackages__",
+ "//vendor:__subpackages__",
+ ],
+}
diff --git a/tests/utils/safetycenter/AndroidManifest.xml b/tests/utils/safetycenter/AndroidManifest.xml
new file mode 100644
index 000000000..9d7c52e62
--- /dev/null
+++ b/tests/utils/safetycenter/AndroidManifest.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.safetycenter.testing">
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+
+ <application>
+ <!-- The receiver is marked as disabled and is manually enabled in the tests for the desired
+ user(s); as it does not support multi-users calls for now. -->
+ <receiver android:name=".SafetySourceReceiver"
+ android:enabled="false"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED"/>
+ <action android:name="android.safetycenter.action.REFRESH_SAFETY_SOURCES"/>
+ <action android:name="com.android.safetycenter.testing.action.RESOLVE_ACTION"/>
+ <action android:name="com.android.safetycenter.testing.action.DISMISS_ISSUE"/>
+ </intent-filter>
+ </receiver>
+
+ <service android:name=".SafetySourceReceiver$ForegroundService"
+ android:foregroundServiceType="dataSync"
+ android:exported="false"/>
+
+ <activity android:name=".TestActivity"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="com.android.safetycenter.testing.action.TEST_ACTIVITY"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+
+ <activity-alias android:name=".TestActivityExported"
+ android:targetActivity=".TestActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.safetycenter.testing.action.TEST_ACTIVITY_EXPORTED"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity-alias>
+ </application>
+</manifest>
diff --git a/tests/utils/safetycenter/OWNERS b/tests/utils/safetycenter/OWNERS
new file mode 100644
index 000000000..5d8b8161b
--- /dev/null
+++ b/tests/utils/safetycenter/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1026964
+
+include /SafetyCenter/OWNERS
diff --git a/tests/utils/safetycenter/TEST_MAPPING b/tests/utils/safetycenter/TEST_MAPPING
new file mode 100644
index 000000000..3cad386bc
--- /dev/null
+++ b/tests/utils/safetycenter/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "packages/modules/Permission/SafetyCenter"
+ }
+ ]
+}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/Coroutines.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/Coroutines.kt
new file mode 100644
index 000000000..44c0686e2
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/Coroutines.kt
@@ -0,0 +1,103 @@
+/*
+ * 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.testing
+
+import android.util.Log
+import java.time.Duration
+import kotlinx.coroutines.DEBUG_PROPERTY_NAME
+import kotlinx.coroutines.DEBUG_PROPERTY_VALUE_AUTO
+import kotlinx.coroutines.DEBUG_PROPERTY_VALUE_ON
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withTimeout
+import kotlinx.coroutines.withTimeoutOrNull
+
+/** A class that facilitates interacting with coroutines. */
+object Coroutines {
+
+ /** A long timeout, to be used for actions that are expected to complete. */
+ val TIMEOUT_LONG: Duration = Duration.ofSeconds(25)
+
+ /** A short timeout, to be used for actions that are expected not to complete. */
+ val TIMEOUT_SHORT: Duration = Duration.ofSeconds(1)
+
+ /** Shorthand for [runBlocking] combined with [withTimeout]. */
+ fun <T> runBlockingWithTimeout(timeout: Duration = TIMEOUT_LONG, block: suspend () -> T): T =
+ runBlocking {
+ withTimeout(timeout.toMillis()) { block() }
+ }
+
+ /** Shorthand for [runBlocking] combined with [withTimeoutOrNull] */
+ fun <T> runBlockingWithTimeoutOrNull(
+ timeout: Duration = TIMEOUT_LONG,
+ block: suspend () -> T
+ ): T? = runBlocking { withTimeoutOrNull(timeout.toMillis()) { block() } }
+
+ /** Check a condition using coroutines with a timeout. */
+ fun waitForWithTimeout(
+ timeout: Duration = TIMEOUT_LONG,
+ checkPeriod: Duration = CHECK_PERIOD,
+ condition: () -> Boolean
+ ) {
+ runBlockingWithTimeout(timeout) { waitFor(checkPeriod, condition) }
+ }
+
+ /** Retries a [fallibleAction] until no errors are thrown or a timeout occurs. */
+ fun waitForSuccessWithTimeout(
+ timeout: Duration = TIMEOUT_LONG,
+ checkPeriod: Duration = CHECK_PERIOD,
+ fallibleAction: () -> Unit
+ ) {
+ waitForWithTimeout(timeout, checkPeriod) {
+ try {
+ fallibleAction()
+ true
+ } catch (ex: Throwable) {
+ Log.w(TAG, "Encountered failure, retrying until timeout: $ex")
+ false
+ }
+ }
+ }
+
+ /**
+ * Enables debug mode for coroutines, in particular this enables stack traces in case of
+ * failures.
+ */
+ fun enableDebugging() {
+ System.setProperty(DEBUG_PROPERTY_NAME, DEBUG_PROPERTY_VALUE_ON)
+ }
+
+ /** Resets the debug mode to its original state. */
+ fun resetDebugging() {
+ System.setProperty(DEBUG_PROPERTY_NAME, debugMode)
+ }
+
+ /** Check a condition using coroutines. */
+ private suspend fun waitFor(checkPeriod: Duration = CHECK_PERIOD, condition: () -> Boolean) {
+ while (!condition()) {
+ delay(checkPeriod.toMillis())
+ }
+ }
+
+ private const val TAG: String = "Coroutines"
+
+ /** A medium period, to be used for conditions that are expected to change. */
+ private val CHECK_PERIOD: Duration = Duration.ofMillis(250)
+
+ private val debugMode: String? =
+ System.getProperty(DEBUG_PROPERTY_NAME, DEBUG_PROPERTY_VALUE_AUTO)
+}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/EqualsHashCodeToStringTester.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/EqualsHashCodeToStringTester.kt
new file mode 100644
index 000000000..2dedfc853
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/EqualsHashCodeToStringTester.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.safetycenter.testing
+
+import android.os.Bundle
+import android.os.Parcelable
+import androidx.test.core.os.Parcelables.forceParcel
+import com.google.common.base.Equivalence
+import com.google.common.testing.EqualsTester
+import com.google.common.testing.EquivalenceTester
+
+/**
+ * A class similar to [EqualsTester] that also optionally checks that the [Object.hashCode],
+ * [Object.toString] and [Parcelable] implementations are consistent with equality groups.
+ *
+ * Note: this class assumes that [Object.hashCode] does not create a collision for equality groups,
+ * however this can be disabled by setting [ignoreHashCode] to `true`.
+ *
+ * Note: this class assumes that [Object.toString] only represents the state that is used in
+ * [Object.equals] and [Object.hashCode] implementation. Objects with [Bundle] fields may break it.
+ * This can be disabled by setting [ignoreToString] to `true`.
+ *
+ * @param parcelRoundTripEqualsEquivalence optionally provide an equivalence that also checks that
+ * the [Parcelable] implementation is consistent with equality groups by recreating equal items
+ * from their [Parcelable] implementation
+ * @param createCopy optionally provide a custom method to create an equal copy that will be applied
+ * to all the items in provided in an equality group
+ */
+class EqualsHashCodeToStringTester<T>
+private constructor(
+ private val ignoreHashCode: Boolean = false,
+ private val ignoreToString: Boolean = false,
+ private val parcelRoundTripEqualsEquivalence: Equivalence<T>? = null,
+ private val createCopy: ((T) -> T)? = null
+) {
+
+ private val equalsTester = EqualsTester()
+ private val hashCodeTester =
+ EquivalenceTester.of<T>(hashCodeEquivalence()).takeIf { !ignoreHashCode }
+ private val toStringTester =
+ EquivalenceTester.of<T>(toStringEquivalence()).takeIf { !ignoreToString }
+ private val parcelableTester =
+ parcelRoundTripEqualsEquivalence?.let { EquivalenceTester.of(it) }
+
+ fun addEqualityGroup(vararg equalItems: T): EqualsHashCodeToStringTester<T> {
+ val equalItemsWithCopiesIfNeeded = equalItems.toList().withCopiesIfNeeded(createCopy)
+ equalsTester.addEqualityGroup(*equalItemsWithCopiesIfNeeded.toAnyArray())
+ hashCodeTester?.addEquivalenceGroup(equalItemsWithCopiesIfNeeded)
+ toStringTester?.addEquivalenceGroup(equalItemsWithCopiesIfNeeded)
+ parcelableTester?.addEquivalenceGroup(equalItemsWithCopiesIfNeeded)
+ return this
+ }
+
+ fun test() {
+ equalsTester.testEquals()
+ hashCodeTester?.test()
+ toStringTester?.test()
+ parcelableTester?.test()
+ }
+
+ companion object {
+
+ /**
+ * Returns an [EqualsHashCodeToStringTester] that also checks that the [Parcelable]
+ * implementation: i.e. recreating an instance from its [Parcelable] implementation returns
+ * an object that's consistent with its equality group.
+ *
+ * @see EqualsHashCodeToStringTester
+ */
+ fun <T : Parcelable> ofParcelable(
+ parcelableCreator: Parcelable.Creator<T>,
+ ignoreHashCode: Boolean = false,
+ ignoreToString: Boolean = false,
+ createCopy: ((T) -> T)? = null
+ ): EqualsHashCodeToStringTester<T> =
+ EqualsHashCodeToStringTester(
+ ignoreHashCode,
+ ignoreToString,
+ parcelRoundTripEqualsEquivalence(parcelableCreator),
+ createCopy
+ )
+
+ /**
+ * Returns an [EqualsHashCodeToStringTester] that does not check the [Parcelable]
+ * implementation of the class, typically if the class doesn't implement [Parcelable].
+ *
+ * @see EqualsHashCodeToStringTester
+ */
+ fun <T> of(
+ ignoreHashCode: Boolean = false,
+ ignoreToString: Boolean = false,
+ createCopy: ((T) -> T)? = null
+ ): EqualsHashCodeToStringTester<T> =
+ EqualsHashCodeToStringTester(
+ ignoreHashCode,
+ ignoreToString,
+ parcelRoundTripEqualsEquivalence = null,
+ createCopy
+ )
+
+ /**
+ * An [Equivalence] that considers two instances of a class equivalent iff they are still
+ * equal when one of them is recreated from their [Parcelable] implementation.
+ */
+ private fun <T : Parcelable> parcelRoundTripEqualsEquivalence(
+ parcelableCreator: Parcelable.Creator<T>
+ ) =
+ object : Equivalence<T>() {
+
+ override fun doEquivalent(a: T, b: T): Boolean {
+ return a.recreateFromParcel() == b && a == b.recreateFromParcel()
+ }
+
+ override fun doHash(o: T): Int {
+ return o.recreateFromParcel().hashCode()
+ }
+
+ private fun T.recreateFromParcel(): T = forceParcel(this, parcelableCreator)
+ }
+
+ /**
+ * An [Equivalence] that considers two instances of a class equivalent iff [Object.toString]
+ * return the same value.
+ */
+ private fun <T> toStringEquivalence() =
+ object : Equivalence<T>() {
+
+ override fun doEquivalent(a: T, b: T): Boolean {
+ return a.toString() == b.toString()
+ }
+
+ override fun doHash(o: T): Int {
+ return o.toString().hashCode()
+ }
+ }
+
+ /**
+ * An [Equivalence] that considers two instances of a class equivalent iff [Object.hashCode]
+ * return the same value.
+ */
+ private fun <T> hashCodeEquivalence() =
+ object : Equivalence<T>() {
+
+ override fun doEquivalent(a: T, b: T): Boolean {
+ return a.hashCode() == b.hashCode()
+ }
+
+ override fun doHash(o: T): Int {
+ return o.hashCode()
+ }
+ }
+
+ private fun <T> List<T>.toAnyArray(): Array<*> = Array(size) { this[it] as Any }
+
+ private fun <T> List<T>.withCopiesIfNeeded(createCopy: ((T) -> T)? = null): List<T> =
+ createCopy?.let { this + this.map(it) } ?: this
+ }
+}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterActivityLauncher.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterActivityLauncher.kt
new file mode 100644
index 000000000..537eb7ead
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterActivityLauncher.kt
@@ -0,0 +1,122 @@
+/*
+ * 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.testing
+
+import android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
+import android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE
+import android.content.Context
+import android.content.Intent
+import android.content.Intent.ACTION_SAFETY_CENTER
+import android.content.Intent.ACTION_VIEW_SAFETY_CENTER_QS
+import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
+import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
+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
+
+/** A class that provides a way to launch the SafetyCenter activity in tests. */
+@RequiresApi(TIRAMISU)
+object SafetyCenterActivityLauncher {
+
+ /**
+ * Launches the SafetyCenter activity and exits it once [block] completes.
+ *
+ * @param withReceiverPermission whether we should hold the [SEND_SAFETY_CENTER_UPDATE]
+ * permission while the activity is on the screen (e.g. to ensure the CTS package can have its
+ * receiver called during refresh/rescan)
+ */
+ fun Context.launchSafetyCenterActivity(
+ intentExtras: Bundle? = null,
+ withReceiverPermission: Boolean = false,
+ preventTrampolineToSettings: Boolean = true,
+ block: () -> Unit
+ ) {
+ val launchSafetyCenterIntent =
+ createIntent(
+ ACTION_SAFETY_CENTER,
+ intentExtras,
+ preventTrampolineToSettings = preventTrampolineToSettings
+ )
+ if (withReceiverPermission) {
+ callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) {
+ executeBlockAndExit(block) { startActivity(launchSafetyCenterIntent) }
+ }
+ } else {
+ executeBlockAndExit(block) { startActivity(launchSafetyCenterIntent) }
+ }
+ }
+
+ /** Launches the SafetyCenter Quick Settings activity and exits it once [block] completes. */
+ fun Context.launchSafetyCenterQsActivity(intentExtras: Bundle? = null, block: () -> Unit) {
+ val launchSafetyCenterQsIntent = createIntent(ACTION_VIEW_SAFETY_CENTER_QS, intentExtras)
+ executeBlockAndExit(block) {
+ callWithShellPermissionIdentity(REVOKE_RUNTIME_PERMISSIONS) {
+ startActivity(launchSafetyCenterQsIntent)
+ }
+ }
+ }
+
+ /** Launches a page in Safety Center and exits it once [block] completes. */
+ fun openPageAndExit(entryPoint: String, block: () -> Unit) {
+ 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?,
+ preventTrampolineToSettings: Boolean = false
+ ): Intent {
+ val launchIntent =
+ Intent(intentAction).addFlags(FLAG_ACTIVITY_NEW_TASK).addFlags(FLAG_ACTIVITY_CLEAR_TASK)
+ intentExtras?.let { launchIntent.putExtras(it) }
+ if (preventTrampolineToSettings) {
+ launchIntent.putExtra(EXTRA_PREVENT_TRAMPOLINE_TO_SETTINGS, true)
+ }
+ return launchIntent
+ }
+
+ fun executeBlockAndExit(block: () -> Unit, launchActivity: () -> Unit) {
+ val uiDevice = getUiDevice()
+ uiDevice.waitForIdle()
+ launchActivity()
+ uiDevice.waitForIdle()
+ block()
+ uiDevice.pressBack()
+ uiDevice.waitForIdle()
+ }
+
+ private const val EXTRA_PREVENT_TRAMPOLINE_TO_SETTINGS: String =
+ "com.android.permissioncontroller.safetycenter.extra.PREVENT_TRAMPOLINE_TO_SETTINGS"
+}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetyCenterApisWithShellPermissions.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterApisWithShellPermissions.kt
index fe1092873..961d03c47 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetyCenterApisWithShellPermissions.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterApisWithShellPermissions.kt
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package android.safetycenter.cts.testing
+package com.android.safetycenter.testing
import android.Manifest.permission.MANAGE_SAFETY_CENTER
import android.Manifest.permission.READ_SAFETY_CENTER_STATUS
import android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE
+import android.os.Build.VERSION_CODES.TIRAMISU
import android.safetycenter.SafetyCenterData
import android.safetycenter.SafetyCenterManager
import android.safetycenter.SafetyCenterManager.OnSafetyCenterDataChangedListener
@@ -26,13 +27,15 @@ import android.safetycenter.SafetyEvent
import android.safetycenter.SafetySourceData
import android.safetycenter.SafetySourceErrorDetails
import android.safetycenter.config.SafetyCenterConfig
-import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
+import androidx.annotation.RequiresApi
+import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity
import java.util.concurrent.Executor
/**
* Extension methods for [SafetyCenterManager] that delegate to the relevant implementation, but
* making each call with the appropriate permission.
*/
+@RequiresApi(TIRAMISU)
object SafetyCenterApisWithShellPermissions {
/**
@@ -40,7 +43,7 @@ object SafetyCenterApisWithShellPermissions {
* [READ_SAFETY_CENTER_STATUS] permission.
*/
fun SafetyCenterManager.isSafetyCenterEnabledWithPermission(): Boolean =
- callWithShellPermissionIdentity({ isSafetyCenterEnabled }, READ_SAFETY_CENTER_STATUS)
+ callWithShellPermissionIdentity(READ_SAFETY_CENTER_STATUS) { isSafetyCenterEnabled }
/**
* Calls [SafetyCenterManager.setSafetySourceData] adopting Shell's [SEND_SAFETY_CENTER_UPDATE]
@@ -51,9 +54,9 @@ object SafetyCenterApisWithShellPermissions {
safetySourceData: SafetySourceData?,
safetyEvent: SafetyEvent
) {
- callWithShellPermissionIdentity(
- { setSafetySourceData(safetySourceId, safetySourceData, safetyEvent) },
- SEND_SAFETY_CENTER_UPDATE)
+ callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) {
+ setSafetySourceData(safetySourceId, safetySourceData, safetyEvent)
+ }
}
/**
@@ -61,7 +64,7 @@ object SafetyCenterApisWithShellPermissions {
* permission.
*/
fun SafetyCenterManager.getSafetySourceDataWithPermission(id: String): SafetySourceData? =
- callWithShellPermissionIdentity({ getSafetySourceData(id) }, SEND_SAFETY_CENTER_UPDATE)
+ callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) { getSafetySourceData(id) }
/**
* Calls [SafetyCenterManager.reportSafetySourceError] adopting Shell's
@@ -71,18 +74,26 @@ object SafetyCenterApisWithShellPermissions {
safetySourceId: String,
safetySourceErrorDetails: SafetySourceErrorDetails
) {
- callWithShellPermissionIdentity(
- { reportSafetySourceError(safetySourceId, safetySourceErrorDetails) },
- SEND_SAFETY_CENTER_UPDATE)
+ callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) {
+ reportSafetySourceError(safetySourceId, safetySourceErrorDetails)
+ }
}
/**
* Calls [SafetyCenterManager.refreshSafetySources] adopting Shell's [MANAGE_SAFETY_CENTER]
* permission.
*/
- fun SafetyCenterManager.refreshSafetySourcesWithPermission(refreshReason: Int) {
- callWithShellPermissionIdentity(
- { refreshSafetySources(refreshReason) }, MANAGE_SAFETY_CENTER)
+ fun SafetyCenterManager.refreshSafetySourcesWithPermission(
+ refreshReason: Int,
+ safetySourceIds: List<String>? = null
+ ) {
+ callWithShellPermissionIdentity(MANAGE_SAFETY_CENTER) {
+ if (safetySourceIds != null) {
+ refreshSafetySources(refreshReason, safetySourceIds)
+ } else {
+ refreshSafetySources(refreshReason)
+ }
+ }
}
/**
@@ -90,14 +101,14 @@ object SafetyCenterApisWithShellPermissions {
* permission.
*/
fun SafetyCenterManager.getSafetyCenterConfigWithPermission(): SafetyCenterConfig? =
- callWithShellPermissionIdentity(::getSafetyCenterConfig, MANAGE_SAFETY_CENTER)
+ callWithShellPermissionIdentity(MANAGE_SAFETY_CENTER) { safetyCenterConfig }
/**
* Calls [SafetyCenterManager.getSafetyCenterData] adopting Shell's [MANAGE_SAFETY_CENTER]
* permission.
*/
fun SafetyCenterManager.getSafetyCenterDataWithPermission(): SafetyCenterData =
- callWithShellPermissionIdentity(::getSafetyCenterData, MANAGE_SAFETY_CENTER)
+ callWithShellPermissionIdentity(MANAGE_SAFETY_CENTER) { safetyCenterData }
/**
* Calls [SafetyCenterManager.addOnSafetyCenterDataChangedListener] adopting Shell's
@@ -107,8 +118,9 @@ object SafetyCenterApisWithShellPermissions {
executor: Executor,
listener: OnSafetyCenterDataChangedListener
) {
- callWithShellPermissionIdentity(
- { addOnSafetyCenterDataChangedListener(executor, listener) }, MANAGE_SAFETY_CENTER)
+ callWithShellPermissionIdentity(MANAGE_SAFETY_CENTER) {
+ addOnSafetyCenterDataChangedListener(executor, listener)
+ }
}
/**
@@ -118,8 +130,9 @@ object SafetyCenterApisWithShellPermissions {
fun SafetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(
listener: OnSafetyCenterDataChangedListener
) {
- callWithShellPermissionIdentity(
- { removeOnSafetyCenterDataChangedListener(listener) }, MANAGE_SAFETY_CENTER)
+ callWithShellPermissionIdentity(MANAGE_SAFETY_CENTER) {
+ removeOnSafetyCenterDataChangedListener(listener)
+ }
}
/**
@@ -127,8 +140,9 @@ object SafetyCenterApisWithShellPermissions {
* permission.
*/
fun SafetyCenterManager.dismissSafetyCenterIssueWithPermission(safetyCenterIssueId: String) {
- callWithShellPermissionIdentity(
- { dismissSafetyCenterIssue(safetyCenterIssueId) }, MANAGE_SAFETY_CENTER)
+ callWithShellPermissionIdentity(MANAGE_SAFETY_CENTER) {
+ dismissSafetyCenterIssue(safetyCenterIssueId)
+ }
}
/**
@@ -139,9 +153,9 @@ object SafetyCenterApisWithShellPermissions {
safetyCenterIssueId: String,
safetyCenterIssueActionId: String
) {
- callWithShellPermissionIdentity(
- { executeSafetyCenterIssueAction(safetyCenterIssueId, safetyCenterIssueActionId) },
- MANAGE_SAFETY_CENTER)
+ callWithShellPermissionIdentity(MANAGE_SAFETY_CENTER) {
+ executeSafetyCenterIssueAction(safetyCenterIssueId, safetyCenterIssueActionId)
+ }
}
/**
@@ -149,8 +163,7 @@ object SafetyCenterApisWithShellPermissions {
* [MANAGE_SAFETY_CENTER] permission.
*/
fun SafetyCenterManager.clearAllSafetySourceDataForTestsWithPermission() =
- callWithShellPermissionIdentity(
- { clearAllSafetySourceDataForTests() }, MANAGE_SAFETY_CENTER)
+ callWithShellPermissionIdentity(MANAGE_SAFETY_CENTER) { clearAllSafetySourceDataForTests() }
/**
* Calls [SafetyCenterManager.setSafetyCenterConfigForTests] adopting Shell's
@@ -159,8 +172,9 @@ object SafetyCenterApisWithShellPermissions {
fun SafetyCenterManager.setSafetyCenterConfigForTestsWithPermission(
safetyCenterConfig: SafetyCenterConfig
) {
- callWithShellPermissionIdentity(
- { setSafetyCenterConfigForTests(safetyCenterConfig) }, MANAGE_SAFETY_CENTER)
+ callWithShellPermissionIdentity(MANAGE_SAFETY_CENTER) {
+ setSafetyCenterConfigForTests(safetyCenterConfig)
+ }
}
/**
@@ -168,6 +182,6 @@ object SafetyCenterApisWithShellPermissions {
* [MANAGE_SAFETY_CENTER] permission.
*/
fun SafetyCenterManager.clearSafetyCenterConfigForTestsWithPermission() {
- callWithShellPermissionIdentity({ clearSafetyCenterConfigForTests() }, MANAGE_SAFETY_CENTER)
+ callWithShellPermissionIdentity(MANAGE_SAFETY_CENTER) { clearSafetyCenterConfigForTests() }
}
}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterEnabledChangedReceiver.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterEnabledChangedReceiver.kt
new file mode 100644
index 000000000..b948dc52c
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterEnabledChangedReceiver.kt
@@ -0,0 +1,87 @@
+/*
+ * 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.testing
+
+import android.Manifest.permission.READ_SAFETY_CENTER_STATUS
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+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.runBlockingWithTimeout
+import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity
+import java.time.Duration
+
+/** Broadcast receiver used for testing broadcasts sent when the SafetyCenter flag changes. */
+@RequiresApi(TIRAMISU)
+class SafetyCenterEnabledChangedReceiver(private val context: Context) : BroadcastReceiver() {
+
+ private val mSafetySourceIntentHandler = SafetySourceIntentHandler()
+
+ init {
+ context.registerReceiver(this, IntentFilter(ACTION_SAFETY_CENTER_ENABLED_CHANGED))
+ }
+
+ override fun onReceive(context: Context, intent: Intent?) {
+ if (intent == null) {
+ throw IllegalArgumentException("Received null intent")
+ }
+
+ if (intent.action != ACTION_SAFETY_CENTER_ENABLED_CHANGED) {
+ throw IllegalArgumentException("Received intent with action: ${intent.action}")
+ }
+
+ runBlockingWithTimeout { mSafetySourceIntentHandler.handle(context, intent) }
+ }
+
+ fun setSafetyCenterEnabledWithReceiverPermissionAndWait(
+ value: Boolean,
+ timeout: Duration = TIMEOUT_LONG
+ ) =
+ callWithShellPermissionIdentity(READ_SAFETY_CENTER_STATUS) {
+ setSafetyCenterEnabledWithoutReceiverPermissionAndWait(value, timeout)
+ }
+
+ fun setSafetyCenterEnabledWithoutReceiverPermissionAndWait(
+ value: Boolean,
+ timeout: Duration = TIMEOUT_LONG
+ ): Boolean {
+ SafetyCenterFlags.isEnabled = value
+ if (timeout < TIMEOUT_LONG) {
+ SystemUtil.waitForBroadcasts()
+ }
+ return receiveSafetyCenterEnabledChanged(timeout)
+ }
+
+ fun unregister() {
+ context.unregisterReceiver(this)
+ mSafetySourceIntentHandler.cancel()
+ }
+
+ /**
+ * Waits for an [ACTION_SAFETY_CENTER_ENABLED_CHANGED] to be received by this receiver within
+ * the given [timeout].
+ */
+ fun receiveSafetyCenterEnabledChanged(timeout: Duration = TIMEOUT_LONG): Boolean =
+ runBlockingWithTimeout(timeout) {
+ mSafetySourceIntentHandler.receiveSafetyCenterEnabledChanged()
+ }
+}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt
new file mode 100644
index 000000000..aad979229
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt
@@ -0,0 +1,562 @@
+/*
+ * 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.testing
+
+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
+import android.provider.DeviceConfig.Properties
+import android.safetycenter.SafetyCenterManager.REFRESH_REASON_DEVICE_LOCALE_CHANGE
+import android.safetycenter.SafetyCenterManager.REFRESH_REASON_DEVICE_REBOOT
+import android.safetycenter.SafetyCenterManager.REFRESH_REASON_OTHER
+import android.safetycenter.SafetyCenterManager.REFRESH_REASON_PAGE_OPEN
+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.safetycenter.testing.Coroutines.TIMEOUT_LONG
+import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity
+import java.time.Duration
+import kotlin.reflect.KProperty
+
+/** A class that facilitates working with Safety Center flags. */
+object SafetyCenterFlags {
+
+ /** Flag that determines whether Safety Center is enabled. */
+ private val isEnabledFlag =
+ Flag("safety_center_is_enabled", defaultValue = false, BooleanParser())
+
+ /** Flag that determines whether Safety Center can send notifications. */
+ private val notificationsFlag =
+ Flag("safety_center_notifications_enabled", defaultValue = false, BooleanParser())
+
+ /**
+ * Flag that determines the minimum delay before Safety Center can send a notification for an
+ * issue with [SafetySourceIssue.NOTIFICATION_BEHAVIOR_DELAYED].
+ *
+ * The actual delay used may be longer.
+ */
+ private val notificationsMinDelayFlag =
+ Flag(
+ "safety_center_notifications_min_delay",
+ defaultValue = Duration.ofHours(2),
+ DurationParser()
+ )
+
+ /**
+ * Flag containing a comma delimited list of IDs of sources that Safety Center can send
+ * notifications about, in addition to those permitted by the current XML config.
+ */
+ private val notificationsAllowedSourcesFlag =
+ Flag(
+ "safety_center_notifications_allowed_sources",
+ defaultValue = emptySet(),
+ SetParser(StringParser())
+ )
+
+ /**
+ * Flag containing a comma-delimited list of the issue type IDs for which, if otherwise
+ * undefined, Safety Center should use [SafetySourceIssue.NOTIFICATION_BEHAVIOR_IMMEDIATELY].
+ */
+ private val immediateNotificationBehaviorIssuesFlag =
+ Flag(
+ "safety_center_notifications_immediate_behavior_issues",
+ defaultValue = emptySet(),
+ SetParser(StringParser())
+ )
+
+ /**
+ * Flag for the minimum interval which must elapse before Safety Center can resurface a
+ * notification after it was dismissed. A negative [Duration] (the default) means that dismissed
+ * notifications cannot resurface.
+ *
+ * There may be other conditions for resurfacing a notification and the actual delay may be
+ * longer than this.
+ */
+ private val notificationResurfaceIntervalFlag =
+ Flag(
+ "safety_center_notification_resurface_interval",
+ defaultValue = Duration.ofDays(-1),
+ 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 = false, 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())
+
+ /**
+ * Flag that determines the time for which a Safety Center refresh is allowed to wait for a
+ * source to respond to a refresh request before timing out and marking the refresh as finished,
+ * depending on the refresh reason.
+ */
+ private val refreshSourceTimeoutsFlag =
+ Flag(
+ "safety_center_refresh_sources_timeouts_millis",
+ defaultValue = getAllRefreshTimeoutsMap(TIMEOUT_LONG),
+ MapParser(IntParser(), DurationParser())
+ )
+
+ /**
+ * Flag that determines the time for which Safety Center will wait for a source to respond to a
+ * resolving action before timing out.
+ */
+ private val resolveActionTimeoutFlag =
+ Flag(
+ "safety_center_resolve_action_timeout_millis",
+ defaultValue = TIMEOUT_LONG,
+ DurationParser()
+ )
+
+ /** Flag that determines a duration after which a temporarily hidden issue will resurface. */
+ private val tempHiddenIssueResurfaceDelayFlag =
+ Flag(
+ "safety_center_temp_hidden_issue_resurface_delay_millis",
+ defaultValue = Duration.ofDays(2),
+ DurationParser()
+ )
+
+ /**
+ * Flag that determines the time for which Safety Center will wait before starting dismissal of
+ * resolved issue UI
+ */
+ private val hideResolveUiTransitionDelayFlag =
+ Flag(
+ "safety_center_hide_resolved_ui_transition_delay_millis",
+ defaultValue = Duration.ofMillis(400),
+ DurationParser()
+ )
+
+ /**
+ * Flag containing a comma delimited lists of source IDs that we won't track when deciding if a
+ * broadcast is completed. We still send broadcasts to (and handle API calls from) these sources
+ * as normal.
+ */
+ private val untrackedSourcesFlag =
+ Flag(
+ "safety_center_untracked_sources",
+ defaultValue = emptySet(),
+ SetParser(StringParser())
+ )
+
+ /**
+ * Flag containing a map (a comma separated list of colon separated pairs) where the key is an
+ * issue [SafetySourceData.SeverityLevel] and the value is the number of times an issue of this
+ * [SafetySourceData.SeverityLevel] should be resurfaced.
+ */
+ private val resurfaceIssueMaxCountsFlag =
+ Flag(
+ "safety_center_resurface_issue_max_counts",
+ defaultValue = emptyMap(),
+ MapParser(IntParser(), LongParser())
+ )
+
+ /**
+ * Flag containing a map (a comma separated list of colon separated pairs) where the key is an
+ * issue [SafetySourceData.SeverityLevel] and the value is the time after which a dismissed
+ * issue of this [SafetySourceData.SeverityLevel] will resurface if it has not reached the
+ * maximum count for which a dismissed issue of this [SafetySourceData.SeverityLevel] should be
+ * resurfaced.
+ */
+ private val resurfaceIssueDelaysFlag =
+ Flag(
+ "safety_center_resurface_issue_delays_millis",
+ defaultValue = emptyMap(),
+ MapParser(IntParser(), DurationParser())
+ )
+
+ /**
+ * Flag containing a map (a comma separated list of colon separated pairs) where the key is an
+ * issue [SafetySourceIssue.IssueCategory] and the value is a vertical-bar-delimited list of IDs
+ * of safety sources that are allowed to send issues with this category.
+ */
+ private val issueCategoryAllowlistsFlag =
+ Flag(
+ "safety_center_issue_category_allowlists",
+ defaultValue = emptyMap(),
+ MapParser(IntParser(), 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.
+ */
+ private val backgroundRefreshDeniedSourcesFlag =
+ Flag(
+ "safety_center_background_refresh_denied_sources",
+ defaultValue = emptySet(),
+ SetParser(StringParser())
+ )
+
+ /**
+ * Flag that determines whether statsd logging is allowed.
+ *
+ * This is useful to allow testing statsd logs in some specific tests, while keeping the other
+ * tests from polluting our statsd logs.
+ */
+ private val allowStatsdLoggingFlag =
+ Flag("safety_center_allow_statsd_logging", defaultValue = false, BooleanParser())
+
+ /**
+ * The Package Manager flag used while toggling the QS tile component.
+ *
+ * This is to make sure that the SafetyCenter is not killed while toggling the QS tile component
+ * during the tests, which causes flakiness in them.
+ */
+ private val qsTileComponentSettingFlag =
+ Flag(
+ "safety_center_qs_tile_component_setting_flags",
+ defaultValue = PackageManager.DONT_KILL_APP,
+ IntParser()
+ )
+
+ /**
+ * Flag that determines whether to show subpages in the Safety Center UI instead of the
+ * expand-and-collapse list.
+ */
+ private val showSubpagesFlag =
+ Flag("safety_center_show_subpages", defaultValue = false, BooleanParser())
+
+ private val overrideRefreshOnPageOpenSourcesFlag =
+ Flag(
+ "safety_center_override_refresh_on_page_open_sources",
+ defaultValue = setOf(),
+ SetParser(StringParser())
+ )
+
+ /**
+ * Flag that enables both one-off and periodic background refreshes in
+ * [SafetyCenterBackgroundRefreshJobService].
+ */
+ private val backgroundRefreshIsEnabledFlag =
+ Flag(
+ "safety_center_background_refresh_is_enabled",
+ // do not set defaultValue to true, do not want background refreshes running
+ // during other tests
+ defaultValue = false,
+ BooleanParser()
+ )
+
+ /**
+ * Flag that determines how often periodic background refreshes are run in
+ * [SafetyCenterBackgroundRefreshJobService]. See [JobInfo.setPeriodic] for details.
+ *
+ * Note that jobs may take longer than this to be scheduled, or may possibly never run,
+ * depending on whether the other constraints on the job get satisfied.
+ */
+ private val periodicBackgroundRefreshIntervalFlag =
+ Flag(
+ "safety_center_periodic_background_interval_millis",
+ defaultValue = Duration.ofDays(1),
+ DurationParser()
+ )
+
+ /** Flag for allowlisting additional certificates for a given package. */
+ private val allowedAdditionalPackageCertsFlag =
+ Flag(
+ "safety_center_additional_allow_package_certs",
+ defaultValue = emptyMap(),
+ 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(
+ isEnabledFlag,
+ notificationsFlag,
+ notificationsAllowedSourcesFlag,
+ notificationsMinDelayFlag,
+ immediateNotificationBehaviorIssuesFlag,
+ notificationResurfaceIntervalFlag,
+ showErrorEntriesOnTimeoutFlag,
+ replaceLockScreenIconActionFlag,
+ refreshSourceTimeoutsFlag,
+ resolveActionTimeoutFlag,
+ tempHiddenIssueResurfaceDelayFlag,
+ hideResolveUiTransitionDelayFlag,
+ untrackedSourcesFlag,
+ resurfaceIssueMaxCountsFlag,
+ resurfaceIssueDelaysFlag,
+ issueCategoryAllowlistsFlag,
+ allowedAdditionalPackageCertsFlag,
+ backgroundRefreshDeniedSourcesFlag,
+ allowStatsdLoggingFlag,
+ qsTileComponentSettingFlag,
+ showSubpagesFlag,
+ overrideRefreshOnPageOpenSourcesFlag,
+ backgroundRefreshIsEnabledFlag,
+ periodicBackgroundRefreshIntervalFlag,
+ backgroundRefreshRequiresChargingFlag
+ )
+
+ /** Returns whether the device supports Safety Center. */
+ fun Context.deviceSupportsSafetyCenter() =
+ resources.getBoolean(
+ Resources.getSystem().getIdentifier("config_enableSafetyCenter", "bool", "android")
+ )
+
+ /** A property that allows getting and setting the [isEnabledFlag]. */
+ var isEnabled: Boolean by isEnabledFlag
+
+ /** A property that allows getting and setting the [notificationsFlag]. */
+ var notificationsEnabled: Boolean by notificationsFlag
+
+ /** A property that allows getting and setting the [notificationsAllowedSourcesFlag]. */
+ var notificationsAllowedSources: Set<String> by notificationsAllowedSourcesFlag
+
+ /** A property that allows getting and setting the [notificationsMinDelayFlag]. */
+ var notificationsMinDelay: Duration by notificationsMinDelayFlag
+
+ /** A property that allows getting and setting the [immediateNotificationBehaviorIssuesFlag]. */
+ var immediateNotificationBehaviorIssues: Set<String> by immediateNotificationBehaviorIssuesFlag
+
+ /** 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
+
+ /** A property that allows getting and setting the [refreshSourceTimeoutsFlag]. */
+ var refreshTimeouts: Map<Int, Duration> by refreshSourceTimeoutsFlag
+
+ /** A property that allows getting and setting the [resolveActionTimeoutFlag]. */
+ var resolveActionTimeout: Duration by resolveActionTimeoutFlag
+
+ /** A property that allows getting and setting the [tempHiddenIssueResurfaceDelayFlag]. */
+ var tempHiddenIssueResurfaceDelay: Duration by tempHiddenIssueResurfaceDelayFlag
+
+ /** A property that allows getting and setting the [hideResolveUiTransitionDelayFlag]. */
+ var hideResolvedIssueUiTransitionDelay: Duration by hideResolveUiTransitionDelayFlag
+
+ /** A property that allows getting and setting the [untrackedSourcesFlag]. */
+ var untrackedSources: Set<String> by untrackedSourcesFlag
+
+ /** A property that allows getting and setting the [resurfaceIssueMaxCountsFlag]. */
+ var resurfaceIssueMaxCounts: Map<Int, Long> by resurfaceIssueMaxCountsFlag
+
+ /** A property that allows getting and setting the [resurfaceIssueDelaysFlag]. */
+ var resurfaceIssueDelays: Map<Int, Duration> by resurfaceIssueDelaysFlag
+
+ /** A property that allows getting and setting the [issueCategoryAllowlistsFlag]. */
+ var issueCategoryAllowlists: Map<Int, Set<String>> by issueCategoryAllowlistsFlag
+
+ var allowedAdditionalPackageCerts: Map<String, Set<String>> by allowedAdditionalPackageCertsFlag
+
+ /** A property that allows getting and setting the [backgroundRefreshDeniedSourcesFlag]. */
+ var backgroundRefreshDeniedSources: Set<String> by backgroundRefreshDeniedSourcesFlag
+
+ /** A property that allows getting and setting the [allowStatsdLoggingFlag]. */
+ var allowStatsdLogging: Boolean by allowStatsdLoggingFlag
+
+ /** A property that allows getting and setting the [showSubpagesFlag]. */
+ var showSubpages: Boolean by showSubpagesFlag
+
+ /** 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.
+ *
+ * This snapshot is only taken once and cached afterwards. [setup] must be called at least once
+ * prior to modifying any flag for the snapshot to be taken with the right values.
+ */
+ @Volatile lateinit var snapshot: Properties
+
+ private val lazySnapshot: Properties by lazy {
+ callWithShellPermissionIdentity(READ_DEVICE_CONFIG) {
+ DeviceConfig.getProperties(NAMESPACE_PRIVACY, *FLAGS.map { it.name }.toTypedArray())
+ }
+ }
+
+ /**
+ * Takes a snapshot of all Safety Center flags and sets them up to their default values.
+ *
+ * This doesn't apply to [isEnabled] as it is handled separately by [SafetyCenterTestHelper]:
+ * there is a listener that listens to changes to this flag in system server, and we need to
+ * ensure we wait for it to complete when modifying this flag.
+ */
+ fun setup() {
+ snapshot = lazySnapshot
+ FLAGS.filter { it.name != isEnabledFlag.name }
+ .forEach { writeDeviceConfigProperty(it.name, it.defaultStringValue) }
+ }
+
+ /**
+ * Resets the Safety Center flags based on the existing [snapshot] captured during [setup].
+ *
+ * This doesn't apply to [isEnabled] as it is handled separately by [SafetyCenterTestHelper]:
+ * there is a listener that listens to changes to this flag in system server, and we need to
+ * ensure we wait for it to complete when modifying this flag.
+ */
+ fun reset() {
+ // Write flags one by one instead of using `DeviceConfig#setProperties` as the latter does
+ // not work when DeviceConfig sync is disabled and does not take uninitialized values into
+ // account.
+ FLAGS.filter { it.name != isEnabledFlag.name }
+ .forEach {
+ val key = it.name
+ val value = snapshot.getString(key, /* defaultValue */ null)
+ writeDeviceConfigProperty(key, value)
+ }
+ }
+
+ /** Sets the [refreshTimeouts] for all refresh reasons to the given [refreshTimeout]. */
+ fun setAllRefreshTimeoutsTo(refreshTimeout: Duration) {
+ refreshTimeouts = getAllRefreshTimeoutsMap(refreshTimeout)
+ }
+
+ /** Returns the [isEnabledFlag] value of the Safety Center flags snapshot. */
+ fun Properties.isSafetyCenterEnabled() =
+ getBoolean(isEnabledFlag.name, /* defaultValue */ false)
+
+ @TargetApi(UPSIDE_DOWN_CAKE)
+ private fun getAllRefreshTimeoutsMap(refreshTimeout: Duration): Map<Int, Duration> =
+ mapOf(
+ REFRESH_REASON_PAGE_OPEN to refreshTimeout,
+ REFRESH_REASON_RESCAN_BUTTON_CLICK to refreshTimeout,
+ REFRESH_REASON_DEVICE_REBOOT to refreshTimeout,
+ REFRESH_REASON_DEVICE_LOCALE_CHANGE to refreshTimeout,
+ REFRESH_REASON_SAFETY_CENTER_ENABLED to refreshTimeout,
+ REFRESH_REASON_OTHER to refreshTimeout,
+ REFRESH_REASON_PERIODIC to refreshTimeout
+ )
+
+ private interface Parser<T> {
+ fun parseFromString(stringValue: String): T
+
+ fun toString(value: T): String = value.toString()
+ }
+
+ private class StringParser : Parser<String> {
+ override fun parseFromString(stringValue: String) = stringValue
+ }
+
+ private class BooleanParser : Parser<Boolean> {
+ override fun parseFromString(stringValue: String) = stringValue.toBoolean()
+ }
+
+ private class IntParser : Parser<Int> {
+ override fun parseFromString(stringValue: String) = stringValue.toInt()
+ }
+
+ private class LongParser : Parser<Long> {
+ override fun parseFromString(stringValue: String) = stringValue.toLong()
+ }
+
+ private class DurationParser : Parser<Duration> {
+ override fun parseFromString(stringValue: String) = Duration.ofMillis(stringValue.toLong())
+
+ override fun toString(value: Duration) = value.toMillis().toString()
+ }
+
+ private class SetParser<T>(
+ private val elementParser: Parser<T>,
+ private val delimiter: String = ","
+ ) : Parser<Set<T>> {
+ override fun parseFromString(stringValue: String) =
+ stringValue.split(delimiter).map(elementParser::parseFromString).toSet()
+
+ override fun toString(value: Set<T>) =
+ value.joinToString(delimiter, transform = elementParser::toString)
+ }
+
+ private class MapParser<K, V>(
+ private val keyParser: Parser<K>,
+ private val valueParser: Parser<V>,
+ private val entriesDelimiter: String = ",",
+ private val pairDelimiter: String = ":"
+ ) : Parser<Map<K, V>> {
+ override fun parseFromString(stringValue: String) =
+ stringValue.split(entriesDelimiter).associate { pair ->
+ val (keyString, valueString) = pair.split(pairDelimiter)
+ keyParser.parseFromString(keyString) to valueParser.parseFromString(valueString)
+ }
+
+ override fun toString(value: Map<K, V>) =
+ value
+ .map {
+ "${keyParser.toString(it.key)}${pairDelimiter}${valueParser.toString(it.value)}"
+ }
+ .joinToString(entriesDelimiter)
+ }
+
+ private class Flag<T>(
+ val name: String,
+ private val defaultValue: T,
+ private val parser: Parser<T>
+ ) {
+ val defaultStringValue = parser.toString(defaultValue)
+
+ operator fun getValue(thisRef: Any?, property: KProperty<*>): T =
+ readDeviceConfigProperty(name)?.let(parser::parseFromString) ?: defaultValue
+
+ operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
+ writeDeviceConfigProperty(name, parser.toString(value))
+ }
+ }
+
+ private fun readDeviceConfigProperty(name: String): String? =
+ callWithShellPermissionIdentity(READ_DEVICE_CONFIG) {
+ DeviceConfig.getProperty(NAMESPACE_PRIVACY, name)
+ }
+
+ private fun writeDeviceConfigProperty(name: String, stringValue: String?) {
+ callWithShellPermissionIdentity(WRITE_DEVICE_CONFIG) {
+ val valueWasSet =
+ DeviceConfig.setProperty(
+ NAMESPACE_PRIVACY,
+ name,
+ stringValue, /* makeDefault */
+ false
+ )
+ require(valueWasSet) { "Could not set $name to: $stringValue" }
+ }
+ }
+}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt
new file mode 100644
index 000000000..de4cf7094
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt
@@ -0,0 +1,1037 @@
+/*
+ * 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.testing
+
+import android.content.Context
+import android.content.pm.PackageManager.GET_SIGNING_CERTIFICATES
+import android.content.pm.PackageManager.PackageInfoFlags
+import android.content.res.Resources
+import android.os.Build
+import android.os.Build.VERSION_CODES.TIRAMISU
+import android.safetycenter.SafetySourceData
+import android.safetycenter.config.SafetyCenterConfig
+import android.safetycenter.config.SafetySource
+import android.safetycenter.config.SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC
+import android.safetycenter.config.SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY
+import android.safetycenter.config.SafetySource.SAFETY_SOURCE_TYPE_STATIC
+import android.safetycenter.config.SafetySourcesGroup
+import androidx.annotation.RequiresApi
+import com.android.modules.utils.build.SdkLevel
+import com.android.safetycenter.testing.SettingsPackage.getSettingsPackageName
+import java.security.MessageDigest
+
+/**
+ * A class that provides [SafetyCenterConfig] objects and associated constants to facilitate setting
+ * up safety sources for testing.
+ */
+@RequiresApi(TIRAMISU)
+class SafetyCenterTestConfigs(private val context: Context) {
+ /** The certificate hash signing the current package. */
+ val packageCertHash =
+ MessageDigest.getInstance("SHA256")
+ .digest(
+ context.packageManager
+ .getPackageInfo(
+ context.packageName,
+ PackageInfoFlags.of(GET_SIGNING_CERTIFICATES.toLong())
+ )
+ .signingInfo
+ .apkContentsSigners[0]
+ .toByteArray()
+ )
+ .joinToString("") { "%02x".format(it) }
+
+ /** A simple [SafetyCenterConfig] for tests with a single source of id [SINGLE_SOURCE_ID]. */
+ val singleSourceConfig = singleSourceConfig(dynamicSafetySource(SINGLE_SOURCE_ID))
+
+ /**
+ * A simple [SafetyCenterConfig] with an invalid intent action for tests with a single source of
+ * id [SINGLE_SOURCE_ID].
+ */
+ val singleSourceInvalidIntentConfig =
+ singleSourceConfig(
+ dynamicSafetySourceBuilder(SINGLE_SOURCE_ID).setIntentAction("stub").build()
+ )
+
+ /**
+ * Same as [singleSourceConfig] but with an `intentAction` that will resolve implicitly; i.e.
+ * the source's `packageName` does not own the activity resolved by the `intentAction`.
+ */
+ val implicitIntentSingleSourceConfig =
+ singleSourceConfig(
+ dynamicSafetySourceBuilder(SINGLE_SOURCE_ID)
+ // A valid package name that is *not* CTS.
+ .setPackageName(context.packageManager.permissionControllerPackageName)
+ // Exported activity that lives in the CTS package. The PC package does
+ // implement this intent action so the activity has to resolve
+ // implicitly.
+ .setIntentAction(ACTION_TEST_ACTIVITY_EXPORTED)
+ .build()
+ )
+
+ /** A simple [SafetyCenterConfig] for tests with a source max severity level of 0. */
+ val severityZeroConfig =
+ singleSourceConfig(
+ dynamicSafetySourceBuilder(SINGLE_SOURCE_ID).setMaxSeverityLevel(0).build()
+ )
+
+ /** A simple [SafetyCenterConfig] for tests with a fake/incorrect package cert hash. */
+ val singleSourceWithFakeCert: SafetyCenterConfig
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ get() =
+ singleSourceConfig(
+ dynamicSafetySourceBuilder(SINGLE_SOURCE_ID)
+ .addPackageCertificateHash(PACKAGE_CERT_HASH_FAKE)
+ .build()
+ )
+
+ /**
+ * A simple [SafetyCenterConfig] for tests with a invalid package cert hash (not a hex-formatted
+ * byte string).
+ */
+ val singleSourceWithInvalidCert: SafetyCenterConfig
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ get() =
+ singleSourceConfig(
+ dynamicSafetySourceBuilder(SINGLE_SOURCE_ID)
+ .addPackageCertificateHash(PACKAGE_CERT_HASH_INVALID)
+ .build()
+ )
+
+ /**
+ * A simple [SafetyCenterConfig] for tests with a source that does not support refresh on page
+ * open.
+ */
+ val noPageOpenConfig =
+ singleSourceConfig(
+ dynamicSafetySourceBuilder(SINGLE_SOURCE_ID).setRefreshOnPageOpenAllowed(false).build()
+ )
+
+ /** A Simple [SafetyCenterConfig] with an issue only source. */
+ val issueOnlySourceConfig =
+ singleSourceConfig(issueOnlySafetySourceBuilder(ISSUE_ONLY_ALL_OPTIONAL_ID).build())
+
+ /** A Simple [SafetyCenterConfig] with an issue only source supporting all profiles. */
+ val issueOnlySourceAllProfileConfig =
+ singleSourceConfig(
+ issueOnlyAllProfileSafetySourceBuilder(ISSUE_ONLY_ALL_PROFILE_SOURCE_ID).build()
+ )
+
+ /**
+ * A Simple [SafetyCenterConfig] with an issue only source inside a [SafetySourcesGroup] with
+ * null title.
+ */
+ val issueOnlySourceNoGroupTitleConfig =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(SINGLE_SOURCE_GROUP_ID)
+ .setTitleResId(Resources.ID_NULL)
+ .addSafetySource(
+ issueOnlySafetySourceBuilder(ISSUE_ONLY_ALL_OPTIONAL_ID).build()
+ )
+ .build()
+ )
+ .build()
+
+ /** A dynamic source with [OTHER_PACKAGE_NAME] */
+ val dynamicOtherPackageSafetySource =
+ dynamicSafetySourceBuilder(DYNAMIC_OTHER_PACKAGE_ID)
+ .setRefreshOnPageOpenAllowed(false)
+ .setPackageName(OTHER_PACKAGE_NAME)
+ .build()
+
+ /** A [SafetyCenterConfig] with a dynamic source in a different, missing package. */
+ val singleSourceOtherPackageConfig = singleSourceConfig(dynamicOtherPackageSafetySource)
+
+ /** A simple [SafetyCenterConfig] with a source supporting all profiles. */
+ val singleSourceAllProfileConfig =
+ singleSourceConfig(
+ dynamicAllProfileSafetySourceBuilder(SINGLE_SOURCE_ALL_PROFILE_ID).build()
+ )
+
+ /** A simple [SafetyCenterConfig] for tests with multiple sources. */
+ val multipleSourcesConfig =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(MULTIPLE_SOURCES_GROUP_ID_1)
+ .addSafetySource(dynamicSafetySource(SOURCE_ID_1))
+ .addSafetySource(dynamicSafetySource(SOURCE_ID_2))
+ .build()
+ )
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(MULTIPLE_SOURCES_GROUP_ID_2)
+ .setTitleResId(android.R.string.copy)
+ .setSummaryResId(android.R.string.cancel)
+ .addSafetySource(
+ dynamicSafetySourceBuilder(SOURCE_ID_3)
+ .setTitleResId(android.R.string.copy)
+ .setSummaryResId(android.R.string.cancel)
+ .setRefreshOnPageOpenAllowed(false)
+ .build()
+ )
+ .build()
+ )
+ .build()
+
+ /** A simple [SafetyCenterConfig] with multiple sources in a single [SafetySourcesGroup]. */
+ val multipleSourcesInSingleGroupConfig =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(MULTIPLE_SOURCES_GROUP_ID_1)
+ .addSafetySource(dynamicSafetySource(SOURCE_ID_1))
+ .addSafetySource(dynamicSafetySource(SOURCE_ID_2))
+ .addSafetySource(dynamicSafetySource(SOURCE_ID_3))
+ .build()
+ )
+ .build()
+
+ /** A simple [SafetyCenterConfig] for tests with multiple sources with deduplication info. */
+ val multipleSourcesWithDeduplicationInfoConfig: SafetyCenterConfig
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ get() =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(MULTIPLE_SOURCES_GROUP_ID_1)
+ .addSafetySource(
+ issueOnlySafetySourceWithDuplicationInfo(
+ SOURCE_ID_1,
+ DEDUPLICATION_GROUP_1
+ )
+ )
+ .addSafetySource(
+ issueOnlySafetySourceWithDuplicationInfo(
+ SOURCE_ID_2,
+ DEDUPLICATION_GROUP_1
+ )
+ )
+ .addSafetySource(
+ issueOnlySafetySourceWithDuplicationInfo(
+ SOURCE_ID_3,
+ DEDUPLICATION_GROUP_2
+ )
+ )
+ .addSafetySource(
+ issueOnlySafetySourceWithDuplicationInfo(
+ SOURCE_ID_4,
+ DEDUPLICATION_GROUP_3
+ )
+ )
+ .build()
+ )
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(MULTIPLE_SOURCES_GROUP_ID_2)
+ .addSafetySource(
+ issueOnlySafetySourceWithDuplicationInfo(
+ SOURCE_ID_5,
+ DEDUPLICATION_GROUP_1
+ )
+ )
+ .addSafetySource(
+ issueOnlySafetySourceWithDuplicationInfo(
+ SOURCE_ID_6,
+ DEDUPLICATION_GROUP_3
+ )
+ )
+ .build()
+ )
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(MULTIPLE_SOURCES_GROUP_ID_3)
+ .addSafetySource(
+ issueOnlySafetySourceWithDuplicationInfo(
+ SOURCE_ID_7,
+ DEDUPLICATION_GROUP_3
+ )
+ )
+ .build()
+ )
+ .build()
+
+ /**
+ * A simple [SafetyCenterConfig] for testing the Privacy subpage. Note that this config contains
+ * the [PRIVACY_SOURCE_ID_1] source that is part of the generic category, and the [SOURCE_ID_1]
+ * that is part of the data category.
+ */
+ val privacySubpageConfig: SafetyCenterConfig
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ get() =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(ANDROID_PRIVACY_SOURCES_GROUP_ID)
+ .addSafetySource(dynamicSafetySource(PRIVACY_SOURCE_ID_1))
+ .addSafetySource(dynamicSafetySource(SOURCE_ID_1))
+ .build()
+ )
+ .build()
+
+ /**
+ * A simple [SafetyCenterConfig] without data sources for testing the Privacy subpage. Note that
+ * this config contains only [PRIVACY_SOURCE_ID_1] source that is part of the generic category.
+ * Hence it doesn't have any data category sources.
+ */
+ val privacySubpageWithoutDataSourcesConfig: SafetyCenterConfig
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ get() =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(ANDROID_PRIVACY_SOURCES_GROUP_ID)
+ .addSafetySource(dynamicSafetySource(PRIVACY_SOURCE_ID_1))
+ .build()
+ )
+ .build()
+
+ /** Source included in [dynamicSourceGroup1]. */
+ val dynamicSource1 = dynamicSafetySource(SOURCE_ID_1)
+
+ /** Source included in [dynamicSourceGroup1]. */
+ val dynamicSource2 = dynamicSafetySource(SOURCE_ID_2)
+
+ /** Source included in [dynamicSourceGroup2]. */
+ val dynamicSource3 = dynamicSafetySource(SOURCE_ID_3)
+
+ private val dynamicSource4 = dynamicSafetySource(SOURCE_ID_4)
+ private val dynamicSource5 = dynamicSafetySource(SOURCE_ID_5)
+
+ /** Source group provided by [multipleSourceGroupsConfig]. */
+ val dynamicSourceGroup1 =
+ safetySourcesGroupBuilder(MULTIPLE_SOURCES_GROUP_ID_1)
+ .addSafetySource(dynamicSource1)
+ .addSafetySource(dynamicSource2)
+ .setTitleResId(android.R.string.copy)
+ .setSummaryResId(android.R.string.cut)
+ .build()
+
+ /** Source group provided by [multipleSourceGroupsConfig]. */
+ val dynamicSourceGroup2 =
+ safetySourcesGroupBuilder(MULTIPLE_SOURCES_GROUP_ID_2)
+ .addSafetySource(dynamicSource3)
+ .setTitleResId(android.R.string.paste)
+ .setSummaryResId(android.R.string.cancel)
+ .build()
+
+ /** Source group provided by [multipleSourceGroupsConfig]. */
+ val dynamicSourceGroup3 =
+ safetySourcesGroupBuilder(MULTIPLE_SOURCES_GROUP_ID_3)
+ .addSafetySource(dynamicSource4)
+ .addSafetySource(dynamicSource5)
+ .setTitleResId(android.R.string.dialog_alert_title)
+ .setSummaryResId(android.R.string.selectAll)
+ .build()
+
+ /** A simple [SafetyCenterConfig] for tests with multiple groups of multiple sources. */
+ val multipleSourceGroupsConfig =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(dynamicSourceGroup1)
+ .addSafetySourcesGroup(dynamicSourceGroup2)
+ .addSafetySourcesGroup(dynamicSourceGroup3)
+ .build()
+
+ /**
+ * A simple [SafetyCenterConfig] for tests with multiple sources with one source having an
+ * invalid default intent.
+ */
+ val multipleSourcesConfigWithSourceWithInvalidIntent =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(MULTIPLE_SOURCES_GROUP_ID_1)
+ .addSafetySource(
+ dynamicSafetySourceBuilder(SOURCE_ID_1).setIntentAction("stub").build()
+ )
+ .addSafetySource(dynamicSafetySource(SOURCE_ID_2))
+ .build()
+ )
+ .build()
+
+ /** Source provided by [staticSourcesConfig]. */
+ val staticSource1 =
+ staticSafetySourceBuilder("test_static_source_id_1")
+ .setTitleResId(android.R.string.dialog_alert_title)
+ .setSummaryResId(android.R.string.autofill)
+ .build()
+
+ /** Source provided by [staticSourcesConfig]. */
+ val staticSource2 =
+ staticSafetySourceBuilder("test_static_source_id_2")
+ .setTitleResId(android.R.string.copyUrl)
+ .setSummaryResId(android.R.string.cut)
+ .build()
+
+ /**
+ * 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)
+ .addSafetySource(staticSource1)
+ .build()
+
+ /**
+ * Source group provided by [staticSourcesConfig] containing a single source [staticSource2].
+ */
+ val staticSourceGroup2 =
+ SafetySourcesGroup.Builder()
+ .setId("test_static_sources_group_id_2")
+ .setTitleResId(android.R.string.copy)
+ .addSafetySource(staticSource2)
+ .build()
+
+ /** A simple [SafetyCenterConfig] for tests with static sources. */
+ val staticSourcesConfig =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(staticSourceGroup1)
+ .addSafetySourcesGroup(staticSourceGroup2)
+ .build()
+
+ /**
+ * A [SafetyCenterConfig] with a single static source
+ *
+ * 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"))
+
+ /** [SafetyCenterConfig] used in tests for Your Work Policy Info source. */
+ val workPolicyInfoConfig =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(
+ SafetySourcesGroup.Builder()
+ .setId("AndroidAdvancedSources")
+ .setTitleResId(android.R.string.paste)
+ .addSafetySource(
+ SafetySource.Builder(SAFETY_SOURCE_TYPE_DYNAMIC)
+ .setId("AndroidWorkPolicyInfo")
+ .setPackageName(context.packageManager.permissionControllerPackageName)
+ .setProfile(SafetySource.PROFILE_PRIMARY)
+ .setRefreshOnPageOpenAllowed(true)
+ .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_HIDDEN)
+ .build()
+ )
+ .build()
+ )
+ .build()
+
+ /** [SafetyCenterConfig] used in tests to replicate the lock screen source. */
+ val settingsLockScreenSourceConfig =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(ANDROID_LOCK_SCREEN_SOURCES_GROUP_ID)
+ .addSafetySource(
+ dynamicSafetySourceBuilder("AndroidLockScreen")
+ .setPackageName(context.getSettingsPackageName())
+ .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
+ .build()
+ )
+ .build()
+ )
+ .build()
+
+ /** [SafetyCenterConfig] used in tests to replicate the lock screen sources group. */
+ val androidLockScreenSourcesConfig =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(ANDROID_LOCK_SCREEN_SOURCES_GROUP_ID)
+ // This is needed to have a stateful group with an empty summary
+ .setSummaryResId(Resources.ID_NULL)
+ .setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
+ .addSafetySource(
+ dynamicSafetySourceBuilder(DYNAMIC_BAREBONE_ID)
+ .setRefreshOnPageOpenAllowed(false)
+ .build()
+ )
+ .addSafetySource(
+ dynamicSafetySourceBuilder(DYNAMIC_HIDDEN_ID)
+ .setTitleResId(Resources.ID_NULL)
+ .setSummaryResId(Resources.ID_NULL)
+ .setIntentAction(null)
+ .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_HIDDEN)
+ .build()
+ )
+ .addSafetySource(
+ dynamicSafetySourceBuilder(DYNAMIC_DISABLED_ID)
+ .setIntentAction(null)
+ .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
+ .build()
+ )
+ .build()
+ )
+ .build()
+
+ /** A simple [SafetyCenterConfig] used in tests that stress the group summary logic. */
+ val summaryTestConfig =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(SUMMARY_TEST_GROUP_ID)
+ .addSafetySource(dynamicSafetySource(SOURCE_ID_1))
+ .addSafetySource(dynamicSafetySource(SOURCE_ID_2))
+ .addSafetySource(dynamicSafetySource(SOURCE_ID_3))
+ .addSafetySource(dynamicSafetySource(SOURCE_ID_4))
+ .addSafetySource(dynamicSafetySource(SOURCE_ID_5))
+ .addSafetySource(dynamicSafetySource(SOURCE_ID_6))
+ .addSafetySource(dynamicSafetySource(SOURCE_ID_7))
+ .addSafetySource(staticSafetySource(STATIC_IN_STATEFUL_ID))
+ .build()
+ )
+ .build()
+
+ /**
+ * A complex [SafetyCenterConfig] exploring different combinations of valid sources and groups.
+ */
+ val complexConfig =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(DYNAMIC_GROUP_ID)
+ .setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
+ .addSafetySource(
+ dynamicSafetySourceBuilder(DYNAMIC_BAREBONE_ID)
+ .setRefreshOnPageOpenAllowed(false)
+ .build()
+ )
+ .addSafetySource(
+ dynamicSafetySourceBuilder(DYNAMIC_ALL_OPTIONAL_ID)
+ .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
+ .setMaxSeverityLevel(SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION)
+ .setSearchTermsResId(android.R.string.ok)
+ .setLoggingAllowed(false)
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup("group")
+ addPackageCertificateHash(PACKAGE_CERT_HASH_FAKE)
+ addPackageCertificateHash(packageCertHash)
+ }
+ }
+ .build()
+ )
+ .addSafetySource(
+ dynamicSafetySourceBuilder(DYNAMIC_DISABLED_ID)
+ .setIntentAction(null)
+ .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
+ .build()
+ )
+ .addSafetySource(
+ dynamicSafetySourceBuilder(DYNAMIC_HIDDEN_ID)
+ .setTitleResId(Resources.ID_NULL)
+ .setSummaryResId(Resources.ID_NULL)
+ .setIntentAction(null)
+ .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_HIDDEN)
+ .build()
+ )
+ .addSafetySource(
+ dynamicSafetySourceBuilder(DYNAMIC_HIDDEN_WITH_SEARCH_ID)
+ .setSummaryResId(Resources.ID_NULL)
+ .setIntentAction(null)
+ .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_HIDDEN)
+ .setSearchTermsResId(android.R.string.ok)
+ .build()
+ )
+ .addSafetySource(dynamicOtherPackageSafetySource)
+ .build()
+ )
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(STATIC_GROUP_ID)
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setType(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATELESS)
+ setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
+ } else {
+ setSummaryResId(Resources.ID_NULL)
+ }
+ }
+ .addSafetySource(
+ staticSafetySourceBuilder(STATIC_BAREBONE_ID)
+ .setSummaryResId(Resources.ID_NULL)
+ .build()
+ )
+ .addSafetySource(
+ staticSafetySourceBuilder(STATIC_ALL_OPTIONAL_ID)
+ .setSearchTermsResId(android.R.string.ok)
+ .apply {
+ if (SdkLevel.isAtLeastU()) setPackageName(context.packageName)
+ }
+ .build()
+ )
+ .build()
+ )
+ .addSafetySourcesGroup(
+ SafetySourcesGroup.Builder()
+ .setId(ISSUE_ONLY_GROUP_ID)
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setType(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_HIDDEN)
+ setTitleResId(android.R.string.ok)
+ setSummaryResId(android.R.string.ok)
+ setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
+ }
+ }
+ .addSafetySource(
+ issueOnlySafetySourceBuilder(ISSUE_ONLY_BAREBONE_ID)
+ .setRefreshOnPageOpenAllowed(false)
+ .build()
+ )
+ .addSafetySource(
+ issueOnlySafetySourceBuilder(ISSUE_ONLY_ALL_OPTIONAL_ID)
+ .setMaxSeverityLevel(SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION)
+ .setLoggingAllowed(false)
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup("group")
+ addPackageCertificateHash(PACKAGE_CERT_HASH_FAKE)
+ addPackageCertificateHash(packageCertHash)
+ }
+ }
+ .build()
+ )
+ .build()
+ )
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(MIXED_STATEFUL_GROUP_ID)
+ .addSafetySource(dynamicSafetySource(DYNAMIC_IN_STATEFUL_ID))
+ .addSafetySource(staticSafetySource(STATIC_IN_STATEFUL_ID))
+ .build()
+ )
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(MIXED_STATELESS_GROUP_ID)
+ .setSummaryResId(Resources.ID_NULL)
+ .addSafetySource(dynamicSafetySource(DYNAMIC_IN_STATELESS_ID))
+ .addSafetySource(staticSafetySource(STATIC_IN_STATELESS_ID))
+ .addSafetySource(issueOnlySafetySource(ISSUE_ONLY_IN_STATELESS_ID))
+ .build()
+ )
+ .build()
+
+ /**
+ * A complex [SafetyCenterConfig] exploring different combinations of valid sources and groups.
+ * Including sources that support all profiles.
+ */
+ val complexAllProfileConfig =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(DYNAMIC_GROUP_ID)
+ .addSafetySource(
+ dynamicSafetySourceBuilder(DYNAMIC_BAREBONE_ID)
+ .setRefreshOnPageOpenAllowed(false)
+ .build()
+ )
+ .addSafetySource(
+ dynamicAllProfileSafetySourceBuilder(DYNAMIC_DISABLED_ID)
+ .setIntentAction(null)
+ .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
+ .build()
+ )
+ .addSafetySource(
+ dynamicAllProfileSafetySourceBuilder(DYNAMIC_HIDDEN_ID)
+ .setTitleResId(Resources.ID_NULL)
+ .setTitleForWorkResId(Resources.ID_NULL)
+ .setSummaryResId(Resources.ID_NULL)
+ .setIntentAction(null)
+ .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_HIDDEN)
+ .build()
+ )
+ .build()
+ )
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(STATIC_GROUP_ID)
+ .setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
+ .addSafetySource(
+ staticSafetySourceBuilder(STATIC_BAREBONE_ID)
+ .setSummaryResId(Resources.ID_NULL)
+ .build()
+ )
+ .addSafetySource(
+ staticAllProfileSafetySourceBuilder(STATIC_ALL_OPTIONAL_ID)
+ .setSearchTermsResId(android.R.string.ok)
+ .apply {
+ if (SdkLevel.isAtLeastU()) setPackageName(context.packageName)
+ }
+ .build()
+ )
+ .build()
+ )
+ .addSafetySourcesGroup(
+ SafetySourcesGroup.Builder()
+ .setId(ISSUE_ONLY_GROUP_ID)
+ .addSafetySource(
+ issueOnlySafetySourceBuilder(ISSUE_ONLY_BAREBONE_ID)
+ .setRefreshOnPageOpenAllowed(false)
+ .build()
+ )
+ .addSafetySource(
+ issueOnlyAllProfileSafetySourceBuilder(ISSUE_ONLY_ALL_OPTIONAL_ID)
+ .setMaxSeverityLevel(SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION)
+ .setLoggingAllowed(false)
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setNotificationsAllowed(true)
+ setDeduplicationGroup("group")
+ addPackageCertificateHash(PACKAGE_CERT_HASH_FAKE)
+ addPackageCertificateHash(packageCertHash)
+ }
+ }
+ .build()
+ )
+ .build()
+ )
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(MIXED_STATELESS_GROUP_ID)
+ .setSummaryResId(Resources.ID_NULL)
+ .addSafetySource(
+ dynamicAllProfileSafetySourceBuilder(DYNAMIC_IN_STATELESS_ID).build()
+ )
+ .addSafetySource(
+ staticAllProfileSafetySourceBuilder(STATIC_IN_STATELESS_ID).build()
+ )
+ .addSafetySource(
+ issueOnlyAllProfileSafetySourceBuilder(ISSUE_ONLY_IN_STATELESS_ID).build()
+ )
+ .build()
+ )
+ .build()
+
+ /** A [SafetyCenterConfig] containing only hidden sources. */
+ val hiddenOnlyConfig =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder("some_collapsible_group")
+ .addSafetySource(
+ dynamicSafetySourceBuilder("some_hidden_source")
+ .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_HIDDEN)
+ .build()
+ )
+ .build()
+ )
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder("some_rigid_group")
+ .setSummaryResId(Resources.ID_NULL)
+ .addSafetySource(
+ dynamicSafetySourceBuilder("another_hidden_source")
+ .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_HIDDEN)
+ .build()
+ )
+ .build()
+ )
+ .build()
+
+ private fun dynamicSafetySource(id: String) = dynamicSafetySourceBuilder(id).build()
+
+ fun dynamicSafetySourceBuilder(id: String) =
+ SafetySource.Builder(SAFETY_SOURCE_TYPE_DYNAMIC)
+ .setId(id)
+ .setPackageName(context.packageName)
+ .setTitleResId(android.R.string.ok)
+ .setSummaryResId(android.R.string.ok)
+ .setIntentAction(ACTION_TEST_ACTIVITY)
+ .setProfile(SafetySource.PROFILE_PRIMARY)
+ .setRefreshOnPageOpenAllowed(true)
+
+ private fun dynamicAllProfileSafetySourceBuilder(id: String) =
+ dynamicSafetySourceBuilder(id)
+ .setProfile(SafetySource.PROFILE_ALL)
+ .setTitleForWorkResId(android.R.string.paste)
+
+ private fun staticSafetySource(id: String) = staticSafetySourceBuilder(id).build()
+
+ private fun staticSafetySourceBuilder(id: String) =
+ SafetySource.Builder(SAFETY_SOURCE_TYPE_STATIC)
+ .setId(id)
+ .setTitleResId(android.R.string.ok)
+ .setSummaryResId(android.R.string.ok)
+ .setIntentAction(ACTION_TEST_ACTIVITY)
+ .setProfile(SafetySource.PROFILE_PRIMARY)
+
+ private fun staticAllProfileSafetySourceBuilder(id: String) =
+ staticSafetySourceBuilder(id)
+ .setProfile(SafetySource.PROFILE_ALL)
+ .setTitleForWorkResId(android.R.string.paste)
+
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ private fun issueOnlySafetySourceWithDuplicationInfo(id: String, deduplicationGroup: String) =
+ issueOnlySafetySourceBuilder(id).setDeduplicationGroup(deduplicationGroup).build()
+
+ private fun issueOnlySafetySource(id: String) = issueOnlySafetySourceBuilder(id).build()
+
+ private fun issueOnlySafetySourceBuilder(id: String) =
+ SafetySource.Builder(SAFETY_SOURCE_TYPE_ISSUE_ONLY)
+ .setId(id)
+ .setPackageName(context.packageName)
+ .setProfile(SafetySource.PROFILE_PRIMARY)
+ .setRefreshOnPageOpenAllowed(true)
+
+ private fun issueOnlyAllProfileSafetySourceBuilder(id: String) =
+ issueOnlySafetySourceBuilder(id).setProfile(SafetySource.PROFILE_ALL)
+
+ private fun safetySourcesGroupBuilder(id: String) =
+ SafetySourcesGroup.Builder()
+ .setId(id)
+ .setTitleResId(android.R.string.ok)
+ .setSummaryResId(android.R.string.ok)
+
+ fun singleSourceConfig(safetySource: SafetySource) =
+ SafetyCenterConfig.Builder()
+ .addSafetySourcesGroup(
+ safetySourcesGroupBuilder(SINGLE_SOURCE_GROUP_ID)
+ .addSafetySource(safetySource)
+ .build()
+ )
+ .build()
+
+ companion object {
+ /** ID of a source not used in any config. */
+ const val SAMPLE_SOURCE_ID = "test_sample_source_id"
+
+ /** Activity action: Launches the [TestActivity] used to check redirects in tests. */
+ const val ACTION_TEST_ACTIVITY = "com.android.safetycenter.testing.action.TEST_ACTIVITY"
+
+ /**
+ * Activity action: Launches the [TestActivity] used to check redirects in tests, but with
+ * an exported activity alias.
+ */
+ const val ACTION_TEST_ACTIVITY_EXPORTED =
+ "com.android.safetycenter.testing.action.TEST_ACTIVITY_EXPORTED"
+
+ /**
+ * ID of the only source provided in [singleSourceConfig], [severityZeroConfig] and
+ * [noPageOpenConfig].
+ */
+ const val SINGLE_SOURCE_ID = "test_single_source_id"
+
+ /** ID of the only source provided in [singleSourceAllProfileConfig]. */
+ const val SINGLE_SOURCE_ALL_PROFILE_ID = "test_single_source_all_profile_id"
+
+ /** ID of the only source provided in [issueOnlySourceAllProfileConfig]. */
+ const val ISSUE_ONLY_ALL_PROFILE_SOURCE_ID = "test_issue_only_all_profile_id"
+
+ /**
+ * ID of the only [SafetySourcesGroup] provided by [singleSourceConfig],
+ * [severityZeroConfig] and [noPageOpenConfig].
+ */
+ const val SINGLE_SOURCE_GROUP_ID = "test_single_source_group_id"
+
+ /**
+ * SHA256 hash of a package certificate.
+ *
+ * <p>This is a fake certificate, and can be used to test failure cases, or to test a list
+ * of certificates when only one match is required.
+ */
+ const val PACKAGE_CERT_HASH_FAKE = "feed12"
+
+ /** An invalid SHA256 hash (not a byte string, not even number of chars). */
+ const val PACKAGE_CERT_HASH_INVALID = "0124ppl"
+
+ /** ID of a source provided by [multipleSourcesConfig] and [summaryTestConfig]. */
+ const val SOURCE_ID_1 = "test_source_id_1"
+
+ /** ID of a source provided by [multipleSourcesConfig] and [summaryTestConfig]. */
+ const val SOURCE_ID_2 = "test_source_id_2"
+
+ /** ID of a source provided by [multipleSourcesConfig] and [summaryTestConfig]. */
+ const val SOURCE_ID_3 = "test_source_id_3"
+
+ /** ID of a source provided by [summaryTestConfig]. */
+ const val SOURCE_ID_4 = "test_source_id_4"
+
+ /** ID of a source provided by [summaryTestConfig]. */
+ const val SOURCE_ID_5 = "test_source_id_5"
+
+ /** ID of a source provided by [summaryTestConfig]. */
+ const val SOURCE_ID_6 = "test_source_id_6"
+
+ /** ID of a source provided by [summaryTestConfig]. */
+ const val SOURCE_ID_7 = "test_source_id_7"
+
+ /**
+ * ID of a source provided by [privacySubpageConfig] and
+ * [privacySubpageWithoutDataSourcesConfig].
+ */
+ const val PRIVACY_SOURCE_ID_1 = "AndroidPermissionUsage"
+
+ /**
+ * ID of a [SafetySourcesGroup] provided by [multipleSourcesConfig], containing two sources
+ * of ids [SOURCE_ID_1] and [SOURCE_ID_2].
+ */
+ const val MULTIPLE_SOURCES_GROUP_ID_1 = "test_multiple_sources_group_id_1"
+
+ /**
+ * ID of a [SafetySourcesGroup] provided by [multipleSourcesConfig], containing a single
+ * source of id [SOURCE_ID_3].
+ */
+ const val MULTIPLE_SOURCES_GROUP_ID_2 = "test_multiple_sources_group_id_2"
+
+ /**
+ * ID of a [SafetySourcesGroup] provided by [multipleSourcesConfig], containing two sources
+ * of ids [SOURCE_ID_4] and [SOURCE_ID_5].
+ */
+ const val MULTIPLE_SOURCES_GROUP_ID_3 = "test_multiple_sources_group_id_3"
+
+ /**
+ * ID of a [SafetySourcesGroup] provided by [summaryTestGroupConfig], containing sources:
+ * [SOURCE_ID_1], [SOURCE_ID_2], [SOURCE_ID_3], [SOURCE_ID_4], [SOURCE_ID_5], [SOURCE_ID_6],
+ * [SOURCE_ID_7], [STATIC_IN_STATEFUL_ID].
+ */
+ const val SUMMARY_TEST_GROUP_ID = "summary_test_group_id"
+
+ /**
+ * ID of a [SafetySourcesGroup] provided by [complexConfig], containing sources:
+ * [DYNAMIC_BAREBONE_ID], [DYNAMIC_ALL_OPTIONAL_ID], [DYNAMIC_DISABLED_ID],
+ * [DYNAMIC_HIDDEN_ID], [DYNAMIC_HIDDEN_WITH_SEARCH_ID], [DYNAMIC_OTHER_PACKAGE_ID]. And
+ * provided by [complexAllProfileConfig], containing sources: [DYNAMIC_BAREBONE_ID],
+ * [DYNAMIC_DISABLED_ID], [DYNAMIC_HIDDEN_ID].
+ */
+ const val DYNAMIC_GROUP_ID = "dynamic"
+
+ /**
+ * ID of a [SafetySourcesGroup] provided by [complexConfig] and [complexAllProfileConfig],
+ * containing sources: [STATIC_BAREBONE_ID], [STATIC_ALL_OPTIONAL_ID].
+ */
+ const val STATIC_GROUP_ID = "static"
+
+ /**
+ * ID of a [SafetySourcesGroup] provided by [complexConfig] and [complexAllProfileConfig],
+ * containing sources: [ISSUE_ONLY_BAREBONE_ID], [ISSUE_ONLY_ALL_OPTIONAL_ID].
+ */
+ const val ISSUE_ONLY_GROUP_ID = "issue_only"
+
+ /**
+ * ID of a [SafetySourcesGroup] provided by [complexConfig], containing sources:
+ * [DYNAMIC_IN_STATEFUL_ID], [STATIC_IN_STATEFUL_ID].
+ */
+ const val MIXED_STATEFUL_GROUP_ID = "mixed_stateful"
+
+ /**
+ * ID of a [SafetySourcesGroup] provided by [complexConfig] and [complexAllProfileConfig],
+ * containing sources: [DYNAMIC_IN_STATELESS_ID], [STATIC_IN_STATELESS_ID],
+ * [ISSUE_ONLY_IN_STATELESS_ID].
+ */
+ const val MIXED_STATELESS_GROUP_ID = "mixed_stateless"
+
+ /**
+ * ID of a source provided by [complexConfig], [complexAllProfileConfig], and
+ * [androidLockScreenSourcesConfig], this is a dynamic, primary profile only, visible source
+ * for which only the required fields are set.
+ */
+ const val DYNAMIC_BAREBONE_ID = "dynamic_barebone"
+
+ /**
+ * ID of a source provided by [complexConfig] and [singleSourceOtherPackageConfig], this is
+ * a dynamic, primary profile only, visible source belonging to the [OTHER_PACKAGE_NAME]
+ * package for which only the required fields are set.
+ */
+ const val DYNAMIC_OTHER_PACKAGE_ID = "dynamic_other_package"
+
+ /**
+ * ID of a source provided by [complexConfig], this is a dynamic, primary profile only,
+ * disabled by default source for which all the required and optional fields are set.
+ * Notably, this includes the refresh on page open flag and a max severity level of
+ * recommendation.
+ */
+ const val DYNAMIC_ALL_OPTIONAL_ID = "dynamic_all_optional"
+
+ /**
+ * ID of a source provided by [complexConfig], [complexAllProfileConfig], and
+ * [androidLockScreenSourcesConfig], this is a dynamic, disabled by default source for which
+ * only the required fields are set.
+ */
+ const val DYNAMIC_DISABLED_ID = "dynamic_disabled"
+
+ /**
+ * ID of a source provided by [complexConfig], [complexAllProfileConfig], and
+ * [androidLockScreenSourcesConfig], this ism a dynamic, hidden by default source for which
+ * only the required fields are set.
+ */
+ const val DYNAMIC_HIDDEN_ID = "dynamic_hidden"
+
+ /**
+ * ID of a source provided by [complexConfig], this is a dynamic, primary profile only,
+ * hidden by default source for which all the required and optional fields are set.
+ */
+ const val DYNAMIC_HIDDEN_WITH_SEARCH_ID = "dynamic_hidden_with_search"
+
+ /**
+ * ID of a source provided by [complexConfig] and [complexAllProfileConfig], this is a
+ * static, primary profile only source for which only the required fields are set.
+ */
+ const val STATIC_BAREBONE_ID = "static_barebone"
+
+ /**
+ * ID of a source provided by [complexConfig] and [complexAllProfileConfig], this is a
+ * static source for which all the required and optional fields are set.
+ */
+ const val STATIC_ALL_OPTIONAL_ID = "static_all_optional"
+
+ /**
+ * ID of a source provided by [complexConfig] and [complexAllProfileConfig], this is an
+ * issue-only, primary profile only source for which only the required fields are set.
+ */
+ const val ISSUE_ONLY_BAREBONE_ID = "issue_only_barebone"
+
+ /**
+ * ID of a source provided by [complexConfig] and [complexAllProfileConfig], this is an
+ * issue-only source for which all the required and optional fields are set. Notably, this
+ * includes the refresh on page open flag and a max severity level of recommendation.
+ */
+ const val ISSUE_ONLY_ALL_OPTIONAL_ID = "issue_only_all_optional"
+
+ /**
+ * ID of a source provided by [complexConfig], this is a generic, dynamic, primary profile
+ * only, visible source.
+ */
+ const val DYNAMIC_IN_STATEFUL_ID = "dynamic_in_stateful"
+
+ /**
+ * ID of a source provided by [complexConfig] and [complexAllProfileConfig], this is a
+ * generic, dynamic, visible source.
+ */
+ const val DYNAMIC_IN_STATELESS_ID = "dynamic_in_stateless"
+
+ /**
+ * ID of a source provided by [complexConfig] and [complexAllProfileConfig], this is an
+ * issue-only source.
+ */
+ const val ISSUE_ONLY_IN_STATELESS_ID = "issue_only_in_stateless"
+
+ /**
+ * ID of a source provided by [complexConfig] and [summaryTestConfig], this is a generic,
+ * static, primary profile only source.
+ */
+ const val STATIC_IN_STATEFUL_ID = "static_in_stateful"
+
+ /**
+ * ID of a source provided by [complexConfig] and [complexAllProfileConfig], this is a
+ * generic, static source.
+ */
+ const val STATIC_IN_STATELESS_ID = "static_in_stateless"
+
+ /** Package name for the [DYNAMIC_OTHER_PACKAGE_ID] source. */
+ const val OTHER_PACKAGE_NAME = "other_package_name"
+
+ private const val DEDUPLICATION_GROUP_1 = "deduplication_group_1"
+ private const val DEDUPLICATION_GROUP_2 = "deduplication_group_2"
+ private const val DEDUPLICATION_GROUP_3 = "deduplication_group_3"
+
+ /**
+ * ID of a [SafetySourcesGroup] provided by [settingsLockScreenSourceConfig] and
+ * [androidLockScreenSourcesConfig], to replicate the lock screen sources group.
+ */
+ const val ANDROID_LOCK_SCREEN_SOURCES_GROUP_ID = "AndroidLockScreenSources"
+
+ /**
+ * ID of a [SafetySourcesGroup] provided by [privacySubpageConfig] and
+ * [privacySubpageWithoutDataSourcesConfig], to replicate the privacy sources group.
+ */
+ const val ANDROID_PRIVACY_SOURCES_GROUP_ID = "AndroidPrivacySources"
+ }
+}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestData.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestData.kt
new file mode 100644
index 000000000..5ff42e23c
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestData.kt
@@ -0,0 +1,558 @@
+/*
+ * 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.testing
+
+import android.app.PendingIntent
+import android.content.Context
+import android.icu.text.MessageFormat
+import android.os.Build.VERSION_CODES.TIRAMISU
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import android.os.Bundle
+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_OK
+import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION
+import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN
+import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED
+import android.safetycenter.SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON
+import android.safetycenter.SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION
+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 android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING
+import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK
+import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN
+import android.util.ArrayMap
+import androidx.annotation.RequiresApi
+import com.android.modules.utils.build.SdkLevel
+import com.android.safetycenter.internaldata.SafetyCenterEntryId
+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.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
+import com.android.safetycenter.testing.SafetySourceTestData.Companion.INFORMATION_ISSUE_ACTION_ID
+import com.android.safetycenter.testing.SafetySourceTestData.Companion.INFORMATION_ISSUE_ID
+import com.android.safetycenter.testing.SafetySourceTestData.Companion.ISSUE_TYPE_ID
+import com.android.safetycenter.testing.SafetySourceTestData.Companion.RECOMMENDATION_ISSUE_ACTION_ID
+import com.android.safetycenter.testing.SafetySourceTestData.Companion.RECOMMENDATION_ISSUE_ID
+import java.util.Locale
+
+/**
+ * A class that provides [SafetyCenterData] objects and associated constants to facilitate asserting
+ * on specific Safety Center states in SafetyCenter for testing.
+ */
+@RequiresApi(TIRAMISU)
+class SafetyCenterTestData(context: Context) {
+
+ private val safetyCenterResourcesContext = SafetyCenterResourcesContext.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"
+ )
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ .build()
+
+ /**
+ * Returns a [SafetyCenterStatus] with one alert and the given [statusResource] and
+ * [overallSeverityLevel].
+ */
+ fun safetyCenterStatusOneAlert(
+ statusResource: String,
+ overallSeverityLevel: Int
+ ): SafetyCenterStatus = safetyCenterStatusNAlerts(statusResource, overallSeverityLevel, 1)
+
+ /**
+ * Returns a [SafetyCenterStatus] with [numAlerts] and the given [statusResource] and
+ * [overallSeverityLevel].
+ */
+ fun safetyCenterStatusNAlerts(
+ statusResource: String,
+ overallSeverityLevel: Int,
+ numAlerts: Int,
+ ): SafetyCenterStatus =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesContext.getStringByName(statusResource),
+ getAlertString(numAlerts)
+ )
+ .setSeverityLevel(overallSeverityLevel)
+ .build()
+
+ /**
+ * Returns an information [SafetyCenterStatus] that has "Tip(s) available" as a summary for the
+ * given [numTipIssues].
+ */
+ fun safetyCenterStatusTips(
+ numTipIssues: Int,
+ ): SafetyCenterStatus =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_title"),
+ safetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_tip_summary",
+ numTipIssues
+ )
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK)
+ .build()
+
+ /**
+ * Returns an information [SafetyCenterStatus] that has "Action(s) taken" as a summary for the
+ * given [numAutomaticIssues].
+ */
+ fun safetyCenterStatusActionsTaken(
+ numAutomaticIssues: Int,
+ ): SafetyCenterStatus =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_title"),
+ safetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_action_taken_summary",
+ numAutomaticIssues
+ )
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK)
+ .build()
+
+ /**
+ * Returns the [SafetyCenterStatus] used when the overall status is critical and no scan is in
+ * progress for the given number of alerts.
+ */
+ fun safetyCenterStatusCritical(numAlerts: Int) =
+ SafetyCenterStatus.Builder(
+ safetyCenterResourcesContext.getStringByName(
+ "overall_severity_level_critical_safety_warning_title"
+ ),
+ getAlertString(numAlerts)
+ )
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .build()
+
+ /**
+ * Returns a [SafetyCenterEntry] builder with a grey icon (for unknown severity), the summary
+ * generally used for sources of the [SafetyCenterTestConfigs], and a pending intent that
+ * redirects to [TestActivity] for the given source, user id, and title.
+ */
+ fun safetyCenterEntryDefaultBuilder(
+ sourceId: String,
+ userId: Int = UserHandle.myUserId(),
+ title: CharSequence = "OK",
+ pendingIntent: PendingIntent? = safetySourceTestData.testActivityRedirectPendingIntent
+ ) =
+ SafetyCenterEntry.Builder(entryId(sourceId, userId), title)
+ .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNKNOWN)
+ .setSummary("OK")
+ .setPendingIntent(pendingIntent)
+ .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
+
+ /**
+ * Returns a [SafetyCenterEntry] with a grey icon (for unknown severity), the summary generally
+ * used for sources of the [SafetyCenterTestConfigs], and a pending intent that redirects to
+ * Safety Center for the given source, user id, and title.
+ */
+ fun safetyCenterEntryDefault(
+ sourceId: String,
+ userId: Int = UserHandle.myUserId(),
+ title: CharSequence = "OK",
+ pendingIntent: PendingIntent? = safetySourceTestData.testActivityRedirectPendingIntent
+ ) = safetyCenterEntryDefaultBuilder(sourceId, userId, title, pendingIntent).build()
+
+ /**
+ * Returns a [SafetyCenterEntry] builder with no icon, the summary generally used for sources of
+ * the [SafetyCenterTestConfigs], and a pending intent that redirects to [TestActivity] for the
+ * given source, user id, and title.
+ */
+ fun safetyCenterEntryDefaultStaticBuilder(
+ sourceId: String,
+ userId: Int = UserHandle.myUserId(),
+ title: CharSequence = "OK"
+ ) =
+ SafetyCenterEntry.Builder(entryId(sourceId, userId), title)
+ .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
+ .setSummary("OK")
+ .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
+ .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON)
+
+ /**
+ * Returns a [SafetyCenterEntry] with a grey icon (for unknown severity), a refresh error
+ * summary, and a pending intent that redirects to [TestActivity] for the given source, user id,
+ * and title.
+ */
+ fun safetyCenterEntryError(sourceId: String) =
+ safetyCenterEntryDefaultBuilder(sourceId).setSummary(getRefreshErrorString(1)).build()
+
+ /**
+ * Returns a disabled [SafetyCenterEntry] with a grey icon (for unspecified severity), a
+ * standard summary, and a standard title for the given source and pending intent.
+ */
+ fun safetyCenterEntryUnspecified(
+ sourceId: String,
+ pendingIntent: PendingIntent? = safetySourceTestData.testActivityRedirectPendingIntent
+ ) =
+ SafetyCenterEntry.Builder(entryId(sourceId), "Unspecified title")
+ .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
+ .setSummary("Unspecified summary")
+ .setPendingIntent(pendingIntent)
+ .setEnabled(false)
+ .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
+ .build()
+
+ /**
+ * Returns a [SafetyCenterEntry] builder with a green icon (for ok severity), a standard
+ * summary, and a pending intent that redirects to [TestActivity] for the given source, user id,
+ * and title.
+ */
+ fun safetyCenterEntryOkBuilder(
+ sourceId: String,
+ userId: Int = UserHandle.myUserId(),
+ title: CharSequence = "Ok title"
+ ) =
+ SafetyCenterEntry.Builder(entryId(sourceId, userId), title)
+ .setSeverityLevel(ENTRY_SEVERITY_LEVEL_OK)
+ .setSummary("Ok summary")
+ .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
+ .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
+
+ /**
+ * Returns a [SafetyCenterEntry] with a green icon (for ok severity), a standard summary, and a
+ * pending intent that redirects to [TestActivity] for the given source, user id, and title.
+ */
+ fun safetyCenterEntryOk(
+ sourceId: String,
+ userId: Int = UserHandle.myUserId(),
+ title: CharSequence = "Ok title"
+ ) = safetyCenterEntryOkBuilder(sourceId, userId, title).build()
+
+ /**
+ * Returns a [SafetyCenterEntry] with a yellow icon (for recommendation severity), a standard
+ * title, and a pending intent that redirects to [TestActivity] for the given source and
+ * summary.
+ */
+ fun safetyCenterEntryRecommendation(
+ sourceId: String,
+ summary: String = "Recommendation summary"
+ ) =
+ SafetyCenterEntry.Builder(entryId(sourceId), "Recommendation title")
+ .setSeverityLevel(ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
+ .setSummary(summary)
+ .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
+ .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
+ .build()
+
+ /**
+ * Returns a [SafetyCenterEntry] with a red icon (for critical severity), a standard title, a
+ * standard summary, and a pending intent that redirects to [TestActivity] for the given source.
+ */
+ fun safetyCenterEntryCritical(sourceId: String) =
+ SafetyCenterEntry.Builder(entryId(sourceId), "Critical title")
+ .setSeverityLevel(ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .setSummary("Critical summary")
+ .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
+ .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
+ .build()
+
+ /**
+ * Returns an information [SafetyCenterIssue] for the given source and user id that is
+ * consistent with information [SafetySourceIssue]s used in [SafetySourceTestData].
+ */
+ fun safetyCenterIssueInformation(
+ sourceId: String,
+ userId: Int = UserHandle.myUserId(),
+ attributionTitle: String? = "OK",
+ groupId: String? = SINGLE_SOURCE_GROUP_ID
+ ) =
+ SafetyCenterIssue.Builder(
+ issueId(sourceId, INFORMATION_ISSUE_ID, userId = userId),
+ "Information issue title",
+ "Information issue summary"
+ )
+ .setSeverityLevel(ISSUE_SEVERITY_LEVEL_OK)
+ .setShouldConfirmDismissal(false)
+ .setActions(
+ listOf(
+ SafetyCenterIssue.Action.Builder(
+ issueActionId(
+ sourceId,
+ INFORMATION_ISSUE_ID,
+ INFORMATION_ISSUE_ACTION_ID,
+ userId
+ ),
+ "Review",
+ safetySourceTestData.testActivityRedirectPendingIntent
+ )
+ .build()
+ )
+ )
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setAttributionTitle(attributionTitle)
+ setGroupId(groupId)
+ }
+ }
+ .build()
+
+ /**
+ * Returns a recommendation [SafetyCenterIssue] for the given source and user id that is
+ * consistent with recommendation [SafetySourceIssue]s used in [SafetySourceTestData].
+ */
+ fun safetyCenterIssueRecommendation(
+ sourceId: String,
+ userId: Int = UserHandle.myUserId(),
+ attributionTitle: String? = "OK",
+ groupId: String? = SINGLE_SOURCE_GROUP_ID,
+ confirmationDialog: Boolean = false
+ ) =
+ SafetyCenterIssue.Builder(
+ issueId(sourceId, RECOMMENDATION_ISSUE_ID, userId = userId),
+ "Recommendation issue title",
+ "Recommendation issue summary"
+ )
+ .setSeverityLevel(ISSUE_SEVERITY_LEVEL_RECOMMENDATION)
+ .setActions(
+ listOf(
+ SafetyCenterIssue.Action.Builder(
+ issueActionId(
+ sourceId,
+ RECOMMENDATION_ISSUE_ID,
+ RECOMMENDATION_ISSUE_ACTION_ID,
+ userId
+ ),
+ "See issue",
+ safetySourceTestData.testActivityRedirectPendingIntent
+ )
+ .apply {
+ if (confirmationDialog && SdkLevel.isAtLeastU()) {
+ setConfirmationDialogDetails(
+ SafetyCenterIssue.Action.ConfirmationDialogDetails(
+ "Confirmation title",
+ "Confirmation text",
+ "Confirmation yes",
+ "Confirmation no"
+ )
+ )
+ }
+ }
+ .build()
+ )
+ )
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setAttributionTitle(attributionTitle)
+ setGroupId(groupId)
+ }
+ }
+ .build()
+
+ /**
+ * Returns a critical [SafetyCenterIssue] for the given source and user id that is consistent
+ * with critical [SafetySourceIssue]s used in [SafetySourceTestData].
+ */
+ fun safetyCenterIssueCritical(
+ sourceId: String,
+ isActionInFlight: Boolean = false,
+ userId: Int = UserHandle.myUserId(),
+ attributionTitle: String? = "OK",
+ groupId: String? = SINGLE_SOURCE_GROUP_ID
+ ) =
+ SafetyCenterIssue.Builder(
+ issueId(sourceId, CRITICAL_ISSUE_ID, userId = userId),
+ "Critical issue title",
+ "Critical issue summary"
+ )
+ .setSeverityLevel(ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING)
+ .setActions(
+ listOf(
+ SafetyCenterIssue.Action.Builder(
+ issueActionId(
+ sourceId,
+ CRITICAL_ISSUE_ID,
+ CRITICAL_ISSUE_ACTION_ID,
+ userId
+ ),
+ "Solve issue",
+ safetySourceTestData.criticalIssueActionPendingIntent
+ )
+ .setWillResolve(true)
+ .setIsInFlight(isActionInFlight)
+ .build()
+ )
+ )
+ .apply {
+ if (SdkLevel.isAtLeastU()) {
+ setAttributionTitle(attributionTitle)
+ setGroupId(groupId)
+ }
+ }
+ .build()
+
+ /**
+ * Returns the [overall_severity_n_alerts_summary] string formatted for the given number of
+ * alerts.
+ */
+ fun getAlertString(numberOfAlerts: Int): String =
+ getIcuPluralsString("overall_severity_n_alerts_summary", numberOfAlerts)
+
+ /** Returns the [refresh_error] string formatted for the given number of error entries. */
+ fun getRefreshErrorString(numberOfErrorEntries: Int): String =
+ getIcuPluralsString("refresh_error", numberOfErrorEntries)
+
+ private fun getIcuPluralsString(name: String, count: Int, vararg formatArgs: Any): String {
+ val messageFormat =
+ MessageFormat(
+ safetyCenterResourcesContext.getStringByName(name, formatArgs),
+ Locale.getDefault()
+ )
+ val arguments = ArrayMap<String, Any>()
+ arguments["count"] = count
+ return messageFormat.format(arguments)
+ }
+
+ companion object {
+ /** The default [SafetyCenterData] returned by the Safety Center APIs. */
+ val DEFAULT: SafetyCenterData =
+ SafetyCenterData(
+ SafetyCenterStatus.Builder("", "")
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ .build(),
+ emptyList(),
+ emptyList(),
+ emptyList()
+ )
+
+ /** Creates an ID for a Safety Center entry. */
+ fun entryId(sourceId: String, userId: Int = UserHandle.myUserId()) =
+ SafetyCenterIds.encodeToString(
+ SafetyCenterEntryId.newBuilder()
+ .setSafetySourceId(sourceId)
+ .setUserId(userId)
+ .build()
+ )
+
+ /** Creates an ID for a Safety Center issue. */
+ fun issueId(
+ sourceId: String,
+ sourceIssueId: String,
+ issueTypeId: String = ISSUE_TYPE_ID,
+ userId: Int = UserHandle.myUserId()
+ ) =
+ SafetyCenterIds.encodeToString(
+ SafetyCenterIssueId.newBuilder()
+ .setSafetyCenterIssueKey(
+ SafetyCenterIssueKey.newBuilder()
+ .setSafetySourceId(sourceId)
+ .setSafetySourceIssueId(sourceIssueId)
+ .setUserId(userId)
+ .build()
+ )
+ .setIssueTypeId(issueTypeId)
+ .build()
+ )
+
+ /** Creates an ID for a Safety Center issue action. */
+ fun issueActionId(
+ sourceId: String,
+ sourceIssueId: String,
+ sourceIssueActionId: String,
+ userId: Int = UserHandle.myUserId()
+ ) =
+ SafetyCenterIds.encodeToString(
+ SafetyCenterIssueActionId.newBuilder()
+ .setSafetyCenterIssueKey(
+ SafetyCenterIssueKey.newBuilder()
+ .setSafetySourceId(sourceId)
+ .setSafetySourceIssueId(sourceIssueId)
+ .setUserId(userId)
+ .build()
+ )
+ .setSafetySourceIssueActionId(sourceIssueActionId)
+ .build()
+ )
+
+ /**
+ * On U+, returns a new [SafetyCenterData] with the dismissed issues set. Prior to U,
+ * returns the passed in [SafetyCenterData].
+ */
+ fun SafetyCenterData.withDismissedIssuesIfAtLeastU(
+ dismissedIssues: List<SafetyCenterIssue>
+ ): SafetyCenterData =
+ if (SdkLevel.isAtLeastU()) {
+ copy(dismissedIssues = dismissedIssues)
+ } else this
+
+ /** Returns a [SafetyCenterData] without extras. */
+ fun SafetyCenterData.withoutExtras() =
+ if (SdkLevel.isAtLeastU()) {
+ SafetyCenterData.Builder(this).clearExtras().build()
+ } else this
+
+ /**
+ * On U+, returns a new [SafetyCenterData] with [SafetyCenterIssue]s having the
+ * [attributionTitle]. Prior to U, returns the passed in [SafetyCenterData].
+ */
+ fun SafetyCenterData.withAttributionTitleInIssuesIfAtLeastU(
+ attributionTitle: String?
+ ): SafetyCenterData {
+ return if (SdkLevel.isAtLeastU()) {
+ val issuesWithAttributionTitle =
+ this.issues.map {
+ SafetyCenterIssue.Builder(it).setAttributionTitle(attributionTitle).build()
+ }
+ copy(issues = issuesWithAttributionTitle)
+ } else this
+ }
+
+ /**
+ * On U+, returns a new [SafetyCenterData] with the extras set. Prior to U, returns the
+ * passed in [SafetyCenterData].
+ */
+ fun SafetyCenterData.withExtrasIfAtLeastU(extras: Bundle): SafetyCenterData =
+ if (SdkLevel.isAtLeastU()) {
+ copy(extras = extras)
+ } else this
+
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ private fun SafetyCenterData.copy(
+ issues: List<SafetyCenterIssue> = this.issues,
+ dismissedIssues: List<SafetyCenterIssue> = this.dismissedIssues,
+ extras: Bundle = this.extras
+ ): SafetyCenterData =
+ SafetyCenterData.Builder(status)
+ .apply {
+ issues.forEach(::addIssue)
+ entriesOrGroups.forEach(::addEntryOrGroup)
+ staticEntryGroups.forEach(::addStaticEntryGroup)
+ dismissedIssues.forEach(::addDismissedIssue)
+ }
+ .setExtras(extras)
+ .build()
+ }
+}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestHelper.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestHelper.kt
new file mode 100644
index 000000000..82f7326fd
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestHelper.kt
@@ -0,0 +1,191 @@
+/*
+ * 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.testing
+
+import android.Manifest.permission.READ_SAFETY_CENTER_STATUS
+import android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE
+import android.content.Context
+import android.os.Build.VERSION_CODES.TIRAMISU
+import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import android.os.UserManager
+import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetyEvent
+import android.safetycenter.SafetySourceData
+import android.safetycenter.config.SafetyCenterConfig
+import android.safetycenter.config.SafetySource.SAFETY_SOURCE_TYPE_STATIC
+import androidx.annotation.RequiresApi
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.addOnSafetyCenterDataChangedListenerWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.clearAllSafetySourceDataForTestsWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.clearSafetyCenterConfigForTestsWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.dismissSafetyCenterIssueWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.getSafetyCenterConfigWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.isSafetyCenterEnabledWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.removeOnSafetyCenterDataChangedListenerWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.setSafetyCenterConfigForTestsWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.setSafetySourceDataWithPermission
+import com.android.safetycenter.testing.SafetyCenterFlags.isSafetyCenterEnabled
+import com.android.safetycenter.testing.SafetySourceTestData.Companion.EVENT_SOURCE_STATE_CHANGED
+import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity
+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) {
+
+ private val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
+ private val userManager = context.getSystemService(UserManager::class.java)!!
+ private val listeners = mutableListOf<SafetyCenterTestListener>()
+
+ /**
+ * Sets up the state of Safety Center by enabling it on the device and setting default flag
+ * values. To be called before each test.
+ */
+ fun setup() {
+ SafetySourceReceiver.setup()
+ Coroutines.enableDebugging()
+ SafetyCenterFlags.setup()
+ setEnabled(true)
+ }
+
+ /** Resets the state of Safety Center. To be called after each test. */
+ fun reset() {
+ setEnabled(true)
+ listeners.forEach {
+ safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(it)
+ it.cancel()
+ }
+ listeners.clear()
+ safetyCenterManager.clearAllSafetySourceDataForTestsWithPermission()
+ safetyCenterManager.clearSafetyCenterConfigForTestsWithPermission()
+ resetFlags()
+ SafetySourceReceiver.reset()
+ Coroutines.resetDebugging()
+ }
+
+ /** Enables or disables SafetyCenter based on [value]. */
+ fun setEnabled(value: Boolean) {
+ val safetyCenterConfig = safetyCenterManager.getSafetyCenterConfigWithPermission()
+ if (safetyCenterConfig == null) {
+ // No broadcasts are dispatched when toggling the flag when SafetyCenter is not
+ // supported by the device. In this case, toggling this flag should end up being a no-op
+ // as Safety Center will remain disabled regardless, but we still toggle it so that this
+ // no-op behavior can be covered.
+ SafetyCenterFlags.isEnabled = value
+ return
+ }
+ val currentValue = safetyCenterManager.isSafetyCenterEnabledWithPermission()
+ if (currentValue == value) {
+ return
+ }
+ setEnabledWaitingForSafetyCenterBroadcastIdle(value, safetyCenterConfig)
+ }
+
+ /** Sets the given [SafetyCenterConfig]. */
+ fun setConfig(config: SafetyCenterConfig) {
+ require(isEnabled())
+ safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(config)
+ }
+
+ /**
+ * Adds and returns a [SafetyCenterTestListener] to SafetyCenter.
+ *
+ * @param skipInitialData whether the returned [SafetyCenterTestListener] should receive the
+ * initial SafetyCenter update
+ */
+ fun addListener(skipInitialData: Boolean = true): SafetyCenterTestListener {
+ require(isEnabled())
+ val listener = SafetyCenterTestListener()
+ safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
+ directExecutor(),
+ listener
+ )
+ if (skipInitialData) {
+ listener.receiveSafetyCenterData()
+ }
+ listeners.add(listener)
+ return listener
+ }
+
+ /** Sets the [SafetySourceData] for the given [safetySourceId]. */
+ fun setData(
+ safetySourceId: String,
+ safetySourceData: SafetySourceData?,
+ safetyEvent: SafetyEvent = EVENT_SOURCE_STATE_CHANGED
+ ) {
+ require(isEnabled())
+ safetyCenterManager.setSafetySourceDataWithPermission(
+ safetySourceId,
+ safetySourceData,
+ safetyEvent
+ )
+ }
+
+ /** Dismisses the [SafetyCenterIssue] for the given [safetyCenterIssueId]. */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ fun dismissSafetyCenterIssue(safetyCenterIssueId: String) {
+ safetyCenterManager.dismissSafetyCenterIssueWithPermission(safetyCenterIssueId)
+ }
+
+ private fun resetFlags() {
+ setEnabled(SafetyCenterFlags.snapshot.isSafetyCenterEnabled())
+ SafetyCenterFlags.reset()
+ }
+
+ private fun setEnabledWaitingForSafetyCenterBroadcastIdle(
+ value: Boolean,
+ safetyCenterConfig: SafetyCenterConfig
+ ) =
+ callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE, READ_SAFETY_CENTER_STATUS) {
+ val enabledChangedReceiver = SafetyCenterEnabledChangedReceiver(context)
+ SafetyCenterFlags.isEnabled = value
+ // Wait for all ACTION_SAFETY_CENTER_ENABLED_CHANGED broadcasts to be dispatched to
+ // avoid them leaking onto other tests.
+ if (safetyCenterConfig.containsTestSource()) {
+ SafetySourceReceiver.receiveSafetyCenterEnabledChanged()
+ // The explicit ACTION_SAFETY_CENTER_ENABLED_CHANGED broadcast is also sent to the
+ // dynamically registered receivers.
+ enabledChangedReceiver.receiveSafetyCenterEnabledChanged()
+ }
+ // Wait for the implicit ACTION_SAFETY_CENTER_ENABLED_CHANGED broadcast. This is because
+ // the test config could later be set in another test. Since broadcasts are dispatched
+ // asynchronously, a wrong sequencing could still cause failures (e.g: 1: flag switched,
+ // 2: test finishes, 3: new test starts, 4: a test config is set, 5: broadcast from 1
+ // dispatched).
+ if (userManager.isSystemUser) {
+ // The implicit broadcast is only sent to the system user.
+ enabledChangedReceiver.receiveSafetyCenterEnabledChanged()
+ }
+ enabledChangedReceiver.unregister()
+ // NOTE: We could be using ActivityManager#waitForBroadcastIdle() to achieve the same
+ // thing.
+ // However:
+ // 1. We can't solely rely on this call to wait for the
+ // ACTION_SAFETY_CENTER_ENABLED_CHANGED broadcasts to be dispatched, as the DeviceConfig
+ // listener is called on a background thread (so waitForBroadcastIdle() could
+ // immediately return prior to the listener being called)
+ // 2. waitForBroadcastIdle() sleeps 1s in a loop when the broadcast queue is not empty,
+ // which would slow down our tests significantly
+ }
+
+ private fun SafetyCenterConfig.containsTestSource(): Boolean =
+ safetySourcesGroups
+ .flatMap { it.safetySources }
+ .filter { it.type != SAFETY_SOURCE_TYPE_STATIC }
+ .any { it.packageName == context.packageName }
+
+ private fun isEnabled() = safetyCenterManager.isSafetyCenterEnabledWithPermission()
+}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestListener.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestListener.kt
new file mode 100644
index 000000000..d62214843
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestListener.kt
@@ -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 com.android.safetycenter.testing
+
+import android.os.Build.VERSION_CODES.TIRAMISU
+import android.safetycenter.SafetyCenterData
+import android.safetycenter.SafetyCenterErrorDetails
+import android.safetycenter.SafetyCenterManager.OnSafetyCenterDataChangedListener
+import androidx.annotation.RequiresApi
+import com.android.safetycenter.testing.Coroutines.TIMEOUT_LONG
+import com.android.safetycenter.testing.Coroutines.runBlockingWithTimeout
+import java.time.Duration
+import kotlinx.coroutines.channels.Channel
+
+/**
+ * An [OnSafetyCenterDataChangedListener] that facilitates receiving updates from SafetyCenter in
+ * tests.
+ */
+@RequiresApi(TIRAMISU)
+class SafetyCenterTestListener : OnSafetyCenterDataChangedListener {
+ private val dataChannel = Channel<SafetyCenterData>(Channel.UNLIMITED)
+ private val errorChannel = Channel<SafetyCenterErrorDetails>(Channel.UNLIMITED)
+
+ override fun onSafetyCenterDataChanged(data: SafetyCenterData) {
+ runBlockingWithTimeout { dataChannel.send(data) }
+ }
+
+ override fun onError(errorDetails: SafetyCenterErrorDetails) {
+ // This call to super is needed for code coverage purposes, see b/272351657 for more
+ // details. The default impl of the interface is a no-op so the call to super is a no-op.
+ super.onError(errorDetails)
+ runBlockingWithTimeout { errorChannel.send(errorDetails) }
+ }
+
+ /** Waits for a [SafetyCenterData] update from SafetyCenter within the given [timeout]. */
+ fun receiveSafetyCenterData(timeout: Duration = TIMEOUT_LONG) =
+ runBlockingWithTimeout(timeout) { dataChannel.receive() }
+
+ /**
+ * Waits for a [SafetyCenterErrorDetails] update from SafetyCenter within the given [timeout].
+ */
+ fun receiveSafetyCenterErrorDetails(timeout: Duration = TIMEOUT_LONG) =
+ runBlockingWithTimeout(timeout) { errorChannel.receive() }
+
+ /** Cancels any pending update on this [SafetyCenterTestListener]. */
+ fun cancel() {
+ dataChannel.cancel()
+ errorChannel.cancel()
+ }
+}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceIntentHandler.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceIntentHandler.kt
new file mode 100644
index 000000000..2bd662ee8
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceIntentHandler.kt
@@ -0,0 +1,318 @@
+/*
+ * 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.testing
+
+import android.content.Context
+import android.content.Intent
+import android.os.Build.VERSION_CODES.TIRAMISU
+import android.os.UserHandle
+import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetyCenterManager.ACTION_REFRESH_SAFETY_SOURCES
+import android.safetycenter.SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED
+import android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA
+import android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_GET_DATA
+import android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID
+import android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE
+import android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCE_IDS
+import android.safetycenter.SafetyEvent
+import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED
+import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED
+import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED
+import android.safetycenter.SafetySourceData
+import android.safetycenter.SafetySourceErrorDetails
+import androidx.annotation.RequiresApi
+import com.android.safetycenter.testing.SafetySourceTestData.Companion.EVENT_SOURCE_STATE_CHANGED
+import javax.annotation.concurrent.GuardedBy
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+
+/**
+ * A class that handles [Intent] sent by Safety Center and interacts with the [SafetyCenterManager]
+ * as a response.
+ *
+ * This is meant to emulate how Safety Sources will typically react to Safety Center intents.
+ */
+@RequiresApi(TIRAMISU)
+class SafetySourceIntentHandler {
+
+ private val refreshSafetySourcesChannel = Channel<String>(UNLIMITED)
+ private val safetyCenterEnabledChangedChannel = Channel<Boolean>(UNLIMITED)
+ private val resolveActionChannel = Channel<Unit>(UNLIMITED)
+ private val dismissIssueChannel = Channel<Unit>(UNLIMITED)
+ private val mutex = Mutex()
+ @GuardedBy("mutex") private val requestsToResponses = mutableMapOf<Request, Response>()
+
+ /** Handles the given [Intent] sent to a Safety Source in the given [Context]. */
+ suspend fun handle(context: Context, intent: Intent) {
+ val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
+ val userId = context.userId
+ when (val action = intent.action) {
+ ACTION_REFRESH_SAFETY_SOURCES ->
+ safetyCenterManager.processRefreshSafetySources(intent, userId)
+ ACTION_SAFETY_CENTER_ENABLED_CHANGED ->
+ safetyCenterEnabledChangedChannel.send(safetyCenterManager.isSafetyCenterEnabled)
+ ACTION_RESOLVE_ACTION -> safetyCenterManager.processResolveAction(intent, userId)
+ ACTION_DISMISS_ISSUE -> safetyCenterManager.processDismissIssue(intent, userId)
+ else -> throw IllegalArgumentException("Unexpected intent action: $action")
+ }
+ }
+
+ /**
+ * Sets the [response] to perform on the [SafetyCenterManager] on incoming [Intent]s matching
+ * the given [request].
+ */
+ suspend fun setResponse(request: Request, response: Response) {
+ mutex.withLock { requestsToResponses.put(request, response) }
+ }
+
+ /**
+ * Suspends until an [ACTION_REFRESH_SAFETY_SOURCES] [Intent] is processed, and returns the
+ * associated [EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID].
+ */
+ suspend fun receiveRefreshSafetySources(): String = refreshSafetySourcesChannel.receive()
+
+ /**
+ * Suspends until an [ACTION_SAFETY_CENTER_ENABLED_CHANGED] [Intent] is processed, and returns
+ * whether the Safety Center is now enabled.
+ */
+ suspend fun receiveSafetyCenterEnabledChanged(): Boolean =
+ safetyCenterEnabledChangedChannel.receive()
+
+ /** Suspends until an [ACTION_RESOLVE_ACTION] [Intent] is processed. */
+ suspend fun receiveResolveAction() {
+ resolveActionChannel.receive()
+ }
+
+ /** Suspends until an [ACTION_DISMISS_ISSUE] [Intent] is processed. */
+ suspend fun receiveDimissIssue() {
+ dismissIssueChannel.receive()
+ }
+
+ /** Cancels any pending update on this [SafetySourceIntentHandler]. */
+ fun cancel() {
+ refreshSafetySourcesChannel.cancel()
+ safetyCenterEnabledChangedChannel.cancel()
+ resolveActionChannel.cancel()
+ dismissIssueChannel.cancel()
+ }
+
+ private suspend fun SafetyCenterManager.processRefreshSafetySources(
+ intent: Intent,
+ userId: Int
+ ) {
+ val broadcastId = intent.getStringExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID)
+ if (broadcastId.isNullOrEmpty()) {
+ throw IllegalArgumentException("Received refresh intent with no broadcast id specified")
+ }
+
+ val sourceIds = intent.getStringArrayExtra(EXTRA_REFRESH_SAFETY_SOURCE_IDS)
+ if (sourceIds.isNullOrEmpty()) {
+ throw IllegalArgumentException("Received refresh intent with no source ids specified")
+ }
+
+ val requestType = intent.getIntExtra(EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE, -1)
+
+ for (sourceId in sourceIds) {
+ processRequest(toRefreshSafetySourcesRequest(requestType, sourceId, userId)) {
+ createRefreshEvent(
+ if (it is Response.SetData && it.overrideBroadcastId != null) {
+ it.overrideBroadcastId
+ } else {
+ broadcastId
+ }
+ )
+ }
+ }
+
+ refreshSafetySourcesChannel.send(broadcastId)
+ }
+
+ private fun toRefreshSafetySourcesRequest(requestType: Int, sourceId: String, userId: Int) =
+ when (requestType) {
+ EXTRA_REFRESH_REQUEST_TYPE_GET_DATA -> Request.Refresh(sourceId, userId)
+ EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA -> Request.Rescan(sourceId, userId)
+ else -> throw IllegalStateException("Unexpected request type: $requestType")
+ }
+
+ private fun createRefreshEvent(broadcastId: String) =
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
+ .setRefreshBroadcastId(broadcastId)
+ .build()
+
+ private suspend fun SafetyCenterManager.processResolveAction(intent: Intent, userId: Int) {
+ val sourceId = intent.getStringExtra(EXTRA_SOURCE_ID)
+ if (sourceId.isNullOrEmpty()) {
+ throw IllegalArgumentException(
+ "Received resolve action intent with no source id specified"
+ )
+ }
+
+ val sourceIssueId = intent.getStringExtra(EXTRA_SOURCE_ISSUE_ID)
+ if (sourceIssueId.isNullOrEmpty()) {
+ throw IllegalArgumentException(
+ "Received resolve action intent with no source issue id specified"
+ )
+ }
+
+ val sourceIssueActionId = intent.getStringExtra(EXTRA_SOURCE_ISSUE_ACTION_ID)
+ if (sourceIssueActionId.isNullOrEmpty()) {
+ throw IllegalArgumentException(
+ "Received resolve action intent with no source issue action id specified"
+ )
+ }
+
+ processRequest(Request.ResolveAction(sourceId, userId)) {
+ if (it is Response.Error) {
+ createResolveActionErrorEvent(sourceIssueId, sourceIssueActionId)
+ } else {
+ createResolveActionSuccessEvent(sourceIssueId, sourceIssueActionId)
+ }
+ }
+
+ resolveActionChannel.send(Unit)
+ }
+
+ private fun createResolveActionSuccessEvent(
+ sourceIssueId: String,
+ sourceIssueActionId: String
+ ) =
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED)
+ .setSafetySourceIssueId(sourceIssueId)
+ .setSafetySourceIssueActionId(sourceIssueActionId)
+ .build()
+
+ private fun createResolveActionErrorEvent(sourceIssueId: String, sourceIssueActionId: String) =
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
+ .setSafetySourceIssueId(sourceIssueId)
+ .setSafetySourceIssueActionId(sourceIssueActionId)
+ .build()
+
+ private suspend fun SafetyCenterManager.processDismissIssue(intent: Intent, userId: Int) {
+ val sourceId = intent.getStringExtra(EXTRA_SOURCE_ID)
+ if (sourceId.isNullOrEmpty()) {
+ throw IllegalArgumentException(
+ "Received dismiss issue intent with no source id specified"
+ )
+ }
+
+ processRequest(Request.DismissIssue(sourceId, userId)) { EVENT_SOURCE_STATE_CHANGED }
+
+ dismissIssueChannel.send(Unit)
+ }
+
+ private suspend fun SafetyCenterManager.processRequest(
+ request: Request,
+ safetyEventForResponse: (Response) -> SafetyEvent
+ ) {
+ val response = mutex.withLock { requestsToResponses[request] } ?: return
+ val safetyEvent = safetyEventForResponse(response)
+ when (response) {
+ is Response.Error ->
+ reportSafetySourceError(request.sourceId, SafetySourceErrorDetails(safetyEvent))
+ is Response.ClearData -> setSafetySourceData(request.sourceId, null, safetyEvent)
+ is Response.SetData ->
+ setSafetySourceData(request.sourceId, response.safetySourceData, safetyEvent)
+ }
+ }
+
+ /** An interface that matches an [Intent] request (or a subset of it). */
+ sealed interface Request {
+ /** The safety source id this request applies to. */
+ val sourceId: String
+
+ /** The user id this request applies to. */
+ val userId: Int
+
+ /** Creates a refresh [Request] based on the given [sourceId] and [userId]. */
+ data class Refresh(
+ override val sourceId: String,
+ override val userId: Int = UserHandle.myUserId()
+ ) : Request
+
+ /** Creates a rescan [Request] based on the given [sourceId] and [userId]. */
+ data class Rescan(
+ override val sourceId: String,
+ override val userId: Int = UserHandle.myUserId()
+ ) : Request
+
+ /** Creates a resolve action [Request] based on the given [sourceId] and [userId]. */
+ data class ResolveAction(
+ override val sourceId: String,
+ override val userId: Int = UserHandle.myUserId()
+ ) : Request
+
+ /** Creates an issue dismissal [Request] based on the given [sourceId] and [userId]. */
+ data class DismissIssue(
+ override val sourceId: String,
+ override val userId: Int = UserHandle.myUserId()
+ ) : Request
+ }
+
+ /**
+ * An interface that specifies the appropriate action to take on the [SafetyCenterManager] as a
+ * response to an incoming [Request].
+ */
+ sealed interface Response {
+
+ /** Creates an error [Response]. */
+ object Error : Response
+
+ /** Creates a [Response] to clear the data. */
+ object ClearData : Response
+
+ /**
+ * Creates a [Response] to set the given [SafetySourceData].
+ *
+ * @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
+ */
+ data class SetData(
+ val safetySourceData: SafetySourceData,
+ val overrideBroadcastId: String? = null
+ ) : Response
+ }
+
+ companion object {
+ /** An intent action to handle a resolving action. */
+ const val ACTION_RESOLVE_ACTION = "com.android.safetycenter.testing.action.RESOLVE_ACTION"
+
+ /** An intent action to handle an issue dismissed by Safety Center. */
+ const val ACTION_DISMISS_ISSUE = "com.android.safetycenter.testing.action.DISMISS_ISSUE"
+
+ /**
+ * An extra to be used with [ACTION_RESOLVE_ACTION] or [ACTION_DISMISS_ISSUE] to specify the
+ * target safety source id.
+ */
+ const val EXTRA_SOURCE_ID = "com.android.safetycenter.testing.extra.SOURCE_ID"
+
+ /**
+ * An extra to be used with [ACTION_RESOLVE_ACTION] to specify the target safety source
+ * issue id of the resolving action.
+ */
+ const val EXTRA_SOURCE_ISSUE_ID = "com.android.safetycenter.testing.extra.SOURCE_ISSUE_ID"
+
+ /**
+ * An extra to be used with [ACTION_RESOLVE_ACTION] to specify the target safety source
+ * issue action id of the resolving action.
+ */
+ const val EXTRA_SOURCE_ISSUE_ACTION_ID =
+ "com.android.safetycenter.testing.extra.SOURCE_ISSUE_ACTION_ID"
+ }
+}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceReceiver.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceReceiver.kt
new file mode 100644
index 000000000..2ba87040a
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceReceiver.kt
@@ -0,0 +1,255 @@
+/*
+ * 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.testing
+
+import android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.NotificationManager.IMPORTANCE_DEFAULT
+import android.app.Service
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+import android.os.Build.VERSION_CODES.TIRAMISU
+import android.os.IBinder
+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.runBlockingWithTimeout
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.dismissSafetyCenterIssueWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.executeSafetyCenterIssueActionWithPermission
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.refreshSafetySourcesWithPermission
+import com.android.safetycenter.testing.SafetySourceIntentHandler.Request
+import com.android.safetycenter.testing.SafetySourceIntentHandler.Response
+import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity
+import java.time.Duration
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+
+/** Broadcast receiver used for testing broadcasts sent to safety sources. */
+@RequiresApi(TIRAMISU)
+class SafetySourceReceiver : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent?) {
+ if (intent == null) {
+ throw IllegalArgumentException("Received null intent")
+ }
+
+ if (runInForegroundService) {
+ context.startForegroundService(intent.setClass(context, ForegroundService::class.java))
+ } else {
+ runBlockingWithTimeout { safetySourceIntentHandler.handle(context, intent) }
+ }
+ }
+
+ /**
+ * A foreground [Service] that handles incoming intents in the same way as
+ * [SafetySourceReceiver].
+ *
+ * This is used to verify that [SafetySourceReceiver] can start foreground services. Broadcast
+ * receivers are typically not allowed to do that, but Safety Center uses special broadcast
+ * options that allow safety source receivers to process lengthy operations in foreground
+ * services instead.
+ */
+ class ForegroundService : Service() {
+ private val serviceJob = Job()
+ private val serviceScope = CoroutineScope(Dispatchers.Default + serviceJob)
+
+ override fun onBind(intent: Intent?): IBinder? = null
+
+ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+ val notificationManager = getSystemService(NotificationManager::class.java)!!
+ notificationManager.createNotificationChannel(
+ NotificationChannel(
+ NOTIFICATION_CHANNEL_ID,
+ NOTIFICATION_CHANNEL_ID,
+ IMPORTANCE_DEFAULT
+ )
+ )
+ startForeground(
+ NOTIFICATION_ID,
+ Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
+ .setContentTitle("SafetySourceReceiver")
+ .setContentText(
+ "SafetySourceReceiver is processing an incoming intent in its " +
+ "ForegroundService"
+ )
+ .setSmallIcon(android.R.drawable.ic_info)
+ .build()
+ )
+ serviceScope.launch {
+ try {
+ safetySourceIntentHandler.handle(this@ForegroundService, intent!!)
+ } finally {
+ stopForeground(STOP_FOREGROUND_REMOVE)
+ }
+ }
+ super.onStartCommand(intent, flags, startId)
+ return START_NOT_STICKY
+ }
+
+ override fun onDestroy() {
+ serviceJob.cancel()
+ super.onDestroy()
+ }
+
+ companion object {
+ private const val NOTIFICATION_ID: Int = 1204
+ private const val NOTIFICATION_CHANNEL_ID: String = "NOTIFICATION_CHANNEL_ID"
+ }
+ }
+
+ companion object {
+ @Volatile private var safetySourceIntentHandler = SafetySourceIntentHandler()
+
+ /** Whether this receiver should handle incoming intents in a foreground service instead. */
+ @Volatile var runInForegroundService = false
+
+ /** Enables the [SafetySourceReceiver] for the user running the test. */
+ fun setup() {
+ setComponentEnabledState(true)
+ }
+
+ /** Resets the state of the [SafetySourceReceiver] between tests. */
+ fun reset() {
+ setComponentEnabledState(false)
+ safetySourceIntentHandler.cancel()
+ safetySourceIntentHandler = SafetySourceIntentHandler()
+ runInForegroundService = false
+ }
+
+ private fun setComponentEnabledState(enabled: Boolean) {
+ val componentName =
+ ComponentName(getApplicationContext(), SafetySourceReceiver::class.java)
+ getApplicationContext()
+ .packageManager
+ .setComponentEnabledSetting(
+ componentName,
+ if (enabled) COMPONENT_ENABLED_STATE_ENABLED
+ else COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP
+ )
+ }
+
+ /**
+ * Sets the given [SafetySourceIntentHandler] [response] for the given [request] on this
+ * receiver.
+ */
+ fun setResponse(request: Request, response: Response) {
+ runBlockingWithTimeout { safetySourceIntentHandler.setResponse(request, response) }
+ }
+
+ fun SafetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ refreshReason: Int,
+ timeout: Duration = TIMEOUT_LONG,
+ safetySourceIds: List<String>? = null
+ ) =
+ callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) {
+ refreshSafetySourcesWithoutReceiverPermissionAndWait(
+ refreshReason,
+ timeout,
+ safetySourceIds
+ )
+ }
+
+ fun SafetyCenterManager.refreshSafetySourcesWithoutReceiverPermissionAndWait(
+ refreshReason: Int,
+ timeout: Duration,
+ safetySourceIds: List<String>? = null
+ ): String {
+ refreshSafetySourcesWithPermission(refreshReason, safetySourceIds)
+ if (timeout < TIMEOUT_LONG) {
+ SystemUtil.waitForBroadcasts()
+ }
+ return receiveRefreshSafetySources(timeout)
+ }
+
+ fun setSafetyCenterEnabledWithReceiverPermissionAndWait(
+ value: Boolean,
+ timeout: Duration = TIMEOUT_LONG
+ ) =
+ callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) {
+ setSafetyCenterEnabledWithoutReceiverPermissionAndWait(value, timeout)
+ }
+
+ fun setSafetyCenterEnabledWithoutReceiverPermissionAndWait(
+ value: Boolean,
+ timeout: Duration = TIMEOUT_LONG
+ ): Boolean {
+ SafetyCenterFlags.isEnabled = value
+ if (timeout < TIMEOUT_LONG) {
+ SystemUtil.waitForBroadcasts()
+ }
+ return receiveSafetyCenterEnabledChanged(timeout)
+ }
+
+ fun SafetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait(
+ issueId: String,
+ issueActionId: String,
+ timeout: Duration = TIMEOUT_LONG
+ ) {
+ callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) {
+ executeSafetyCenterIssueActionWithPermission(issueId, issueActionId)
+ receiveResolveAction(timeout)
+ }
+ }
+
+ fun SafetyCenterManager.dismissSafetyCenterIssueWithPermissionAndWait(
+ issueId: String,
+ timeout: Duration = TIMEOUT_LONG
+ ) {
+ callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) {
+ dismissSafetyCenterIssueWithPermission(issueId)
+ receiveDismissIssue(timeout)
+ }
+ }
+
+ private fun receiveRefreshSafetySources(timeout: Duration = TIMEOUT_LONG): String =
+ runBlockingWithTimeout(timeout) {
+ safetySourceIntentHandler.receiveRefreshSafetySources()
+ }
+
+ /**
+ * Waits for an [ACTION_SAFETY_CENTER_ENABLED_CHANGED] to be received by this receiver
+ * within the given [timeout].
+ */
+ fun receiveSafetyCenterEnabledChanged(timeout: Duration = TIMEOUT_LONG): Boolean =
+ runBlockingWithTimeout(timeout) {
+ safetySourceIntentHandler.receiveSafetyCenterEnabledChanged()
+ }
+
+ /** Waits for this receiver to resolve an action within the given [timeout]. */
+ fun receiveResolveAction(timeout: Duration = TIMEOUT_LONG) {
+ runBlockingWithTimeout(timeout) { safetySourceIntentHandler.receiveResolveAction() }
+ }
+
+ private fun receiveDismissIssue(timeout: Duration = TIMEOUT_LONG) {
+ runBlockingWithTimeout(timeout) { safetySourceIntentHandler.receiveDimissIssue() }
+ }
+
+ private fun getApplicationContext(): Context = ApplicationProvider.getApplicationContext()
+ }
+}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceTestData.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceTestData.kt
new file mode 100644
index 000000000..97e2078e0
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceTestData.kt
@@ -0,0 +1,838 @@
+/*
+ * 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.testing
+
+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
+import android.safetycenter.SafetySourceData
+import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING
+import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_INFORMATION
+import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION
+import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED
+import android.safetycenter.SafetySourceIssue
+import android.safetycenter.SafetySourceIssue.Action
+import android.safetycenter.SafetySourceIssue.Action.ConfirmationDialogDetails
+import android.safetycenter.SafetySourceStatus
+import android.safetycenter.SafetySourceStatus.IconAction
+import android.safetycenter.SafetySourceStatus.IconAction.ICON_TYPE_GEAR
+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.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
+
+/**
+ * A class that provides [SafetySourceData] objects and associated constants to facilitate setting
+ * up specific states in SafetyCenter for testing.
+ */
+@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].
+ */
+ fun testActivityRedirectPendingIntent(identifier: String? = null) =
+ createRedirectPendingIntent(context, Intent(ACTION_TEST_ACTIVITY).setIdentifier(identifier))
+
+ /** A [SafetySourceData] with a [SEVERITY_LEVEL_UNSPECIFIED] [SafetySourceStatus]. */
+ val unspecified =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder(
+ "Unspecified title",
+ "Unspecified summary",
+ SEVERITY_LEVEL_UNSPECIFIED
+ )
+ .setEnabled(false)
+ .build()
+ )
+ .build()
+
+ /**
+ * A disabled [SafetySourceData] with a [SEVERITY_LEVEL_UNSPECIFIED] [SafetySourceStatus], and a
+ * [PendingIntent] that redirects to [TestActivity].
+ */
+ val unspecifiedDisabledWithTestActivityRedirect =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder(
+ "Clickable disabled title",
+ "Clickable disabled summary",
+ SEVERITY_LEVEL_UNSPECIFIED
+ )
+ .setEnabled(false)
+ .setPendingIntent(testActivityRedirectPendingIntent)
+ .build()
+ )
+ .build()
+
+ /** A [SafetySourceIssue] with a [SEVERITY_LEVEL_INFORMATION] and a redirecting [Action]. */
+ val informationIssue = defaultInformationIssueBuilder().build()
+
+ /**
+ * A [SafetySourceIssue.Builder] with a [SEVERITY_LEVEL_INFORMATION] and a redirecting [Action].
+ */
+ fun defaultInformationIssueBuilder(
+ id: String = INFORMATION_ISSUE_ID,
+ title: String = "Information issue title",
+ 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()
+ )
+
+ /**
+ * A [SafetySourceIssue] with a [SEVERITY_LEVEL_INFORMATION] and a redirecting [Action]. With
+ * subtitle provided.
+ */
+ val informationIssueWithSubtitle =
+ SafetySourceIssue.Builder(
+ INFORMATION_ISSUE_ID,
+ "Information issue title",
+ "Information issue summary",
+ SEVERITY_LEVEL_INFORMATION,
+ ISSUE_TYPE_ID
+ )
+ .setSubtitle("Information issue subtitle")
+ .addAction(
+ Action.Builder(
+ INFORMATION_ISSUE_ACTION_ID,
+ "Review",
+ testActivityRedirectPendingIntent
+ )
+ .build()
+ )
+ .build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_INFORMATION] redirecting [SafetySourceIssue] and
+ * a [SEVERITY_LEVEL_UNSPECIFIED] [SafetySourceStatus].
+ */
+ val unspecifiedWithIssue =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder(
+ "Unspecified title",
+ "Unspecified summary",
+ SEVERITY_LEVEL_UNSPECIFIED
+ )
+ .setPendingIntent(testActivityRedirectPendingIntent)
+ .build()
+ )
+ .addIssue(informationIssue)
+ .build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_INFORMATION] redirecting [SafetySourceIssue] and
+ * a [SEVERITY_LEVEL_UNSPECIFIED] [SafetySourceStatus], to be used for a managed profile entry.
+ */
+ val unspecifiedWithIssueForWork =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder(
+ "Unspecified title for Work",
+ "Unspecified summary",
+ SEVERITY_LEVEL_UNSPECIFIED
+ )
+ .setPendingIntent(testActivityRedirectPendingIntent)
+ .build()
+ )
+ .addIssue(informationIssue)
+ .build()
+
+ /** A [SafetySourceData] with a [SEVERITY_LEVEL_INFORMATION] [SafetySourceStatus]. */
+ val information =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder("Ok title", "Ok summary", SEVERITY_LEVEL_INFORMATION)
+ .setPendingIntent(testActivityRedirectPendingIntent)
+ .build()
+ )
+ .build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_INFORMATION] [SafetySourceStatus] and null
+ * pending intent.
+ */
+ val informationWithNullIntent =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder("Ok title", "Ok summary", SEVERITY_LEVEL_INFORMATION)
+ .setPendingIntent(null)
+ .build()
+ )
+ .build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_INFORMATION] [SafetySourceStatus] and an
+ * [IconAction] defined.
+ */
+ val informationWithIconAction =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder("Ok title", "Ok summary", SEVERITY_LEVEL_INFORMATION)
+ .setPendingIntent(testActivityRedirectPendingIntent)
+ .setIconAction(IconAction(ICON_TYPE_INFO, testActivityRedirectPendingIntent))
+ .build()
+ )
+ .build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_INFORMATION] [SafetySourceStatus] and an
+ * [IconAction] having a [ICON_TYPE_GEAR].
+ */
+ val informationWithGearIconAction =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder("Ok title", "Ok summary", SEVERITY_LEVEL_INFORMATION)
+ .setPendingIntent(testActivityRedirectPendingIntent)
+ .setIconAction(IconAction(ICON_TYPE_GEAR, testActivityRedirectPendingIntent))
+ .build()
+ )
+ .build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_INFORMATION] redirecting [SafetySourceIssue] and
+ * [SafetySourceStatus].
+ */
+ val informationWithIssue =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder("Ok title", "Ok summary", SEVERITY_LEVEL_INFORMATION)
+ .setPendingIntent(testActivityRedirectPendingIntent)
+ .build()
+ )
+ .addIssue(informationIssue)
+ .build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_INFORMATION] redirecting a [SafetySourceIssue]
+ * having a [SafetySourceIssue.attributionTitle] and [SafetySourceStatus].
+ */
+ val informationWithIssueWithAttributionTitle: SafetySourceData
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ get() =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder("Ok title", "Ok summary", SEVERITY_LEVEL_INFORMATION)
+ .setPendingIntent(testActivityRedirectPendingIntent)
+ .build()
+ )
+ .addIssue(
+ defaultInformationIssueBuilder()
+ .setAttributionTitle("Attribution Title")
+ .build()
+ )
+ .build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_INFORMATION] redirecting [SafetySourceIssue] and
+ * [SafetySourceStatus], to be used for a managed profile entry.
+ */
+ val informationWithIssueForWork =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder(
+ "Ok title for Work",
+ "Ok summary",
+ SEVERITY_LEVEL_INFORMATION
+ )
+ .setPendingIntent(testActivityRedirectPendingIntent)
+ .build()
+ )
+ .addIssue(informationIssue)
+ .build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_INFORMATION] redirecting [SafetySourceIssue] and
+ * [SafetySourceStatus].
+ */
+ val informationWithSubtitleIssue =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder("Ok title", "Ok summary", SEVERITY_LEVEL_INFORMATION)
+ .setPendingIntent(testActivityRedirectPendingIntent)
+ .build()
+ )
+ .addIssue(informationIssueWithSubtitle)
+ .build()
+
+ /**
+ * A [SafetySourceIssue.Builder] with a [SEVERITY_LEVEL_RECOMMENDATION] and a redirecting
+ * [Action].
+ */
+ fun defaultRecommendationIssueBuilder(
+ title: String = "Recommendation issue title",
+ summary: String = "Recommendation issue summary",
+ confirmationDialog: Boolean = false
+ ) =
+ SafetySourceIssue.Builder(
+ RECOMMENDATION_ISSUE_ID,
+ title,
+ summary,
+ SEVERITY_LEVEL_RECOMMENDATION,
+ ISSUE_TYPE_ID
+ )
+ .addAction(
+ Action.Builder(
+ RECOMMENDATION_ISSUE_ACTION_ID,
+ "See issue",
+ testActivityRedirectPendingIntent
+ )
+ .apply {
+ if (confirmationDialog && SdkLevel.isAtLeastU()) {
+ setConfirmationDialogDetails(CONFIRMATION_DETAILS)
+ }
+ }
+ .build()
+ )
+
+ /**
+ * A [SafetySourceIssue] with a [SEVERITY_LEVEL_RECOMMENDATION], general category and a
+ * redirecting [Action].
+ */
+ val recommendationGeneralIssue = defaultRecommendationIssueBuilder().build()
+
+ /**
+ * A [SafetySourceIssue] with a [SEVERITY_LEVEL_RECOMMENDATION], general category, redirecting
+ * [Action] and with deduplication id.
+ */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ fun recommendationIssueWithDeduplicationId(deduplicationId: String) =
+ defaultRecommendationIssueBuilder().setDeduplicationId(deduplicationId).build()
+
+ val recommendationIssueWithActionConfirmation: SafetySourceIssue
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ get() = defaultRecommendationIssueBuilder(confirmationDialog = true).build()
+
+ /**
+ * A [SafetySourceIssue] with a [SEVERITY_LEVEL_RECOMMENDATION], account category and a
+ * redirecting [Action].
+ */
+ val recommendationAccountIssue =
+ defaultRecommendationIssueBuilder()
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_ACCOUNT)
+ .build()
+
+ /**
+ * A [SafetySourceIssue] with a [SEVERITY_LEVEL_RECOMMENDATION], device category and a
+ * redirecting [Action].
+ */
+ val recommendationDeviceIssue =
+ defaultRecommendationIssueBuilder()
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
+ .build()
+
+ private val dismissIssuePendingIntent =
+ broadcastPendingIntent(
+ Intent(ACTION_DISMISS_ISSUE).putExtra(EXTRA_SOURCE_ID, SINGLE_SOURCE_ID)
+ )
+
+ /**
+ * A [SafetySourceIssue] with a [SEVERITY_LEVEL_RECOMMENDATION] and a dismiss [PendingIntent].
+ */
+ val recommendationIssueWithDismissPendingIntent =
+ defaultRecommendationIssueBuilder()
+ .setOnDismissPendingIntent(dismissIssuePendingIntent)
+ .build()
+
+ /** A [SafetySourceData.Builder] with a [SEVERITY_LEVEL_RECOMMENDATION] status. */
+ fun defaultRecommendationDataBuilder() =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder(
+ "Recommendation title",
+ "Recommendation summary",
+ SEVERITY_LEVEL_RECOMMENDATION
+ )
+ .setPendingIntent(testActivityRedirectPendingIntent)
+ .build()
+ )
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_RECOMMENDATION] redirecting [SafetySourceIssue]
+ * and [SafetySourceStatus], only containing a general issue.
+ */
+ val recommendationWithGeneralIssue =
+ defaultRecommendationDataBuilder().addIssue(recommendationGeneralIssue).build()
+
+ val recommendationWithIssueWithActionConfirmation: SafetySourceData
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ get() =
+ defaultRecommendationDataBuilder()
+ .addIssue(recommendationIssueWithActionConfirmation)
+ .build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_RECOMMENDATION] redirecting [SafetySourceIssue]
+ * and [SafetySourceStatus], only containing an account issue.
+ */
+ val recommendationWithAccountIssue =
+ defaultRecommendationDataBuilder().addIssue(recommendationAccountIssue).build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_RECOMMENDATION] redirecting [SafetySourceIssue]
+ * and [SafetySourceStatus], only containing a device issue.
+ */
+ val recommendationWithDeviceIssue =
+ defaultRecommendationDataBuilder().addIssue(recommendationDeviceIssue).build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_RECOMMENDATION] [SafetySourceIssue] that has a
+ * dismiss [PendingIntent], and [SafetySourceStatus].
+ */
+ val recommendationDismissPendingIntentIssue =
+ defaultRecommendationDataBuilder()
+ .addIssue(recommendationIssueWithDismissPendingIntent)
+ .build()
+
+ /** A [PendingIntent] used by the resolving [Action] in [criticalResolvingGeneralIssue]. */
+ val criticalIssueActionPendingIntent =
+ 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)
+ )
+
+ /** A resolving Critical [Action] */
+ val criticalResolvingAction =
+ Action.Builder(CRITICAL_ISSUE_ACTION_ID, "Solve issue", criticalIssueActionPendingIntent)
+ .setWillResolve(true)
+ .build()
+
+ /** A resolving Critical [Action] with confirmation */
+ val criticalResolvingActionWithConfirmation: SafetySourceIssue.Action
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ get() =
+ Action.Builder(
+ CRITICAL_ISSUE_ACTION_ID,
+ "Solve issue",
+ criticalIssueActionPendingIntent
+ )
+ .setWillResolve(true)
+ .setConfirmationDialogDetails(CONFIRMATION_DETAILS)
+ .build()
+
+ /** An action that redirects to [TestActivity] */
+ val testActivityRedirectAction =
+ Action.Builder(CRITICAL_ISSUE_ACTION_ID, "Redirect", testActivityRedirectPendingIntent)
+ .build()
+
+ /** A resolving Critical [Action] that declares a success message */
+ val criticalResolvingActionWithSuccessMessage =
+ Action.Builder(CRITICAL_ISSUE_ACTION_ID, "Solve issue", criticalIssueActionPendingIntent)
+ .setWillResolve(true)
+ .setSuccessMessage("Issue solved")
+ .build()
+
+ /** A [SafetySourceIssue] with a [SEVERITY_LEVEL_CRITICAL_WARNING] and a resolving [Action]. */
+ val criticalResolvingIssueWithSuccessMessage =
+ SafetySourceIssue.Builder(
+ CRITICAL_ISSUE_ID,
+ "Critical issue title",
+ "Critical issue summary",
+ SEVERITY_LEVEL_CRITICAL_WARNING,
+ ISSUE_TYPE_ID
+ )
+ .addAction(criticalResolvingActionWithSuccessMessage)
+ .build()
+
+ /**
+ * Another [SafetySourceIssue] with a [SEVERITY_LEVEL_CRITICAL_WARNING] and a redirecting
+ * [Action].
+ */
+ val criticalRedirectingIssue =
+ SafetySourceIssue.Builder(
+ CRITICAL_ISSUE_ID,
+ "Critical issue title 2",
+ "Critical issue summary 2",
+ SEVERITY_LEVEL_CRITICAL_WARNING,
+ ISSUE_TYPE_ID
+ )
+ .addAction(
+ Action.Builder(
+ CRITICAL_ISSUE_ACTION_ID,
+ "Go solve issue",
+ testActivityRedirectPendingIntent
+ )
+ .build()
+ )
+ .build()
+
+ /**
+ * Another [SafetySourceIssue] with a [SEVERITY_LEVEL_CRITICAL_WARNING] an [Action] that
+ * redirects to [TestActivity].
+ */
+ private val criticalIssueWithTestActivityRedirectAction =
+ defaultCriticalResolvingIssueBuilder()
+ .clearActions()
+ .addAction(testActivityRedirectAction)
+ .build()
+
+ val criticalResolvingIssueWithConfirmation: SafetySourceIssue
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ get() =
+ defaultCriticalResolvingIssueBuilder()
+ .clearActions()
+ .addAction(criticalResolvingActionWithConfirmation)
+ .build()
+
+ /**
+ * [SafetySourceIssue.Builder] with a [SEVERITY_LEVEL_CRITICAL_WARNING] and a resolving [Action]
+ * .
+ */
+ fun defaultCriticalResolvingIssueBuilder(issueId: String = CRITICAL_ISSUE_ID) =
+ SafetySourceIssue.Builder(
+ issueId,
+ "Critical issue title",
+ "Critical issue summary",
+ SEVERITY_LEVEL_CRITICAL_WARNING,
+ ISSUE_TYPE_ID
+ )
+ .addAction(criticalResolvingAction)
+
+ /**
+ * General [SafetySourceIssue] with a [SEVERITY_LEVEL_CRITICAL_WARNING] and a resolving [Action]
+ * .
+ */
+ val criticalResolvingGeneralIssue = defaultCriticalResolvingIssueBuilder().build()
+
+ /**
+ * General [SafetySourceIssue] with a [SEVERITY_LEVEL_CRITICAL_WARNING] and with deduplication
+ * info and a resolving [Action].
+ */
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ fun criticalIssueWithDeduplicationId(deduplicationId: String) =
+ defaultCriticalResolvingIssueBuilder().setDeduplicationId(deduplicationId).build()
+
+ /**
+ * Account related [SafetySourceIssue] with a [SEVERITY_LEVEL_CRITICAL_WARNING] and a resolving
+ * [Action].
+ */
+ val criticalResolvingAccountIssue =
+ defaultCriticalResolvingIssueBuilder()
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_ACCOUNT)
+ .build()
+
+ /**
+ * Device related [SafetySourceIssue] with a [SEVERITY_LEVEL_CRITICAL_WARNING] and a resolving
+ * [Action].
+ */
+ val criticalResolvingDeviceIssue =
+ defaultCriticalResolvingIssueBuilder()
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
+ .build()
+
+ /** A [SafetySourceData.Builder] with a [SEVERITY_LEVEL_CRITICAL_WARNING] status. */
+ fun defaultCriticalDataBuilder() =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder(
+ "Critical title",
+ "Critical summary",
+ SEVERITY_LEVEL_CRITICAL_WARNING
+ )
+ .setPendingIntent(testActivityRedirectPendingIntent)
+ .build()
+ )
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_CRITICAL_WARNING] having a resolving
+ * [SafetySourceIssue] with a [SafetySourceIssue.attributionTitle] and success message.
+ */
+ val criticalWithIssueWithAttributionTitle: SafetySourceData
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ get() =
+ defaultCriticalDataBuilder()
+ .addIssue(
+ defaultCriticalResolvingIssueBuilder()
+ .setAttributionTitle("Attribution Title")
+ .clearActions()
+ .addAction(criticalResolvingActionWithSuccessMessage)
+ .build()
+ )
+ .build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_CRITICAL_WARNING] having a redirecting
+ * [SafetySourceIssue] with a [SafetySourceIssue.attributionTitle] and confirmation.
+ */
+ val criticalWithIssueWithConfirmationWithAttributionTitle: SafetySourceData
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ get() =
+ defaultCriticalDataBuilder()
+ .addIssue(
+ defaultCriticalResolvingIssueBuilder()
+ .setAttributionTitle("Attribution Title")
+ .clearActions()
+ .addAction(criticalResolvingActionWithConfirmation)
+ .build()
+ )
+ .build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_CRITICAL_WARNING] having a redirecting
+ * [SafetySourceIssue] with a [SafetySourceIssue.attributionTitle].
+ */
+ val criticalWithTestActivityRedirectWithAttributionTitle: SafetySourceData
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ get() =
+ defaultCriticalDataBuilder()
+ .addIssue(
+ defaultCriticalResolvingIssueBuilder()
+ .setAttributionTitle("Attribution Title")
+ .clearActions()
+ .addAction(testActivityRedirectAction)
+ .build()
+ )
+ .build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_CRITICAL_WARNING] resolving general
+ * [SafetySourceIssue] and [SafetySourceStatus].
+ */
+ val criticalWithResolvingGeneralIssue =
+ defaultCriticalDataBuilder().addIssue(criticalResolvingGeneralIssue).build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_CRITICAL_WARNING] resolving general
+ * [SafetySourceIssue] and [SafetySourceStatus], with confirmation dialog.
+ */
+ val criticalWithResolvingGeneralIssueWithConfirmation: SafetySourceData
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ get() =
+ defaultCriticalDataBuilder().addIssue(criticalResolvingIssueWithConfirmation).build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_CRITICAL_WARNING] with a [SafetySourceIssue] that
+ * redirects to the [TestActivity].
+ */
+ val criticalWithTestActivityRedirectIssue =
+ defaultCriticalDataBuilder().addIssue(criticalIssueWithTestActivityRedirectAction).build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_CRITICAL_WARNING] resolving account related
+ * [SafetySourceIssue] and [SafetySourceStatus].
+ */
+ val criticalWithResolvingAccountIssue =
+ defaultCriticalDataBuilder().addIssue(criticalResolvingAccountIssue).build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_CRITICAL_WARNING] resolving device related
+ * [SafetySourceIssue] and [SafetySourceStatus].
+ */
+ val criticalWithResolvingDeviceIssue =
+ defaultCriticalDataBuilder().addIssue(criticalResolvingDeviceIssue).build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_CRITICAL_WARNING] resolving device related
+ * [SafetySourceIssue] and [SafetySourceStatus] and a recommendation issue.
+ */
+ val criticalWithResolvingDeviceIssueAndRecommendationIssue =
+ defaultCriticalDataBuilder()
+ .addIssue(criticalResolvingDeviceIssue)
+ .addIssue(recommendationAccountIssue)
+ .build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_CRITICAL_WARNING] resolving [SafetySourceIssue]
+ * and [SafetySourceStatus].
+ */
+ val criticalWithResolvingIssueWithSuccessMessage =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder(
+ "Critical title",
+ "Critical summary",
+ SEVERITY_LEVEL_CRITICAL_WARNING
+ )
+ .setPendingIntent(testActivityRedirectPendingIntent)
+ .build()
+ )
+ .addIssue(criticalResolvingIssueWithSuccessMessage)
+ .build()
+
+ /**
+ * A [SafetySourceData] with a [SEVERITY_LEVEL_INFORMATION] redirecting [SafetySourceIssue] and
+ * [SEVERITY_LEVEL_CRITICAL_WARNING] [SafetySourceStatus].
+ */
+ val criticalWithInformationIssue =
+ defaultCriticalDataBuilder().addIssue(informationIssue).build()
+
+ /**
+ * Another [SafetySourceData] with a [SEVERITY_LEVEL_CRITICAL_WARNING] redirecting
+ * [SafetySourceIssue] and [SafetySourceStatus].
+ */
+ val criticalWithRedirectingIssue =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder(
+ "Critical title 2",
+ "Critical summary 2",
+ SEVERITY_LEVEL_CRITICAL_WARNING
+ )
+ .setPendingIntent(testActivityRedirectPendingIntent)
+ .build()
+ )
+ .addIssue(criticalRedirectingIssue)
+ .build()
+
+ /**
+ * A function to generate simple [SafetySourceData] with the given entry [severityLevel] and
+ * [entrySummary], and an optional issue with the same [severityLevel].
+ */
+ fun buildSafetySourceDataWithSummary(
+ severityLevel: Int,
+ entrySummary: String,
+ withIssue: Boolean = false,
+ entryTitle: String = "Entry title"
+ ) =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder(entryTitle, entrySummary, severityLevel)
+ .setPendingIntent(testActivityRedirectPendingIntent)
+ .build()
+ )
+ .apply {
+ if (withIssue) {
+ addIssue(
+ SafetySourceIssue.Builder(
+ "issue_id",
+ "Issue title",
+ "Issue summary",
+ max(severityLevel, SEVERITY_LEVEL_INFORMATION),
+ ISSUE_TYPE_ID
+ )
+ .addAction(
+ Action.Builder(
+ "action_id",
+ "Action",
+ testActivityRedirectPendingIntent
+ )
+ .build()
+ )
+ .build()
+ )
+ }
+ }
+ .build()
+
+ private fun broadcastPendingIntent(intent: Intent): PendingIntent =
+ PendingIntent.getBroadcast(
+ context,
+ 0,
+ intent.addFlags(FLAG_RECEIVER_FOREGROUND).setPackage(context.packageName),
+ PendingIntent.FLAG_IMMUTABLE
+ )
+
+ companion object {
+ /** Issue ID for [informationIssue]. */
+ const val INFORMATION_ISSUE_ID = "information_issue_id"
+
+ /** Action ID for the redirecting action in [informationIssue]. */
+ const val INFORMATION_ISSUE_ACTION_ID = "information_issue_action_id"
+
+ /** Issue ID for a recommendation issue */
+ const val RECOMMENDATION_ISSUE_ID = "recommendation_issue_id"
+
+ /** Action ID for the redirecting action in recommendation issue. */
+ const val RECOMMENDATION_ISSUE_ACTION_ID = "recommendation_issue_action_id"
+
+ /** Issue ID for the critical issues in this file. */
+ const val CRITICAL_ISSUE_ID = "critical_issue_id"
+
+ /** Action ID for the critical actions in this file. */
+ const val CRITICAL_ISSUE_ACTION_ID = "critical_issue_action_id"
+
+ /** Issue type ID for all the issues in this file */
+ const val ISSUE_TYPE_ID = "issue_type_id"
+
+ const val CONFIRMATION_TITLE = "Confirmation title"
+ const val CONFIRMATION_TEXT = "Confirmation text"
+ const val CONFIRMATION_YES = "Confirmation yes"
+ const val CONFIRMATION_NO = "Confirmation no"
+ val CONFIRMATION_DETAILS: ConfirmationDialogDetails
+ @RequiresApi(UPSIDE_DOWN_CAKE)
+ get() =
+ ConfirmationDialogDetails(
+ CONFIRMATION_TITLE,
+ CONFIRMATION_TEXT,
+ CONFIRMATION_YES,
+ CONFIRMATION_NO
+ )
+
+ /** A [SafetyEvent] to push arbitrary changes to Safety Center. */
+ val EVENT_SOURCE_STATE_CHANGED =
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
+
+ /** Returns a [SafetySourceData] object containing only the given [issues]. */
+ fun issuesOnly(vararg issues: SafetySourceIssue): SafetySourceData {
+ val builder = SafetySourceData.Builder()
+ issues.forEach { builder.addIssue(it) }
+ return builder.build()
+ }
+
+ /** Returns a [PendingIntent] that redirects to [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,
+ PendingIntent.FLAG_IMMUTABLE
+ )
+ }
+
+ private fun intentResolves(context: Context, intent: Intent): Boolean =
+ context.packageManager
+ .queryIntentActivities(intent, ResolveInfoFlags.of(0))
+ .isNotEmpty()
+ }
+}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/testing/SettingsPackage.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SettingsPackage.kt
index 03c6d9067..2ba127f4e 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/testing/SettingsPackage.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SettingsPackage.kt
@@ -14,24 +14,32 @@
* limitations under the License.
*/
-package android.safetycenter.cts.testing
+package com.android.safetycenter.testing
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
+import android.content.pm.PackageManager.ResolveInfoFlags
+import android.os.Build.VERSION_CODES.TIRAMISU
import android.provider.Settings
+import androidx.annotation.RequiresApi
/** A class that knows the Settings app package name. */
object SettingsPackage {
/** Returns the Settings app package name. */
+ @RequiresApi(TIRAMISU) // For call to resolveActivity with ResolveInfoFlags.
fun Context.getSettingsPackageName() =
- packageManager
- .resolveActivity(
- Intent(Settings.ACTION_SETTINGS),
- PackageManager.MATCH_DEFAULT_ONLY or
- PackageManager.MATCH_DIRECT_BOOT_AWARE or
- PackageManager.MATCH_DIRECT_BOOT_UNAWARE)!!
- .activityInfo
- .packageName
+ packageManager
+ .resolveActivity(
+ Intent(Settings.ACTION_SETTINGS),
+ ResolveInfoFlags.of(
+ (PackageManager.MATCH_DEFAULT_ONLY or
+ PackageManager.MATCH_DIRECT_BOOT_AWARE or
+ PackageManager.MATCH_DIRECT_BOOT_UNAWARE)
+ .toLong()
+ )
+ )!!
+ .activityInfo
+ .packageName
}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/ShellPermissions.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/ShellPermissions.kt
new file mode 100644
index 000000000..3a74ed2c2
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/ShellPermissions.kt
@@ -0,0 +1,73 @@
+/*
+ * 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.testing
+
+import android.app.UiAutomation
+import android.app.UiAutomation.ALL_PERMISSIONS
+import androidx.annotation.GuardedBy
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.compatibility.common.util.SystemUtil
+import com.google.common.collect.HashMultiset
+import com.google.common.collect.Multiset
+
+/** A class to facilitate working with System Shell permissions. */
+object ShellPermissions {
+
+ private val lock = Object()
+ @GuardedBy("lock") private val nestedPermissions: Multiset<String> = HashMultiset.create()
+
+ /**
+ * Behaves the same way as [SystemUtil.callWithShellPermissionIdentity], but allows nesting
+ * calls to it by merging the adopted [permissions] within each [block].
+ *
+ * Note that [SystemUtil.callWithShellPermissionIdentity] should NOT be used together with this
+ * method.
+ */
+ fun <T> callWithShellPermissionIdentity(vararg permissions: String, block: () -> T): T {
+ val uiAutomation = getInstrumentation().getUiAutomation()
+ val permissionsToAddForThisBlock =
+ if (permissions.isEmpty()) {
+ ALL_PERMISSIONS
+ } else {
+ permissions.toSet()
+ }
+ synchronized(lock) {
+ permissionsToAddForThisBlock.forEach { nestedPermissions.add(it) }
+ uiAutomation.adoptShellPermissionIdentityFor(nestedPermissions.elementSet())
+ }
+ try {
+ return block()
+ } finally {
+ synchronized(lock) {
+ permissionsToAddForThisBlock.forEach { nestedPermissions.remove(it) }
+ if (nestedPermissions.isEmpty()) {
+ uiAutomation.dropShellPermissionIdentity()
+ } else {
+ uiAutomation.adoptShellPermissionIdentityFor(nestedPermissions.elementSet())
+ }
+ }
+ }
+ }
+
+ private fun UiAutomation.adoptShellPermissionIdentityFor(permissionsToAdopt: Set<String>) {
+ if (permissionsToAdopt.containsAll(ALL_PERMISSIONS)) {
+ adoptShellPermissionIdentity()
+ } else {
+ adoptShellPermissionIdentity(*permissionsToAdopt.toTypedArray())
+ }
+ }
+}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/TestActivity.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/TestActivity.kt
new file mode 100644
index 000000000..124f44101
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/TestActivity.kt
@@ -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 com.android.safetycenter.testing
+
+import android.app.Activity
+import android.os.Bundle
+import android.view.View
+import android.widget.TextView
+
+/** An activity used in tests to assert the redirects. */
+class TestActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.test_activity)
+ val bundleText: TextView? = findViewById(R.id.bundle_text)
+ val isFromSettingsHomepage = getIntent().getBooleanExtra("is_from_settings_homepage", false)
+ bundleText?.text = "is_from_settings_homepage $isFromSettingsHomepage"
+
+ val exitButton: View? = findViewById(R.id.button)
+ exitButton?.setOnClickListener { finish() }
+ }
+}
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/UiTestHelper.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/UiTestHelper.kt
new file mode 100644
index 000000000..ec676e3d9
--- /dev/null
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/UiTestHelper.kt
@@ -0,0 +1,255 @@
+/*
+ * 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.os.Build.VERSION_CODES.TIRAMISU
+import android.os.SystemClock
+import android.safetycenter.SafetySourceData
+import android.safetycenter.SafetySourceIssue
+import android.safetycenter.config.SafetySourcesGroup
+import android.util.Log
+import androidx.annotation.RequiresApi
+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 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 java.time.Duration
+import java.util.concurrent.TimeoutException
+import java.util.regex.Pattern
+
+/** A class that helps with UI testing. */
+object UiTestHelper {
+
+ /** The label of the rescan button. */
+ const val RESCAN_BUTTON_LABEL = "Scan device"
+ /** The title of collapsible card that controls the visibility of additional issue cards. */
+ 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 val TAG = UiTestHelper::class.java.simpleName
+
+ /**
+ * Waits for the given [selector] to be displayed and performs the given [uiObjectAction] on it.
+ */
+ fun waitDisplayed(selector: BySelector, uiObjectAction: (UiObject2) -> Unit = {}) {
+ waitFor("$selector to be displayed", WAIT_TIMEOUT) {
+ uiObjectAction(waitFindObject(selector, it.toMillis()))
+ true
+ }
+ }
+
+ /** Waits for all the given [textToFind] to be displayed. */
+ fun waitAllTextDisplayed(vararg textToFind: CharSequence?) {
+ for (text in textToFind) {
+ if (text != null) waitDisplayed(By.text(text.toString()))
+ }
+ }
+
+ /**
+ * Waits for a button with the given [label] to be displayed and performs the given
+ * [uiObjectAction] on it.
+ */
+ fun waitButtonDisplayed(label: CharSequence, uiObjectAction: (UiObject2) -> Unit = {}) =
+ waitDisplayed(buttonSelector(label), uiObjectAction)
+
+ /** 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
+ }
+ }
+
+ /** 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()))
+ }
+ }
+
+ /** Waits for a button with the given [label] not to be displayed. */
+ fun waitButtonNotDisplayed(label: CharSequence) {
+ waitNotDisplayed(buttonSelector(label))
+ }
+
+ /**
+ * Waits for most of the [SafetySourceData] information to be displayed.
+ *
+ * This includes its UI entry and its issues.
+ */
+ @RequiresApi(TIRAMISU)
+ fun waitSourceDataDisplayed(sourceData: SafetySourceData) {
+ waitAllTextDisplayed(sourceData.status?.title, sourceData.status?.summary)
+
+ for (sourceIssue in sourceData.issues) {
+ waitSourceIssueDisplayed(sourceIssue)
+ }
+ }
+
+ /** Waits for most of the [SafetySourceIssue] information to be displayed. */
+ @RequiresApi(TIRAMISU)
+ fun waitSourceIssueDisplayed(sourceIssue: SafetySourceIssue) {
+ waitAllTextDisplayed(sourceIssue.title, sourceIssue.subtitle, sourceIssue.summary)
+
+ for (action in sourceIssue.actions) {
+ waitButtonDisplayed(action.label)
+ }
+ }
+
+ /** Waits for most of the [SafetySourceIssue] information not to be displayed. */
+ @RequiresApi(TIRAMISU)
+ fun waitSourceIssueNotDisplayed(sourceIssue: SafetySourceIssue) {
+ waitAllTextNotDisplayed(sourceIssue.title)
+ }
+
+ /**
+ * Waits for only one [SafetySourceIssue] to be displayed together with [MORE_ISSUES_LABEL]
+ * card, and for all other [SafetySourceIssue]s not to be diplayed.
+ */
+ fun waitCollapsedIssuesDisplayed(vararg sourceIssues: SafetySourceIssue) {
+ waitSourceIssueDisplayed(sourceIssues.first())
+ waitAllTextDisplayed(MORE_ISSUES_LABEL)
+ sourceIssues.asSequence().drop(1).forEach { waitSourceIssueNotDisplayed(it) }
+ }
+
+ /** Waits for all the [SafetySourceIssue] to be displayed with the [MORE_ISSUES_LABEL] card. */
+ fun waitExpandedIssuesDisplayed(vararg sourceIssues: SafetySourceIssue) {
+ // to make landscape checks less flaky it is important to match their order with visuals
+ waitSourceIssueDisplayed(sourceIssues.first())
+ waitAllTextDisplayed(MORE_ISSUES_LABEL)
+ sourceIssues.asSequence().drop(1).forEach { waitSourceIssueDisplayed(it) }
+ }
+
+ /** Waits for the specified screen title to be displayed. */
+ fun waitPageTitleDisplayed(title: String) {
+ // CollapsingToolbar title can't be found by text, so using description instead.
+ waitDisplayed(By.desc(title))
+ }
+
+ /** Waits for the specified screen title not to be displayed. */
+ fun waitPageTitleNotDisplayed(title: String) {
+ // CollapsingToolbar title can't be found by text, so using description instead.
+ waitNotDisplayed(By.desc(title))
+ }
+
+ /** Waits for the group title and summary to be displayed on the homepage */
+ fun waitGroupShownOnHomepage(context: Context, group: SafetySourcesGroup) {
+ waitAllTextDisplayed(
+ context.getString(group.titleResId),
+ context.getString(group.summaryResId)
+ )
+ }
+
+ /** Dismisses the issue card by clicking the dismiss button. */
+ fun clickDismissIssueCard() {
+ waitDisplayed(By.desc(DISMISS_ISSUE_LABEL)) { it.click() }
+ }
+
+ /** Confirms the dismiss action by clicking on the dialog that pops up. */
+ fun clickConfirmDismissal() {
+ waitButtonDisplayed(DISMISS_ISSUE_LABEL) { it.click() }
+ }
+
+ /** Clicks the brand chip button on a subpage in Safety Center. */
+ fun clickSubpageBrandChip() {
+ waitButtonDisplayed("Security & privacy") { it.click() }
+ }
+
+ /** Opens the subpage by clicking on the group title. */
+ fun clickOpenSubpage(context: Context, group: SafetySourcesGroup) {
+ waitDisplayed(By.text(context.getString(group.titleResId))) { it.click() }
+ }
+
+ /** Clicks the more issues card button to show or hide additional issues. */
+ fun clickMoreIssuesCard() {
+ waitDisplayed(By.text(MORE_ISSUES_LABEL)) { it.click() }
+ }
+
+ /** Enables or disables animations based on [enabled]. */
+ fun setAnimationsEnabled(enabled: Boolean) {
+ val scale =
+ if (enabled) {
+ "1"
+ } else {
+ "0"
+ }
+ runShellCommand("settings put global window_animation_scale $scale")
+ runShellCommand("settings put global transition_animation_scale $scale")
+ runShellCommand("settings put global animator_duration_scale $scale")
+ }
+
+ fun UiDevice.rotate() {
+ unfreezeRotation()
+ if (isNaturalOrientation) {
+ setOrientationLeft()
+ } else {
+ setOrientationNatural()
+ }
+ freezeRotation()
+ waitForIdle()
+ }
+
+ fun UiDevice.resetRotation() {
+ if (!isNaturalOrientation) {
+ unfreezeRotation()
+ setOrientationNatural()
+ freezeRotation()
+ waitForIdle()
+ }
+ }
+
+ private fun buttonSelector(label: CharSequence): BySelector {
+ return By.clickable(true).text(Pattern.compile("$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)
+ }
+ }
+
+ throw TimeoutException("Timed out waiting for $message")
+ }
+}
diff --git a/tests/utils/safetycenter/res/layout/test_activity.xml b/tests/utils/safetycenter/res/layout/test_activity.xml
new file mode 100644
index 000000000..edbe3641a
--- /dev/null
+++ b/tests/utils/safetycenter/res/layout/test_activity.xml
@@ -0,0 +1,31 @@
+<?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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+ <Button android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Exit test activity" />
+ <TextView android:id="@+id/bundle_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Missing" />
+</LinearLayout>